-
Notifications
You must be signed in to change notification settings - Fork 40
/
api_container_args.go
118 lines (102 loc) · 4.48 KB
/
api_container_args.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package args
import (
"encoding/json"
"github.com/kurtosis-tech/kurtosis/core/launcher/args/kurtosis_backend_config"
"reflect"
"strings"
"github.com/kurtosis-tech/stacktrace"
)
const (
jsonFieldTag = "json"
)
// Fields are public for JSON de/serialization
type APIContainerArgs struct {
// The version of the API container that was started by the engine, so that the API container can report its
// own version
// Ideally this would come from a hardcoded constant, but we don't yet have the machinery that can update a constant
// on every build
Version string `json:"version"`
LogLevel string `json:"logLevel"`
GrpcListenPortNum uint16 `json:"grpcListenPortNum"`
EnclaveUUID string `json:"enclaveUuid"`
// The directory on the API container where the enclave data directory will have been mounted
EnclaveDataVolumeDirpath string `json:"enclaveDataVolume"`
KurtosisBackendType KurtosisBackendType `json:"kurtosisBackendType"`
// Should be deserialized differently depending on value of KurtosisBackendType
KurtosisBackendConfig interface{} `json:"kurtosisBackendConfig"`
EnclaveEnvVars string `json:"enclaveEnvVars"`
}
func (args *APIContainerArgs) UnmarshalJSON(data []byte) error {
// create a mirror type to avoid unmarshalling infinitely https://stackoverflow.com/questions/52433467/how-to-call-json-unmarshal-inside-unmarshaljson-without-causing-stack-overflow
type APIContainerArgsMirror APIContainerArgs
var apiContainerArgsMirror APIContainerArgsMirror
if err := json.Unmarshal(data, &apiContainerArgsMirror); err != nil {
return stacktrace.Propagate(err, "Failed to unmarshal api container args")
}
byteArray, err := json.Marshal(apiContainerArgsMirror.KurtosisBackendConfig)
if err != nil {
return stacktrace.Propagate(err, "Failed to re-marshal Kurtosis backend interface ")
}
switch apiContainerArgsMirror.KurtosisBackendType {
case KurtosisBackendType_Docker:
var dockerConfig kurtosis_backend_config.DockerBackendConfig
if err := json.Unmarshal(byteArray, &dockerConfig); err != nil {
return stacktrace.Propagate(err, "Failed to unmarshal backend config '%+v' with type '%v'", apiContainerArgsMirror.KurtosisBackendConfig, apiContainerArgsMirror.KurtosisBackendType.String())
}
apiContainerArgsMirror.KurtosisBackendConfig = dockerConfig
case KurtosisBackendType_Kubernetes:
var kubernetesConfig kurtosis_backend_config.KubernetesBackendConfig
if err := json.Unmarshal(byteArray, &kubernetesConfig); err != nil {
return stacktrace.Propagate(err, "Failed to unmarshal backend config '%+v' with type '%v'", apiContainerArgsMirror.KurtosisBackendConfig, apiContainerArgsMirror.KurtosisBackendType.String())
}
apiContainerArgsMirror.KurtosisBackendConfig = kubernetesConfig
default:
return stacktrace.NewError("Unmarshalled an unrecognized Kurtosis backend type: '%v'", apiContainerArgsMirror.KurtosisBackendType.String())
}
*args = APIContainerArgs(apiContainerArgsMirror)
return nil
}
// Even though the fields are public due to JSON de/serialization requirements, we still have this constructor so that
//
// we get compile errors if there are missing fields
func NewAPIContainerArgs(
version string,
logLevel string,
grpcListenPortNum uint16,
enclaveUuid string,
enclaveDataVolumeDirpath string,
kurtosisBackendType KurtosisBackendType,
kurtosisBackendConfig interface{},
enclaveEnvVars string,
) (*APIContainerArgs, error) {
result := &APIContainerArgs{
Version: version,
LogLevel: logLevel,
GrpcListenPortNum: grpcListenPortNum,
EnclaveUUID: enclaveUuid,
EnclaveDataVolumeDirpath: enclaveDataVolumeDirpath,
KurtosisBackendType: kurtosisBackendType,
KurtosisBackendConfig: kurtosisBackendConfig,
EnclaveEnvVars: enclaveEnvVars,
}
if err := result.validate(); err != nil {
return nil, stacktrace.Propagate(err, "An error occurred validating API container args")
}
return result, nil
}
// NOTE: We can't use a pointer receiver here else reflection's NumField will panic
func (args APIContainerArgs) validate() error {
// Generic validation based on field type
reflectVal := reflect.ValueOf(args)
reflectValType := reflectVal.Type()
for i := 0; i < reflectValType.NumField(); i++ {
field := reflectValType.Field(i)
jsonFieldName := field.Tag.Get(jsonFieldTag)
// Ensure no empty strings
strVal := reflectVal.Field(i).String()
if strings.TrimSpace(strVal) == "" {
return stacktrace.NewError("JSON field '%s' is whitespace or empty string", jsonFieldName)
}
}
return nil
}