英文:
Golang panic: interface conversion: interface {} is nil, not string
问题
我已经尝试创建CA配置文件、证书和私钥,我正在使用Go语言中的cfssl
命令,并尝试从以下命令模拟相同的命令:
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
以下是我的代码片段:
package main
import (
"bytes"
"fmt"
"io"
"os/exec"
"github.com/cloudflare/cfssl/log"
"encoding/json"
"io/ioutil"
"os"
"github.com/cloudflare/cfssl/cli"
"github.com/cloudflare/cfssl/cli/bundle"
"github.com/cloudflare/cfssl/cli/certinfo"
"github.com/cloudflare/cfssl/cli/gencert"
"github.com/cloudflare/cfssl/cli/gencrl"
"github.com/cloudflare/cfssl/cli/genkey"
"github.com/cloudflare/cfssl/cli/info"
"github.com/cloudflare/cfssl/cli/ocspdump"
"github.com/cloudflare/cfssl/cli/ocsprefresh"
"github.com/cloudflare/cfssl/cli/ocspserve"
"github.com/cloudflare/cfssl/cli/ocspsign"
printdefaults "github.com/cloudflare/cfssl/cli/printdefault"
"github.com/cloudflare/cfssl/cli/revoke"
"github.com/cloudflare/cfssl/cli/scan"
"github.com/cloudflare/cfssl/cli/selfsign"
"github.com/cloudflare/cfssl/cli/serve"
"github.com/cloudflare/cfssl/cli/sign"
"github.com/cloudflare/cfssl/cli/version"
// err "github.com/hyperledger/fabric/cop/errors"
"google.golang.org/grpc"
)
func main() {
var participantFile string = "key.pem"
// file, err := os.Open("conf/ca-csr.json")
// if err != nil {
// log.Fatalf("missing config file: %v", err)
// }
// defer file.Close()
// s, err := ioutil.ReadAll(file)
// if err != nil {
// log.Fatalf("could not read config file: %v", err)
// }
csr := `{
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:masters",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}`
//csr := string([]byte(s[:]))
GenCert(csr, participantFile)
}
var cfsslCmds = map[string]*cli.Command{
"bundle": bundle.Command,
"certinfo": certinfo.Command,
"sign": sign.Command,
"serve": serve.Command,
"version": version.Command,
"genkey": genkey.Command,
"gencert": gencert.Command,
"gencrl": gencrl.Command,
"ocspdump": ocspdump.Command,
"ocsprefresh": ocsprefresh.Command,
"ocspsign": ocspsign.Command,
"ocspserve": ocspserve.Command,
"selfsign": selfsign.Command,
"scan": scan.Command,
"info": info.Command,
"print-defaults": printdefaults.Command,
"revoke": revoke.Command,
}
// CertMgr is the default certificate manager
type CertMgr struct {
rootPath string
participantFilePath string
cert []byte
grpcServer *grpc.Server
}
type output struct {
Cert string
}
type gencertOutput struct {
cert []byte
csr []byte
key []byte
}
func GenCert(csr string, participantFile string) {
var args []string
gencertCmd := cfsslCmds["gencert"]
var c cli.Config
c.IsCA = true
args = append(args, csr)
out := ExecuteCommand(args, gencertCmd, c)
var gencertOut map[string]interface{}
json.Unmarshal([]byte(out), &gencertOut)
var writeJSON output
writeJSON.Cert = gencertOut["cert"].(string)
jsonOut, _ := json.Marshal(writeJSON)
ioutil.WriteFile(participantFile, jsonOut, 0644)
return
}
func ExecuteCommand(args []string, command *cli.Command, c cli.Config) string {
cfsslJSONCmd := exec.Command("cfssljson", "-bare")
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
err := command.Main(args, c) // Execute command
if err != nil {
log.Error(err)
}
outC := make(chan string)
// copy the output in a separate goroutine so printing can't block indefinitely
var buf bytes.Buffer
go func() {
io.Copy(&buf, r)
cfsslJSONCmd.Stdin = &buf
outC <- buf.String()
}()
w.Close()
out := <-outC
outByte := []byte(out)
tmpFile, _ := ioutil.TempFile("", "tmp")
defer os.Remove(tmpFile.Name())
if _, err = tmpFile.Write(outByte); err != nil {
fmt.Println("err: ", err)
}
os.Stdin = tmpFile
os.Stdout = old // restoring the real stdout
err = cfsslJSONCmd.Run() // Execute cfssljson -bare <prefix>
if err != nil {
log.Error(err)
}
return out // To be used to store in participant file
}
我得到了以下错误:
[ERROR] open {
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:masters",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}: no such file or directory
2022/03/25 19:23:39 [ERROR] exit status 1
panic: interface conversion: interface {} is nil, not string
goroutine 1 [running]:
main.GenCert({0xb9179c, 0xda}, {0xb3a3f3, 0x7})
/home/Documents/git-repo/kunets-vpc-test/main.go:126 +0x229
main.main()
/home/Documents/git-repo/kunets-vpc-test/main.go:70 +0x31
任何帮助和建议将不胜感激,非常感谢!
<details>
<summary>英文:</summary>
I have tried to create CA configuration file, certificate and private key, I am using `cfssl` command in go and try to simulate same command from
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
Here is my code snipped
package main
import (
"bytes"
"fmt"
"io"
"os/exec"
"github.com/cloudflare/cfssl/log"
"encoding/json"
"io/ioutil"
"os"
"github.com/cloudflare/cfssl/cli"
"github.com/cloudflare/cfssl/cli/bundle"
"github.com/cloudflare/cfssl/cli/certinfo"
"github.com/cloudflare/cfssl/cli/gencert"
"github.com/cloudflare/cfssl/cli/gencrl"
"github.com/cloudflare/cfssl/cli/genkey"
"github.com/cloudflare/cfssl/cli/info"
"github.com/cloudflare/cfssl/cli/ocspdump"
"github.com/cloudflare/cfssl/cli/ocsprefresh"
"github.com/cloudflare/cfssl/cli/ocspserve"
"github.com/cloudflare/cfssl/cli/ocspsign"
printdefaults "github.com/cloudflare/cfssl/cli/printdefault"
"github.com/cloudflare/cfssl/cli/revoke"
"github.com/cloudflare/cfssl/cli/scan"
"github.com/cloudflare/cfssl/cli/selfsign"
"github.com/cloudflare/cfssl/cli/serve"
"github.com/cloudflare/cfssl/cli/sign"
"github.com/cloudflare/cfssl/cli/version"
// err "github.com/hyperledger/fabric/cop/errors"
"google.golang.org/grpc"
)
func main() {
var participantFile string = "key.pem"
// file, err := os.Open("conf/ca-csr.json")
// if err != nil {
// log.Fatalf("missing config file: %v", err)
// }
// defer file.Close()
// s, err := ioutil.ReadAll(file)
// if err != nil {
// log.Fatalf("could not read config file: %v", err)
// }
csr := `{
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:masters",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}`
//csr := string([]byte(s[:]))
GenCert(csr, participantFile)
}
var cfsslCmds = map[string]*cli.Command{
"bundle": bundle.Command,
"certinfo": certinfo.Command,
"sign": sign.Command,
"serve": serve.Command,
"version": version.Command,
"genkey": genkey.Command,
"gencert": gencert.Command,
"gencrl": gencrl.Command,
"ocspdump": ocspdump.Command,
"ocsprefresh": ocsprefresh.Command,
"ocspsign": ocspsign.Command,
"ocspserve": ocspserve.Command,
"selfsign": selfsign.Command,
"scan": scan.Command,
"info": info.Command,
"print-defaults": printdefaults.Command,
"revoke": revoke.Command,
}
// CertMgr is the default certificate manager
type CertMgr struct {
rootPath string
participantFilePath string
cert []byte
grpcServer *grpc.Server
}
type output struct {
Cert string
}
type gencertOutput struct {
cert []byte
csr []byte
key []byte
}
func GenCert(csr string, participantFile string) {
var args []string
gencertCmd := cfsslCmds["gencert"]
var c cli.Config
c.IsCA = true
args = append(args, csr)
out := ExecuteCommand(args, gencertCmd, c)
var gencertOut map[string]interface{}
json.Unmarshal([]byte(out), &gencertOut)
var writeJSON output
writeJSON.Cert = gencertOut["cert"].(string)
jsonOut, _ := json.Marshal(writeJSON)
ioutil.WriteFile(participantFile, jsonOut, 0644)
return
}
func ExecuteCommand(args []string, command *cli.Command, c cli.Config) string {
cfsslJSONCmd := exec.Command("cfssljson", "-bare")
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
err := command.Main(args, c) // Execute command
if err != nil {
log.Error(err)
}
outC := make(chan string)
// copy the output in a separate goroutine so printing can't block indefinitely
var buf bytes.Buffer
go func() {
io.Copy(&buf, r)
cfsslJSONCmd.Stdin = &buf
outC <- buf.String()
}()
w.Close()
out := <-outC
outByte := []byte(out)
tmpFile, _ := ioutil.TempFile("", "tmp")
defer os.Remove(tmpFile.Name())
if _, err = tmpFile.Write(outByte); err != nil {
fmt.Println("err: ", err)
}
os.Stdin = tmpFile
os.Stdout = old // restoring the real stdout
err = cfsslJSONCmd.Run() // Execute cfssljson -bare <prefix>
if err != nil {
log.Error(err)
}
return out // To be used to store in participant file
}
and I am getting that error
[ERROR] open {
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:masters",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}: no such file or directory
2022/03/25 19:23:39 [ERROR] exit status 1
panic: interface conversion: interface {} is nil, not string
goroutine 1 [running]:
main.GenCert({0xb9179c, 0xda}, {0xb3a3f3, 0x7})
/home/Documents/git-repo/kunets-vpc-test/main.go:126 +0x229
main.main()
/home/Documents/git-repo/kunets-vpc-test/main.go:70 +0x31
Any help advice would be appreciated, thank you very much!
</details>
# 答案1
**得分**: 4
我认为你在 goroutine 运行时关闭了 w,并且以某种方式突然结束了进程或读取命令输出。尝试通过打印 "out" 来确认,如果是这个问题,可以使用 defer 关闭 w。
使用安全转换来避免 panic,并使用 spew.Dump(需要外部库)来检查数据。
或者使用调试器。
```go
variable, ok := something.(string)
if !ok {
// 无法转换为字符串,现在该怎么办???
}
英文:
I think you are closing the w while the goroutine is running and somehow it ends abruptly the process or reading the command output. Try confirm by print the “out” and if it is the issue, close w with defer
Use a safe convertion to avoid panic and use spew.Dump (need external library) to inspect the data.
Or use a debugger
variable, ok := something.(string)
if !ok {
// cant convert to string, now what???
}
</details>
# 答案2
**得分**: 0
我在模拟时遇到了类似的问题。
```go
type MockSomethingRepository struct {
mock.Mock
}
func (msr *MockSomethingRepository) FindById(id string) (*entity.Session, error) {
args := msr.Called(id)
return args.Get(0).(*entity.Session), args.Error(1)
}
然后我尝试像这样使用模拟对象:
mockSomethignRepository.On("FindById", "1").Return(nil, fmt.Errorf("something went wrong"))
我得到了类似的错误interface conversion: interface {} is *[]entity.Session, not []entity.Session
。
我在https://go.dev/play/p/CLyY2y9-2VF找到了解决方案,所以我通过以下方式解决了问题:
type MockSomethingRepository struct {
mock.Mock
}
func (msr *MockSomethingRepository) FindById(id string) (*entity.Session, error) {
args := msr.Called(id)
if args.Error(1) != nil {
return nil, args.Error(1)
}
return args.Get(0).(*entity.Session), args.Error(1)
}
我没有解释,但它有效!
英文:
I was struggling with a similar problem when I was mocking.
type MockSomethingRepository struct {
mock.Mock
}
func (msr *MockSomethingRepository) FindById(id string) (*entity.Session, error) {
args := msr.Called(id)
return args.Get(0).(*entity.Session), args.Error(1)
}
and Then I tried to use the mock like this
mockSomethignRepository.On("FindById", "1").Return(nil, fmt.Errorf("something went wrong"))
I got similar error nterface conversion: interface {} is *[]entity.Session, not []entity.Session
I have found solution in https://go.dev/play/p/CLyY2y9-2VF
so I have solved it by
type MockSomethingRepository struct {
mock.Mock
}
func (msr *MockSomethingRepository) FindById(id string) (*entity.Session, error) {
args := msr.Called(id)
if args.Error(1) != nil {
return nil, args.Error(1)
}
return args.Get(0).(*entity.Session), args.Error(1)
}
I don't have an explanation but It works!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论