...
1 package flagutil
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 UsePart *bool `json:"usePart"`
75 }
76 type terminalCreateDup struct {
77 model.TerminalCreateInput
78 DiskDup []*diskCreateDup `json:"disks"`
79 }
80 var terminalsDup []*terminalCreateDup
81
82 decoder := json.NewDecoder(bytes.NewReader(data))
83 decoder.DisallowUnknownFields()
84
85 err := decoder.Decode(&terminalsDup)
86 if err != nil {
87 errmsg := ""
88 switch jsonError := err.(type) {
89 case *json.InvalidUnmarshalError:
90
91 errmsg = fmt.Sprintf("JSON data (converted from YAML input) not valid for unmarshalling: %v", err)
92 case *json.SyntaxError:
93 errmsg = fmt.Sprintf("Syntax error in JSON data (converted from YAML input) at offset %v: %v", int(jsonError.Offset), err)
94 case *json.UnmarshalTypeError:
95 errmsg = fmt.Sprintf("Failed to unmarshal JSON data (converted from YAML input) at offset %v: %v", int(jsonError.Offset), err)
96 default:
97 errmsg = fmt.Sprintf("Encountered unknown error when unmarshalling JSON data (converted from YAML input): %v", jsonError)
98 }
99 return nil, errors.New(errmsg)
100 }
101
102 var terminals []*model.TerminalCreateInput
103 for _, terminalDup := range terminalsDup {
104 terminal := terminalDup.TerminalCreateInput
105
106 disks := []*model.TerminalDiskCreateInput{}
107 for _, diskDup := range terminalDup.DiskDup {
108 if diskDup.DevicePath == nil {
109 return nil, fmt.Errorf("cannot create a terminal disk without devicePath")
110 }
111 if diskDup.IncludeDisk == nil {
112 diskDup.IncludeDisk = func(b bool) *bool { return &b }(false)
113 }
114 if diskDup.ExpectEmpty == nil {
115 diskDup.ExpectEmpty = func(b bool) *bool { return &b }(true)
116 }
117 if diskDup.UsePart == nil {
118 diskDup.UsePart = func(b bool) *bool { return &b }(false)
119 }
120
121 disk := model.TerminalDiskCreateInput{DevicePath: *diskDup.DevicePath, ExpectEmpty: *diskDup.ExpectEmpty, IncludeDisk: *diskDup.IncludeDisk, UsePart: *diskDup.UsePart}
122 disks = append(disks, &disk)
123 }
124
125 terminal.Disks = disks
126 terminals = append(terminals, &terminal)
127 }
128
129 return terminals, nil
130 }
131
132 func validateTerminals(terminals []*model.TerminalCreateInput) error {
133 for idx, terminal := range terminals {
134 if !isValidTerminalClass(terminal.Class) {
135 return fmt.Errorf("terminal %v has invalid or missing class field - must be one of '%v' or '%v'", idx, model.TerminalClassTypeServer, model.TerminalClassTypeTouchpoint)
136 }
137 if terminal.Hostname != nil && networkvalidator.IsValidHostname(*terminal.Hostname) != nil {
138 return fmt.Errorf("terminal %v has invalid hostname field", idx)
139 }
140 }
141 return nil
142 }
143
View as plain text