/
firmwareschema_types.go
176 lines (137 loc) · 5.5 KB
/
firmwareschema_types.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
"fmt"
"strconv"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
// Additional data describing the firmware setting.
type SettingSchema struct {
// The type of setting.
// +kubebuilder:validation:Enum=Enumeration;String;Integer;Boolean;Password
AttributeType string `json:"attribute_type,omitempty"`
// The allowable value for an Enumeration type setting.
AllowableValues []string `json:"allowable_values,omitempty"`
// The lowest value for an Integer type setting.
LowerBound *int `json:"lower_bound,omitempty"`
// The highest value for an Integer type setting.
UpperBound *int `json:"upper_bound,omitempty"`
// Minimum length for a String type setting.
MinLength *int `json:"min_length,omitempty"`
// Maximum length for a String type setting.
MaxLength *int `json:"max_length,omitempty"`
// Whether or not this setting is read only.
ReadOnly *bool `json:"read_only,omitempty"`
// Whether or not this setting's value is unique to this node, e.g.
// a serial number.
Unique *bool `json:"unique,omitempty"`
}
type SchemaSettingError struct {
name string
message string
}
func (e SchemaSettingError) Error() string {
return fmt.Sprintf("Setting %s is invalid, %s", e.name, e.message)
}
func (schema *SettingSchema) Validate(name string, value intstr.IntOrString) error {
if schema.ReadOnly != nil && *schema.ReadOnly {
return SchemaSettingError{name: name, message: "it is ReadOnly"}
}
if strings.Contains(name, "Password") {
return SchemaSettingError{name: name, message: "Password fields can't be set"}
}
// Check if valid based on type
switch schema.AttributeType {
case "Enumeration":
for _, av := range schema.AllowableValues {
if value.String() == av {
return nil
}
}
return SchemaSettingError{name: name, message: fmt.Sprintf("unknown enumeration value - %s", value.String())}
case "Integer":
if value.Type == intstr.String {
if _, err := strconv.Atoi(value.String()); err != nil {
return SchemaSettingError{name: name, message: fmt.Sprintf("String %s entered while integer expected", value.String())}
}
}
if schema.LowerBound != nil && value.IntValue() < *schema.LowerBound {
return SchemaSettingError{name: name, message: fmt.Sprintf("integer %d is below minimum value %d", value.IntValue(), *schema.LowerBound)}
}
if schema.UpperBound != nil && value.IntValue() > *schema.UpperBound {
return SchemaSettingError{name: name, message: fmt.Sprintf("integer %d is above maximum value %d", value.IntValue(), *schema.UpperBound)}
}
return nil
case "String":
strLen := len(value.String())
if schema.MinLength != nil && strLen < *schema.MinLength {
return SchemaSettingError{name: name, message: fmt.Sprintf("string %s length is below minimum length %d", value.String(), *schema.MinLength)}
}
if schema.MaxLength != nil && strLen > *schema.MaxLength {
return SchemaSettingError{name: name, message: fmt.Sprintf("string %s length is above maximum length %d", value.String(), *schema.MaxLength)}
}
return nil
case "Boolean":
if value.String() == "true" || value.String() == "false" {
return nil
}
return SchemaSettingError{name: name, message: fmt.Sprintf("%s is not a boolean", value.String())}
case "Password":
// Prevent sets of password types
return SchemaSettingError{name: name, message: "passwords are immutable"}
case "":
// allow the set as BIOS registry fields may not have been available
return nil
default:
// Unexpected attribute type
return SchemaSettingError{name: name, message: fmt.Sprintf("unexpected attribute type %s", schema.AttributeType)}
}
}
// FirmwareSchemaSpec defines the desired state of FirmwareSchema.
type FirmwareSchemaSpec struct {
// The hardware vendor associated with this schema
// +optional
HardwareVendor string `json:"hardwareVendor,omitempty"`
// The hardware model associated with this schema
// +optional
HardwareModel string `json:"hardwareModel,omitempty"`
// Map of firmware name to schema
Schema map[string]SettingSchema `json:"schema" required:"true"`
}
//+kubebuilder:object:root=true
// FirmwareSchema is the Schema for the firmwareschemas API.
type FirmwareSchema struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec FirmwareSchemaSpec `json:"spec,omitempty"`
}
// Check whether the setting's name and value is valid using the schema.
func (host *FirmwareSchema) ValidateSetting(name string, value intstr.IntOrString, schemas map[string]SettingSchema) error {
schema, ok := schemas[name]
if !ok {
return SchemaSettingError{name: name, message: "it is not in the associated schema"}
}
return schema.Validate(name, value)
}
//+kubebuilder:object:root=true
// FirmwareSchemaList contains a list of FirmwareSchema.
type FirmwareSchemaList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []FirmwareSchema `json:"items"`
}
func init() {
SchemeBuilder.Register(&FirmwareSchema{}, &FirmwareSchemaList{})
}