-
Notifications
You must be signed in to change notification settings - Fork 19
/
installation_types.go
214 lines (166 loc) · 7.19 KB
/
installation_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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
package v1
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
const (
Prefix = "porter.sh/"
AnnotationRetry = Prefix + "retry"
)
// We marshal installation spec to yaml when converting to a porter object
var _ yaml.Marshaler = InstallationSpec{}
// InstallationSpec defines the desired state of Installation
//
// SERIALIZATION NOTE:
// * The json serialization is for persisting this to Kubernetes.
// * The yaml serialization is for creating a Porter representation of the resource.
type InstallationSpec struct {
// AgentConfig is the name of an AgentConfig to use instead of the AgentConfig defined at the namespace or system level.
// +optional
AgentConfig v1.LocalObjectReference `json:"agentConfig,omitempty" yaml:"-"`
// PorterConfig is the name of a PorterConfig to use instead of the PorterConfig defined at the namespace or system level.
PorterConfig v1.LocalObjectReference `json:"porterConfig,omitempty" yaml:"-"`
//
// These are fields from the Porter installation resource.
// Your goal is that someone can copy/paste a resource from Porter into the
// spec and have it work. So be consistent!
//
// SchemaVersion is the version of the installation state schema.
SchemaVersion string `json:"schemaVersion" yaml:"schemaVersion"`
// Name is the name of the installation in Porter. Immutable.
Name string `json:"name" yaml:"name"`
// Namespace (in Porter) where the installation is defined.
Namespace string `json:"namespace" yaml:"namespace"`
// Uninstalled specifies if the installation should be uninstalled.
Uninstalled bool `json:"uninstalled,omitempty" yaml:"uninstalled,omitempty"`
// Bundle definition for the installation.
Bundle OCIReferenceParts `json:"bundle" yaml:"bundle"`
// Labels applied to the installation.
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
// Parameters specified by the user through overrides.
// Does not include defaults, or values resolved from parameter sources.
// +kubebuilder:pruning:PreserveUnknownFields
Parameters runtime.RawExtension `json:"parameters,omitempty" yaml:"-"` // See custom marshaler below
// CredentialSets that should be included when the bundle is reconciled.
CredentialSets []string `json:"credentialSets,omitempty" yaml:"credentialSets,omitempty"`
// ParameterSets that should be included when the bundle is reconciled.
ParameterSets []string `json:"parameterSets,omitempty" yaml:"parameterSets,omitempty"`
}
type OCIReferenceParts struct {
// Repository is the OCI repository of the current bundle definition.
Repository string `json:"repository" yaml:"repository"`
// Version is the current version of the bundle.
Version string `json:"version,omitempty" yaml:"version,omitempty"`
// Digest is the current digest of the bundle.
Digest string `json:"digest,omitempty" yaml:"digest,omitempty"`
// Tag is the OCI tag of the current bundle definition.
Tag string `json:"tag,omitempty" yaml:"tag,omitempty"`
}
// ToPorterDocument converts from the Kubernetes representation of the Installation into Porter's resource format.
func (in InstallationSpec) ToPorterDocument() ([]byte, error) {
b, err := yaml.Marshal(in)
return b, errors.Wrap(err, "error converting the Installation spec into its Porter resource representation")
}
func (in InstallationSpec) MarshalYAML() (interface{}, error) {
type Alias InstallationSpec
raw := struct {
Alias `yaml:",inline"`
Parameters map[string]interface{} `yaml:"parameters,omitempty"`
}{
Alias: Alias(in),
}
if in.Parameters.Raw != nil {
err := json.Unmarshal(in.Parameters.Raw, &raw.Parameters)
if err != nil {
return nil, errors.Wrapf(err, "error unmarshaling raw parameters\n%s", string(in.Parameters.Raw))
}
}
return raw, nil
}
// InstallationStatus defines the observed state of Installation
type InstallationStatus struct {
// The last generation observed by the controller.
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// The currently active job that is running Porter.
ActiveJob *v1.LocalObjectReference `json:"activeJob,omitempty"`
// The current status of the installation
// Possible values are: Unknown, Pending, Running, Succeeded, and Failed.
// +kubebuilder:validation:Type=string
Phase InstallationPhase `json:"phase,omitempty"`
// Conditions store a list of states that have been reached.
// Each condition refers to the status of the ActiveJob
// Possible conditions are: Scheduled, Started, Completed, and Failed
Conditions []metav1.Condition `json:"conditions,omitempty"`
}
// Reset the installation status before Porter is run.
// This wipes out the status from any previous runs.
func (s *InstallationStatus) Initialize() {
s.Conditions = []metav1.Condition{}
s.Phase = PhaseUnknown
s.ActiveJob = nil
}
// These are valid statuses for an Installation.
type InstallationPhase string
const (
// PhaseUnknown means that we don't know what porter is doing yet.
PhaseUnknown InstallationPhase = "Unknown"
// PhasePending means that Porter's execution is pending.
PhasePending InstallationPhase = "Pending"
// PhasePending indicates that Porter is running.
PhaseRunning InstallationPhase = "Running"
// PhaseSucceeded means that calling Porter succeeded.
PhaseSucceeded InstallationPhase = "Succeeded"
// PhaseFailed means that calling Porter failed.
PhaseFailed InstallationPhase = "Failed"
)
// These are valid conditions of an Installation.
type InstallationConditionType string
const (
// ConditionScheduled means that the Porter run has been scheduled.
ConditionScheduled InstallationConditionType = "Scheduled"
// ConditionStarted means that the Porter run has started.
ConditionStarted InstallationConditionType = "Started"
// ConditionComplete means the Porter run has completed successfully.
ConditionComplete InstallationConditionType = "Completed"
// ConditionFailed means the Porter run failed.
ConditionFailed InstallationConditionType = "Failed"
)
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// Installation is the Schema for the installations API
type Installation struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec InstallationSpec `json:"spec,omitempty"`
Status InstallationStatus `json:"status,omitempty"`
}
// GetRetryLabelValue returns a value that is safe to use
// as a label value and represents the retry annotation used
// to trigger reconciliation. Annotations don't have limits on
// the value, but labels are restricted to alphanumeric and .-_
// I am just hashing the annotation value here to avoid problems
// using it directly as a label value.
func (i Installation) GetRetryLabelValue() string {
retry := i.Annotations[AnnotationRetry]
if retry == "" {
return ""
}
sum := md5.Sum([]byte(retry))
return hex.EncodeToString(sum[:])
}
// +kubebuilder:object:root=true
// InstallationList contains a list of Installation
type InstallationList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Installation `json:"items"`
}
func init() {
SchemeBuilder.Register(&Installation{}, &InstallationList{})
}