...
1 package edgecliutils
2
3 import (
4 "bytes"
5 "encoding/json"
6 "errors"
7 "fmt"
8 "net"
9 "os"
10
11 "edge-infra.dev/pkg/edge/api/graph/model"
12 "edge-infra.dev/pkg/lib/networkvalidator"
13
14 goyaml "gopkg.in/yaml.v3"
15 "sigs.k8s.io/yaml"
16 )
17
18 type IPVersion string
19
20 const (
21 IPv4 IPVersion = "v4"
22 IPv6 IPVersion = "v6"
23 )
24
25 type IPAddress struct {
26 Version IPVersion
27 Address net.IP
28 }
29
30 func ParseTerminalConfigFile(filepath string) ([]*model.TerminalCreateInput, error) {
31 contents, err := os.ReadFile(filepath)
32 if err != nil {
33 return nil, err
34 }
35
36
37
38
39
40
41
42
43
44 data, err := yaml.YAMLToJSONStrict(contents)
45 if err != nil {
46 errmsg := ""
47 switch yamlError := err.(type) {
48 case *goyaml.TypeError:
49 errmsg = fmt.Sprintf("Failed to unmarshal field(s) in YAML input file: %v", yamlError)
50 default:
51 errmsg = fmt.Sprintf("Invalid YAML input file: %v", yamlError)
52 }
53 return nil, errors.New(errmsg)
54 }
55
56 terminals, err := decodeIntoCreateTerminalStruct(data)
57 if err != nil {
58 return nil, err
59 }
60
61
62 if err = validateTerminals(terminals); err != nil {
63 return nil, err
64 }
65
66 return terminals, nil
67 }
68
69 func decodeIntoCreateTerminalStruct(data []byte) ([]*model.TerminalCreateInput, error) {
70 type diskCreateDup struct {
71 IncludeDisk *bool `json:"includeDisk"`
72 ExpectEmpty *bool `json:"expectEmpty"`
73 DevicePath *string `json:"devicePath"`
74 }
75 type terminalCreateDup struct {
76 model.TerminalCreateInput
77 DiskDup []*diskCreateDup `json:"disks"`
78 }
79 var terminalsDup []*terminalCreateDup
80
81 decoder := json.NewDecoder(bytes.NewReader(data))
82 decoder.DisallowUnknownFields()
83
84 err := decoder.Decode(&terminalsDup)
85 if err != nil {
86 errmsg := ""
87 switch jsonError := err.(type) {
88 case *json.InvalidUnmarshalError:
89
90 errmsg = fmt.Sprintf("JSON data (converted from YAML input) not valid for unmarshalling: %v", err)
91 case *json.SyntaxError:
92 errmsg = fmt.Sprintf("Syntax error in JSON data (converted from YAML input) at offset %v: %v", int(jsonError.Offset), err)
93 case *json.UnmarshalTypeError:
94 errmsg = fmt.Sprintf("Failed to unmarshal JSON data (converted from YAML input) at offset %v: %v", int(jsonError.Offset), err)
95 default:
96 errmsg = fmt.Sprintf("Encountered unknown error when unmarshalling JSON data (converted from YAML input): %v", jsonError)
97 }
98 return nil, errors.New(errmsg)
99 }
100
101 var terminals []*model.TerminalCreateInput
102 for _, terminalDup := range terminalsDup {
103 terminal := terminalDup.TerminalCreateInput
104
105 disks := []*model.TerminalDiskCreateInput{}
106 for _, diskDup := range terminalDup.DiskDup {
107 errMsg := "cannot create a terminal disk without"
108 if diskDup.DevicePath == nil {
109 return nil, fmt.Errorf("%s devicePath", errMsg)
110 }
111 if diskDup.ExpectEmpty == nil {
112 return nil, fmt.Errorf("%s expectEmpty", errMsg)
113 }
114 if diskDup.IncludeDisk == nil {
115 return nil, fmt.Errorf("%s includeDisk", errMsg)
116 }
117
118 disk := model.TerminalDiskCreateInput{DevicePath: *diskDup.DevicePath, ExpectEmpty: *diskDup.ExpectEmpty, IncludeDisk: *diskDup.IncludeDisk}
119 disks = append(disks, &disk)
120 }
121
122 terminal.Disks = disks
123 terminals = append(terminals, &terminal)
124 }
125
126 return terminals, nil
127 }
128
129 func validateTerminals(terminals []*model.TerminalCreateInput) error {
130 for idx, terminal := range terminals {
131 if !isValidTerminalClass(terminal.Class) {
132 return fmt.Errorf("terminal %v has invalid or missing class field - must be one of '%v' or '%v'", idx, model.TerminalClassTypeServer, model.TerminalClassTypeTouchpoint)
133 }
134 if terminal.Hostname != nil && networkvalidator.IsValidHostname(*terminal.Hostname) != nil {
135 return fmt.Errorf("terminal %v has invalid hostname field", idx)
136 }
137 }
138 return nil
139 }
140
View as plain text