Golang执行命令创建文件,并捕获文件输出以便上传到像S3这样的存储对象。

huangapple go评论79阅读模式
英文:

Golang exec command create file and capture the file output in order to upload to storage object like S3

问题

我正在尝试执行创建文件的命令,并捕获文件输出,以便将其上传到像S3这样的存储对象中,我在捕获输出文件时遇到了困难。具体来说,我正在尝试使用keytool创建密钥库(.jks)文件。

以下是我的代码:

package main

import (
	"fmt"
	"os/exec"
)

func main() {
	cmd := exec.Command("keytool", "-genkeypair", "-noprompt", "-keystore", "~/SOME_PATH/USER_KEY.jks", "-keyalg", "RSA", "-keysize", "2048", "-validity", "10000", "-alias", "USER_ALIAS", "-storepass", "PASSWORD", "-keypass", "PASSWORD", "-dname", "CN=A, OU=A, O=A, L=A, S=A, C=A")
	out, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Printf("failed with error: %s\n", err)
	}
	fmt.Printf("succeeded with output:\n%s\n", string(out))

	// 预期的 "out" 是一个 .jks 文件,而不是命令行输出文本。
	uploadToStorageObject(out)
}

func uploadToStorageObject(file []byte) {
	// 将文件上传到存储对象的过程
}

或许还有其他解决方案?也许可以使用Java?因为keytool是使用Java创建的。

英文:

I'm trying to exec command create file and capture the file output in order to upload to storage object like S3 using golang but I difficulty capture the output file. For specific, I'm trying to create keystore (.jks) file using keytool.

Here's my code:

package main

import (
	"fmt"
	"os/exec"
)

func main() {
	cmd := exec.Command("keytool", "-genkeypair", "-noprompt", "-keystore", "~/SOME_PATH/USER_KEY.jks", "-keyalg", "RSA", "-keysize", "2048", "-validity", "10000", "-alias", "USER_ALIAS", "-storepass", "PASSWORD", "-keypass", "PASSWORD", "-dname", "CN=A, OU=A, O=A, L=A, S=A, C=A")
	out, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Printf("failed with error: %s\n", err)
	}
	fmt.Printf("succed with output:\n%s\n", string(out))

	// Expected "out" is a .jks file not commandline output text.
	uploadToStorageObject(out)
}

func uploadToStorageObject(file []byte) {
	// Procedure upload the file to storage object
}

Or maybe there is another solution? Using java maybe? because keytool is created using java.

答案1

得分: 0

这里有几个问题需要解决。

命令输出与命令可能修改的文件无关

你想要执行创建文件的命令并捕获文件输出。在你的命令中,你使用参数"-keystore""~/SOME_PATH/USER_KEY.jks"指定了文件。你似乎期望文件在命令的CombinedOutput中。但是,CombinedOutput只返回命令的标准输出和标准错误输出的组合,并与keytool输出到密钥文件的数据无关。根据我查看keytool的man页面(来自openjdk,可能不是你的版本),这个输出对你的程序没有用处。你想要上传的文件位于"~/SOME_PATH/USER_KEY.jks"

~/是一个shell的概念

由于你没有调用shell,~/不会被替换为用户的主目录;它将被解释为当前工作目录下名为~的目录(除非keytool本身将~/解释为当前用户的主目录,但我非常怀疑)。请参考https://stackoverflow.com/questions/7922270/obtain-users-home-directory以了解如何获取用户的主目录。根据文件的生命周期,将文件放在/var/tmp或其他与调用用户的主目录无关的位置可能更合理,但只有你知道是否有意义。

如果出现错误,不要尝试处理结果

在这里,如果出现错误,你将其输出到标准输出。捕获错误并向用户提供反馈是很好的。然而,无论是否出现错误,程序都会继续执行。如果err != nil,你的程序不应该期望命令的预期结果已经实现。

    out, err := cmd.CombinedOutput()
    if err != nil {
        fmt.Printf("failed with error: %s\n", err)
    }
    fmt.Printf("succeed with output:\n%s\n", string(out))

在出现错误的情况下,这将打印类似以下内容:

failed with error: <error message>
succeed with output:
<stdout and stderr of keytool invocation>

