-
Notifications
You must be signed in to change notification settings - Fork 280
/
catalogue.go
173 lines (152 loc) Β· 5 KB
/
catalogue.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
package hardware
import (
"bufio"
"errors"
"fmt"
"io"
"os"
tinkv1alpha1 "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
yamlutil "k8s.io/apimachinery/pkg/util/yaml"
"sigs.k8s.io/yaml"
eksav1alpha1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1"
rufiov1alpha1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1/thirdparty/tinkerbell/rufio"
"github.com/aws/eks-anywhere/pkg/templater"
)
// Indexer provides indexing behavior for objects.
type Indexer interface {
// Lookup retrieves objects associated with the index => value pair.
Lookup(index, value string) ([]interface{}, error)
// Insert inserts v int the index.
Insert(v interface{}) error
// IndexField associated index with fn such that Lookup may be used to retrieve objects.
IndexField(index string, fn KeyExtractorFunc)
// Remove deletes v from the index.
Remove(v interface{}) error
}
// Catalogue represents a catalogue of Tinkerbell hardware manifests to be used with Tinkerbells
// Kubefied back-end.
type Catalogue struct {
hardware []*tinkv1alpha1.Hardware
hardwareIndex Indexer
bmcs []*rufiov1alpha1.Machine
bmcIndex Indexer
secrets []*corev1.Secret
secretIndex Indexer
}
// CatalogueOption defines an option to be applied in Catalogue instantiation.
type CatalogueOption func(*Catalogue)
// NewCatalogue creates a new Catalogue instance.
func NewCatalogue(opts ...CatalogueOption) *Catalogue {
catalogue := &Catalogue{
hardwareIndex: NewFieldIndexer(&tinkv1alpha1.Hardware{}),
bmcIndex: NewFieldIndexer(&rufiov1alpha1.Machine{}),
secretIndex: NewFieldIndexer(&corev1.Secret{}),
}
for _, opt := range opts {
opt(catalogue)
}
return catalogue
}
// ParseYAMLCatalogueFromFile parses filename, a YAML document, using ParseYamlCatalogue.
func ParseYAMLCatalogueFromFile(catalogue *Catalogue, filename string) error {
fh, err := os.Open(filename)
if err != nil {
return err
}
return ParseYAMLCatalogue(catalogue, fh)
}
// ParseYAMLCatalogue parses a YAML document, r, that represents a set of Kubernetes manifests.
// Manifests parsed include CAPT Hardware, PBnJ BMCs and associated Core API Secret.
func ParseYAMLCatalogue(catalogue *Catalogue, r io.Reader) error {
document := yamlutil.NewYAMLReader(bufio.NewReader(r))
for {
manifest, err := document.Read()
if errors.Is(err, io.EOF) {
return nil
}
if err != nil {
return err
}
var resource unstructured.Unstructured
if err = yaml.Unmarshal(manifest, &resource); err != nil {
return err
}
switch resource.GetKind() {
case "Hardware":
if err := catalogueSerializedHardware(catalogue, manifest); err != nil {
return err
}
case "Machine":
if err := catalogueSerializedBMC(catalogue, manifest); err != nil {
return err
}
case "Secret":
if err := catalogueSerializedSecret(catalogue, manifest); err != nil {
return err
}
}
}
}
func catalogueSerializedHardware(catalogue *Catalogue, manifest []byte) error {
var hardware tinkv1alpha1.Hardware
if err := yaml.UnmarshalStrict(manifest, &hardware); err != nil {
return fmt.Errorf("unable to parse hardware manifest: %v", err)
}
if err := catalogue.InsertHardware(&hardware); err != nil {
return err
}
return nil
}
func catalogueSerializedBMC(catalogue *Catalogue, manifest []byte) error {
var bmc rufiov1alpha1.Machine
if err := yaml.UnmarshalStrict(manifest, &bmc); err != nil {
return fmt.Errorf("unable to parse bmc manifest: %v", err)
}
if err := catalogue.InsertBMC(&bmc); err != nil {
return err
}
return nil
}
func catalogueSerializedSecret(catalogue *Catalogue, manifest []byte) error {
var secret corev1.Secret
if err := yaml.UnmarshalStrict(manifest, &secret); err != nil {
return fmt.Errorf("unable to parse secret manifest: %v", err)
}
if err := catalogue.InsertSecret(&secret); err != nil {
return err
}
return nil
}
// MarshalCatalogue marshals c into YAML that can be submitted to a Kubernetes cluster.
func MarshalCatalogue(c *Catalogue) ([]byte, error) {
var marshallables []eksav1alpha1.Marshallable
for _, hw := range c.AllHardware() {
marshallables = append(marshallables, hw)
}
for _, bmc := range c.AllBMCs() {
marshallables = append(marshallables, bmc)
}
for _, secret := range c.AllSecrets() {
marshallables = append(marshallables, secret)
}
resources := make([][]byte, 0, len(marshallables))
for _, marshallable := range marshallables {
resource, err := yaml.Marshal(marshallable)
if err != nil {
return nil, fmt.Errorf("failed marshalling resource for hardware spec: %v", err)
}
resources = append(resources, resource)
}
return templater.AppendYamlResources(resources...), nil
}
// NewMachineCatalogueWriter creates a MachineWriter instance that writes Machine instances to
// catalogue including its Machine and Secret data.
func NewMachineCatalogueWriter(catalogue *Catalogue) MachineWriter {
return MultiMachineWriter(
NewHardwareCatalogueWriter(catalogue),
NewBMCCatalogueWriter(catalogue),
NewSecretCatalogueWriter(catalogue),
)
}