显然,应该选择其中之一。如果没有其他问题,我建议在出现错误时使用panic,这将立即中止程序并提供堆栈跟踪以供调试(默认情况下)。

keytool和密钥库只与Java环境相关

如果你希望在Java环境中使用密钥库,几乎所有的编程语言都可以调用像keytool这样的外部工具。Java可能也有一个库,允许你在不使用外部keytool的情况下与密钥库进行交互。

希望你最终在Java环境中使用你的密钥库;我不知道还有其他运行时会使用密钥库(我可能太天真了)。如果你只是想生成一个RSA密钥对,并且不特别需要一个密钥库,你可以使用openssl或直接使用Go来完成。如果你真的需要一个密钥库,那么如何调用keytool来创建它并不重要。选择哪种编程语言与keytool并不相关,因为你只是在请求系统调用一个外部程序。选择Go的原因可能是使可执行文件更容易安装(无需JVM),或者因为你喜欢或想使用Go。但你可以使用几乎任何东西运行keytool并上传到S3,包括一个shell脚本(使用支持的aws-cli工具,它会引入一个完整的Python层 - 所以再次,Go给你一个很好的可执行文件,打包并自给自足)。

英文:

There's a few things to address here.

> I'm trying to exec command create file and capture the file output

The keytool utility manages keystore files. In your command you specify this file with the arguments &quot;-keystore&quot;, &quot;~/SOME_PATH/USER_KEY.jks&quot;.

You seem to expect the file to be in the command's CombinedOutput. But CombinedOutput

> CombinedOutput runs the command and returns its combined standard output and standard error.

There is no connection between keytool's output to stdout or stderr, and the data it outputs to the key file. From what I can tell looking through keytool's man page (from openjdk, which might not be your version), this output is not useful to your program.

The file you want to upload is in &quot;~/SOME_PATH/USER_KEY.jks&quot;.

~/ is a shell concept.

Since you're not invoking a shell, ~/ is not going to be replaced with the user's home directory; it will be interpreted as a directory literally named ~ under the current working directory. (That is, unless keytool itself takes ~/ to mean current user's home directory, which I highly doubt).

See https://stackoverflow.com/questions/7922270/obtain-users-home-directory for how to obtain the user's home directory. Depending on that files' lifecycle, it might make more sense to put the file in /var/tmp or somewhere where the invoking user's home directory is irrelevant - but only you know whether that would make sense.

If you get an error, don't try to process the results

Here, if you get an error you output to stdout. It's good to catch the error and provide user feedback. However, the program continues regardless of whether you got an error. If err != nil your program shouldn't expect the command's intended results to have been achieve.

    out, err := cmd.CombinedOutput()
    if err != nil {
        fmt.Printf(&quot;failed with error: %s\n&quot;, err)
    }
    fmt.Printf(&quot;succed with output:\n%s\n&quot;, string(out))

In cases of error, this would print something like:

failed with error: &lt;error message&gt;
succed with output:
&lt;stdout and stderr of keytool invocation&gt;

Clearly it should be one or the other. If nothing else, I'd recommend a panic on the error which will result in an immediate abort of your program and a stack trace for your debugging (by default).

keytool and keystores are only relevant for java environment

> Or maybe there is another solution? Using java maybe? because keytool is created using java

Just about every programming language can invoke an external utility like keyool. Java also probably has a library that allows you to interact with keystores without using an external keytool.

Hopefully you expect to consume your Keystore at the end of the day in a Java environment; I don't know of any other runtimes that would use a keystore (I could be naive). If you're just trying to generate an RSA key pair and aren't specifically wanting a keystore per se, you can do that with openssl or with Go directly.

If you really do want a keystore, it doesn't really matter how you invoke keytool to create it. The language choice isn't much relevant to keytool as you're simply asking the system to invoke an external program anyway. The reason to choose Go might be to make the executable easier to install (without requiring a JVM), or because you prefer or want to use Go. But you could run keytool and upload to s3 with just about anything, including a shell script (with supporting aws-cli tool, which pulls in an entire python layer - so again, Go gives you that nice executable all bundled up and self sufficient).

huangapple
  • 本文由 发表于 2022年1月15日 21:29:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/70721886.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定