diff --git a/pkg/config/draftconfig.go b/pkg/config/draftconfig.go index b3f69e94..1fa8465f 100644 --- a/pkg/config/draftconfig.go +++ b/pkg/config/draftconfig.go @@ -5,6 +5,8 @@ import ( "fmt" "io/fs" + "github.com/Azure/draft/pkg/config/transformers" + "github.com/Azure/draft/pkg/config/validators" log "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" @@ -13,34 +15,46 @@ import ( const draftConfigFile = "draft.yaml" +type VariableValidator func(string) error +type VariableTransformer func(string) (string, error) + type DraftConfig struct { - TemplateName string `yaml:"templateName"` - DisplayName string `yaml:"displayName"` - Description string `yaml:"description"` - Type string `yaml:"type"` - Versions string `yaml:"versions"` - DefaultVersion string `yaml:"defaultVersion"` - Variables []*BuilderVar `yaml:"variables"` - FileNameOverrideMap map[string]string `yaml:"filenameOverrideMap"` + TemplateName string `yaml:"templateName"` + DisplayName string `yaml:"displayName"` + Description string `yaml:"description"` + Type string `yaml:"type"` + Versions string `yaml:"versions"` + DefaultVersion string `yaml:"defaultVersion"` + Variables []*BuilderVar `yaml:"variables"` + FileNameOverrideMap map[string]string `yaml:"filenameOverrideMap"` + Validators map[string]VariableValidator `yaml:"validators"` + Transformers map[string]VariableTransformer `yaml:"transformers"` } type BuilderVar struct { - Name string `yaml:"name"` - Default BuilderVarDefault `yaml:"default"` - Description string `yaml:"description"` - ExampleValues []string `yaml:"exampleValues"` - Type string `yaml:"type"` - Kind string `yaml:"kind"` - Value string `yaml:"value"` - Versions string `yaml:"versions"` + Name string `yaml:"name"` + ConditionalRef BuilderVarConditionalReference `yaml:"conditionalReference"` + Default BuilderVarDefault `yaml:"default"` + Description string `yaml:"description"` + ExampleValues []string `yaml:"exampleValues"` + Type string `yaml:"type"` + Kind string `yaml:"kind"` + Value string `yaml:"value"` + Versions string `yaml:"versions"` } +// BuilderVarDefault holds info on the default value of a variable type BuilderVarDefault struct { IsPromptDisabled bool `yaml:"disablePrompt"` ReferenceVar string `yaml:"referenceVar"` Value string `yaml:"value"` } +// BuilderVarConditionalReference holds a reference to a variable thats value can effect validation/transformation of the associated variable +type BuilderVarConditionalReference struct { + ReferenceVar string `yaml:"referenceVar"` +} + func NewConfigFromFS(fileSys fs.FS, path string) (*DraftConfig, error) { configBytes, err := fs.ReadFile(fileSys, path) if err != nil { @@ -91,7 +105,17 @@ func (d *DraftConfig) GetVariableValue(name string) (string, error) { if variable.Value == "" { return "", fmt.Errorf("variable %s has no value", name) } - return variable.Value, nil + + if err := d.GetVariableValidator(variable.Kind)(variable.Value); err != nil { + return "", fmt.Errorf("failed variable validation: %w", err) + } + + response, err := d.GetVariableTransformer(variable.Kind)(variable.Value) + if err != nil { + return "", fmt.Errorf("failed variable transformation: %w", err) + } + + return response, nil } } @@ -109,6 +133,44 @@ func (d *DraftConfig) SetVariable(name, value string) { } } +// GetVariableTransformer returns the transformer for a specific variable kind +func (d *DraftConfig) GetVariableTransformer(kind string) VariableTransformer { + // user overrides + if transformer, ok := d.Transformers[kind]; ok { + return transformer + } + + // internally defined transformers + return transformers.GetTransformer(kind) +} + +// GetVariableValidator returns the validator for a specific variable kind +func (d *DraftConfig) GetVariableValidator(kind string) VariableValidator { + // user overrides + if validator, ok := d.Validators[kind]; ok { + return validator + } + + // internally defined validators + return validators.GetValidator(kind) +} + +// SetVariableTransformer sets the transformer for a specific variable kind +func (d *DraftConfig) SetVariableTransformer(kind string, transformer VariableTransformer) { + if d.Transformers == nil { + d.Transformers = make(map[string]VariableTransformer) + } + d.Transformers[kind] = transformer +} + +// SetVariableValidator sets the validator for a specific variable kind +func (d *DraftConfig) SetVariableValidator(kind string, validator VariableValidator) { + if d.Validators == nil { + d.Validators = make(map[string]VariableValidator) + } + d.Validators[kind] = validator +} + // ApplyDefaultVariables will apply the defaults to variables that are not already set func (d *DraftConfig) ApplyDefaultVariables() error { for _, variable := range d.Variables { diff --git a/pkg/config/draftconfig_template_test.go b/pkg/config/draftconfig_template_test.go index c7e705a7..6eac2791 100644 --- a/pkg/config/draftconfig_template_test.go +++ b/pkg/config/draftconfig_template_test.go @@ -3,13 +3,17 @@ package config import ( "fmt" "io/fs" + "regexp" "strings" "testing" "github.com/Azure/draft/template" + "github.com/blang/semver/v4" "github.com/stretchr/testify/assert" ) +const alphaNumUnderscoreHyphen = "^[A-Za-z][A-Za-z0-9-_]{1,62}[A-Za-z0-9]$" + var allTemplates = map[string]*DraftConfig{} var validTemplateTypes = map[string]bool{ @@ -67,6 +71,7 @@ func TestTempalteValidation(t *testing.T) { } func loadTemplatesWithValidation() error { + regexp := regexp.MustCompile(alphaNumUnderscoreHyphen) return fs.WalkDir(template.Templates, ".", func(path string, d fs.DirEntry, err error) error { if err != nil { return err @@ -93,6 +98,10 @@ func loadTemplatesWithValidation() error { return fmt.Errorf("template %s has no template name", path) } + if !regexp.MatchString(currTemplate.TemplateName) { + return fmt.Errorf("template %s name must match the alpha-numeric-underscore-hyphen regex: %s", path, currTemplate.TemplateName) + } + if _, ok := allTemplates[strings.ToLower(currTemplate.TemplateName)]; ok { return fmt.Errorf("template %s has a duplicate template name", path) } @@ -101,12 +110,12 @@ func loadTemplatesWithValidation() error { return fmt.Errorf("template %s has an invalid type: %s", path, currTemplate.Type) } - // version range check once we define versions - // if _, err := semver.ParseRange(currTemplate.Versions); err != nil { - // return fmt.Errorf("template %s has an invalid version range: %s", path, currTemplate.Versions) - // } + if _, err := semver.ParseRange(currTemplate.Versions); err != nil { + return fmt.Errorf("template %s has an invalid version range: %s", path, currTemplate.Versions) + } referenceVarMap := map[string]*BuilderVar{} + conditionRefMap := map[string]*BuilderVar{} allVariables := map[string]*BuilderVar{} for _, variable := range currTemplate.Variables { if variable.Name == "" { @@ -121,29 +130,43 @@ func loadTemplatesWithValidation() error { return fmt.Errorf("template %s has an invalid variable kind: %s", path, variable.Kind) } - // version range check once we define versions - // if _, err := semver.ParseRange(variable.Versions); err != nil { - // return fmt.Errorf("template %s has an invalid version range: %s", path, variable.Versions) - // } + if _, err := semver.ParseRange(variable.Versions); err != nil { + return fmt.Errorf("template %s has an invalid version range: %s", path, variable.Versions) + } allVariables[variable.Name] = variable if variable.Default.ReferenceVar != "" { referenceVarMap[variable.Name] = variable } + + if variable.ConditionalRef.ReferenceVar != "" { + conditionRefMap[variable.Name] = variable + } } for _, currVar := range referenceVarMap { refVar, ok := allVariables[currVar.Default.ReferenceVar] if !ok { - return fmt.Errorf("template %s has a variable %s with reference to a non-existent variable: %s", path, currVar.Name, currVar.Default.ReferenceVar) + return fmt.Errorf("template %s has a variable %s with default reference to a non-existent variable: %s", path, currVar.Name, currVar.Default.ReferenceVar) } if currVar.Name == refVar.Name { - return fmt.Errorf("template %s has a variable with cyclical reference to itself: %s", path, currVar.Name) + return fmt.Errorf("template %s has a variable with cyclical default reference to itself: %s", path, currVar.Name) + } + + if isCyclicalDefaultVariableReference(currVar, refVar, allVariables, map[string]bool{}) { + return fmt.Errorf("template %s has a variable with cyclical default reference to itself: %s", path, currVar.Name) + } + } + + for _, currVar := range conditionRefMap { + refVar, ok := allVariables[currVar.ConditionalRef.ReferenceVar] + if !ok { + return fmt.Errorf("template %s has a variable %s with conditional reference to a non-existent variable: %s", path, currVar.Name, currVar.ConditionalRef.ReferenceVar) } - if isCyclicalVariableReference(currVar, refVar, allVariables, map[string]bool{}) { - return fmt.Errorf("template %s has a variable with cyclical reference to itself: %s", path, currVar.Name) + if isCyclicalConditionalVariableReference(currVar, refVar, allVariables, map[string]bool{}) { + return fmt.Errorf("template %s has a variable with cyclical conditional reference to itself or references a non existing variable: %s", path, currVar.Name) } } @@ -152,7 +175,7 @@ func loadTemplatesWithValidation() error { }) } -func isCyclicalVariableReference(initialVar, currRefVar *BuilderVar, allVariables map[string]*BuilderVar, visited map[string]bool) bool { +func isCyclicalDefaultVariableReference(initialVar, currRefVar *BuilderVar, allVariables map[string]*BuilderVar, visited map[string]bool) bool { if initialVar.Name == currRefVar.Name { return true } @@ -171,5 +194,27 @@ func isCyclicalVariableReference(initialVar, currRefVar *BuilderVar, allVariable } visited[currRefVar.Name] = true - return isCyclicalVariableReference(initialVar, refVar, allVariables, visited) + return isCyclicalDefaultVariableReference(initialVar, refVar, allVariables, visited) +} + +func isCyclicalConditionalVariableReference(initialVar, currRefVar *BuilderVar, allVariables map[string]*BuilderVar, visited map[string]bool) bool { + if initialVar.Name == currRefVar.Name { + return true + } + + if _, ok := visited[currRefVar.Name]; ok { + return true + } + + if currRefVar.ConditionalRef.ReferenceVar == "" { + return false + } + + refVar, ok := allVariables[currRefVar.ConditionalRef.ReferenceVar] + if !ok { + return false + } + + visited[currRefVar.Name] = true + return isCyclicalConditionalVariableReference(initialVar, refVar, allVariables, visited) } diff --git a/pkg/config/transformers/transformers.go b/pkg/config/transformers/transformers.go new file mode 100644 index 00000000..48fce997 --- /dev/null +++ b/pkg/config/transformers/transformers.go @@ -0,0 +1,12 @@ +package transformers + +func GetTransformer(variableKind string) func(string) (string, error) { + switch variableKind { + default: + return DefaultTransformer + } +} + +func DefaultTransformer(inputVar string) (string, error) { + return inputVar, nil +} diff --git a/pkg/config/transformers/transformers_test.go b/pkg/config/transformers/transformers_test.go new file mode 100644 index 00000000..72c4286e --- /dev/null +++ b/pkg/config/transformers/transformers_test.go @@ -0,0 +1,17 @@ +package transformers + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetTransformer(t *testing.T) { + assert.NotNil(t, GetTransformer("NonExistentKind")) +} + +func TestDefaultTransformer(t *testing.T) { + res, err := DefaultTransformer("test") + assert.Nil(t, err) + assert.Equal(t, "test", res) +} diff --git a/pkg/config/validators/validators.go b/pkg/config/validators/validators.go new file mode 100644 index 00000000..2c7e5c9f --- /dev/null +++ b/pkg/config/validators/validators.go @@ -0,0 +1,12 @@ +package validators + +func GetValidator(variableKind string) func(string) error { + switch variableKind { + default: + return DefaultValidator + } +} + +func DefaultValidator(input string) error { + return nil +} diff --git a/pkg/config/validators/validators_test.go b/pkg/config/validators/validators_test.go new file mode 100644 index 00000000..7e8a6e1b --- /dev/null +++ b/pkg/config/validators/validators_test.go @@ -0,0 +1,15 @@ +package validators + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetValidator(t *testing.T) { + assert.NotNil(t, GetValidator("NonExistentKind")) +} + +func TestDefaultValidator(t *testing.T) { + assert.Nil(t, DefaultValidator("test")) +} diff --git a/pkg/fixtures/manifests/hpa/hpa.yaml b/pkg/fixtures/manifests/hpa/hpa.yaml new file mode 100644 index 00000000..dd13b9cd --- /dev/null +++ b/pkg/fixtures/manifests/hpa/hpa.yaml @@ -0,0 +1,22 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: test-app + labels: + app.kubernetes.io/name: test-app + app.kubernetes.io/part-of: test-app-project + kubernetes.azure.com/generator: draft +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: test-app + minReplicas: 2 + maxReplicas: 5 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 80 \ No newline at end of file diff --git a/pkg/fixtures/manifests/pdb/pdb.yaml b/pkg/fixtures/manifests/pdb/pdb.yaml new file mode 100644 index 00000000..40e9063f --- /dev/null +++ b/pkg/fixtures/manifests/pdb/pdb.yaml @@ -0,0 +1,13 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: test-app + labels: + app.kubernetes.io/name: test-app + app.kubernetes.io/part-of: test-app-project + kubernetes.azure.com/generator: draft +spec: + maxUnavailable: 1 + selector: + matchLabels: + app: test-app \ No newline at end of file diff --git a/pkg/fixtures/manifests/service/service.yaml b/pkg/fixtures/manifests/service/service.yaml new file mode 100644 index 00000000..802987ce --- /dev/null +++ b/pkg/fixtures/manifests/service/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: test-app + labels: + app.kubernetes.io/name: test-app + app.kubernetes.io/part-of: test-app-project + kubernetes.azure.com/generator: draft +spec: + type: ClusterIP + selector: + app: test-app + ports: + - protocol: TCP + port: 80 + targetPort: 80 \ No newline at end of file diff --git a/pkg/handlers/template_test.go b/pkg/handlers/template_test.go index 7090090b..7083f857 100644 --- a/pkg/handlers/template_test.go +++ b/pkg/handlers/template_test.go @@ -4,6 +4,7 @@ import ( "fmt" "path/filepath" "reflect" + "regexp" "strings" "testing" @@ -12,6 +13,25 @@ import ( "github.com/stretchr/testify/assert" ) +func AlwaysFailingValidator(value string) error { + return fmt.Errorf("this is a failing validator") +} + +func AlwaysFailingTransformer(value string) (string, error) { + return "", fmt.Errorf("this is a failing transformer") +} + +func K8sLabelValidator(value string) error { + labelRegex, err := regexp.Compile("^((A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$") + if err != nil { + return err + } + if !labelRegex.MatchString(value) { + return fmt.Errorf("invalid label: %s", value) + } + return nil +} + func TestDeepCopy(t *testing.T) { // This will fail on adding a new field to the undelying structs that arent handled in DeepCopy testTemplate, err := GetTemplate("deployment-manifests", "0.0.1", ".", &writers.FileMapWriter{}) @@ -33,6 +53,8 @@ func TestTemplateHandlerValidation(t *testing.T) { varMap map[string]string fileNameOverride map[string]string expectedErr error + validators map[string]func(string) error + transformers map[string]func(string) (string, error) }{ { name: "valid manifest deployment", @@ -337,6 +359,69 @@ func TestTemplateHandlerValidation(t *testing.T) { "service-port": "80", }, }, + { + name: "manifest deployment vars with err from validators", + templateName: "deployment-manifests", + fixturesBaseDir: "../fixtures/deployments/manifest", + version: "0.0.1", + dest: ".", + templateWriter: &writers.FileMapWriter{}, + varMap: map[string]string{ + "APPNAME": "testapp", + "NAMESPACE": "default", + "PORT": "80", + "IMAGENAME": "testimage", + "IMAGETAG": "latest", + "GENERATORLABEL": "draft", + "SERVICEPORT": "80", + }, + validators: map[string]func(string) error{ + "kubernetesResourceName": AlwaysFailingValidator, + }, + expectedErr: fmt.Errorf("this is a failing validator"), + }, + { + name: "manifest deployment vars with err from transformers", + templateName: "deployment-manifests", + fixturesBaseDir: "../fixtures/deployments/manifest", + version: "0.0.1", + dest: ".", + templateWriter: &writers.FileMapWriter{}, + varMap: map[string]string{ + "APPNAME": "testapp", + "NAMESPACE": "default", + "PORT": "80", + "IMAGENAME": "testimage", + "IMAGETAG": "latest", + "GENERATORLABEL": "draft", + "SERVICEPORT": "80", + }, + transformers: map[string]func(string) (string, error){ + "kubernetesResourceName": AlwaysFailingTransformer, + }, + expectedErr: fmt.Errorf("this is a failing transformer"), + }, + { + name: "manifest deployment vars with err from label validator", + templateName: "deployment-manifests", + fixturesBaseDir: "../fixtures/deployments/manifest", + version: "0.0.1", + dest: ".", + templateWriter: &writers.FileMapWriter{}, + varMap: map[string]string{ + "APPNAME": "*myTestApp", + "NAMESPACE": "default", + "PORT": "80", + "IMAGENAME": "testimage", + "IMAGETAG": "latest", + "GENERATORLABEL": "draft", + "SERVICEPORT": "80", + }, + validators: map[string]func(string) error{ + "kubernetesResourceName": K8sLabelValidator, + }, + expectedErr: fmt.Errorf("invalid label: *myTestApp"), + }, { name: "valid helm workflow", templateName: "github-workflow-helm", @@ -361,7 +446,8 @@ func TestTemplateHandlerValidation(t *testing.T) { "CHARTOVERRIDES": "replicas:2", "NAMESPACE": "default", }, - }, { + }, + { name: "valid helm workflow", templateName: "github-workflow-kustomize", fixturesBaseDir: "../fixtures/workflows/github/kustomize", @@ -381,7 +467,8 @@ func TestTemplateHandlerValidation(t *testing.T) { "BUILDCONTEXTPATH": "test", "NAMESPACE": "default", }, - }, { + }, + { name: "valid manifest workflow", templateName: "github-workflow-manifests", fixturesBaseDir: "../fixtures/workflows/github/manifests", @@ -402,6 +489,42 @@ func TestTemplateHandlerValidation(t *testing.T) { "NAMESPACE": "default", }, }, + { + name: "valid hpa manifest", + templateName: "horizontalPodAutoscaler-manifests", + fixturesBaseDir: "../fixtures/manifests/hpa", + version: "0.0.1", + dest: ".", + templateWriter: &writers.FileMapWriter{}, + varMap: map[string]string{ + "APPNAME": "test-app", + "PARTOF": "test-app-project", + }, + }, + { + name: "valid pdb manifest", + templateName: "podDisruptionBudget-manifests", + fixturesBaseDir: "../fixtures/manifests/pdb", + version: "0.0.1", + dest: ".", + templateWriter: &writers.FileMapWriter{}, + varMap: map[string]string{ + "APPNAME": "test-app", + "PARTOF": "test-app-project", + }, + }, + { + name: "valid service manifest", + templateName: "service-manifests", + fixturesBaseDir: "../fixtures/manifests/service", + version: "0.0.1", + dest: ".", + templateWriter: &writers.FileMapWriter{}, + varMap: map[string]string{ + "APPNAME": "test-app", + "PARTOF": "test-app-project", + }, + }, } for _, tt := range tests { @@ -414,6 +537,14 @@ func TestTemplateHandlerValidation(t *testing.T) { template.Config.SetVariable(k, v) } + for k, v := range tt.validators { + template.Config.SetVariableValidator(k, v) + } + + for k, v := range tt.transformers { + template.Config.SetVariableTransformer(k, v) + } + overrideReverseLookup := make(map[string]string) for k, v := range tt.fileNameOverride { template.Config.SetFileNameOverride(k, v) @@ -422,7 +553,11 @@ func TestTemplateHandlerValidation(t *testing.T) { err = template.Generate() if tt.expectedErr != nil { - assert.Equal(t, tt.expectedErr.Error(), err.Error()) + if err == nil { + t.Errorf("expected error %v, got nil", tt.expectedErr) + return + } + assert.True(t, strings.Contains(err.Error(), tt.expectedErr.Error())) return } assert.Nil(t, err) diff --git a/template/manifests/HorizontalPodAutoscaling/manifest/draft.yaml b/template/manifests/HorizontalPodAutoscaler/manifests/draft.yaml similarity index 83% rename from template/manifests/HorizontalPodAutoscaling/manifest/draft.yaml rename to template/manifests/HorizontalPodAutoscaler/manifests/draft.yaml index 85aa7fb0..c2dcc98e 100644 --- a/template/manifests/HorizontalPodAutoscaling/manifest/draft.yaml +++ b/template/manifests/HorizontalPodAutoscaler/manifests/draft.yaml @@ -1,42 +1,51 @@ -templateName: "horizontalPodAutoscaling-manifest" +templateName: "horizontalPodAutoscaler-manifests" description: "This template is used to create a horizontalPodAutoscaling for an application" +versions: "0.0.1" +defaultVersion: "0.0.1" type: "manifest" variables: - name: "APPNAME" type: "string" kind: "kubernetesResourceName" description: "the name of the application" + versions: ">=0.0.1" - name: "PARTOF" type: "string" kind: "label" description: "the label to identify which project the resource belong to" + versions: ">=0.0.1" - name: "GENERATORLABEL" type: "string" kind: "label" description: "the label to identify who generated the resource" + versions: ">=0.0.1" default: value: "draft" - name: "MINIMUMREPLICAS" type: "int" kind: "replicaCount" description: "specifies the minimum number of pod replicas that the deployment should have" + versions: ">=0.0.1" default: value: 2 - name: "MAXIMUMREPLICAS" type: "int" kind: "replicaCount" description: "defines the maximum number of pod replicas the deployment can scale to" + versions: ">=0.0.1" default: value: 5 - name: "RESOURCETYPE" type: "string" kind: "scalingResourceType" description: "specifies the resource type (e.g., cpu or memory) to be monitored for scaling" + versions: ">=0.0.1" default: value: "cpu" - name: "AVGUTILIZATION" type: "int" kind: "scalingResourceUtilization" description: "specifies the average utilization for the monitored resource, triggering scaling when exceeded" + versions: ">=0.0.1" default: value: 80 \ No newline at end of file diff --git a/template/manifests/HorizontalPodAutoscaler/manifests/hpa.yaml b/template/manifests/HorizontalPodAutoscaler/manifests/hpa.yaml new file mode 100644 index 00000000..be8bb34a --- /dev/null +++ b/template/manifests/HorizontalPodAutoscaler/manifests/hpa.yaml @@ -0,0 +1,22 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ .Config.GetVariableValue "APPNAME" }} + labels: + app.kubernetes.io/name: {{ .Config.GetVariableValue "APPNAME" }} + app.kubernetes.io/part-of: {{ .Config.GetVariableValue "PARTOF" }} + kubernetes.azure.com/generator: {{ .Config.GetVariableValue "GENERATORLABEL" }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ .Config.GetVariableValue "APPNAME" }} + minReplicas: {{ .Config.GetVariableValue "MINIMUMREPLICAS" }} + maxReplicas: {{ .Config.GetVariableValue "MAXIMUMREPLICAS" }} + metrics: + - type: Resource + resource: + name: {{ .Config.GetVariableValue "RESOURCETYPE" }} + target: + type: Utilization + averageUtilization: {{ .Config.GetVariableValue "AVGUTILIZATION"}} \ No newline at end of file diff --git a/template/manifests/HorizontalPodAutoscaling/manifest/hpa.yaml b/template/manifests/HorizontalPodAutoscaling/manifest/hpa.yaml deleted file mode 100644 index 3250dd6e..00000000 --- a/template/manifests/HorizontalPodAutoscaling/manifest/hpa.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: {{.APPNAME}} - labels: - app.kubernetes.io/name: {{.APPNAME}} - app.kubernetes.io/part-of: {{.PARTOF}} - kubernetes.azure.com/generator: {{.GENERATORLABEL}} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{.APPNAME}} - minReplicas: {{.MINIMUMREPLICAS}} - maxReplicas: {{.MAXIMUMREPLICAS}} - metrics: - - type: Resource - resource: - name: {{.RESOURCETYPE}} - target: - type: Utilization - averageUtilization: {{.AVGUTILIZATION}} \ No newline at end of file diff --git a/template/manifests/PodDisruptionBudget/manifest/pdb.yaml b/template/manifests/PodDisruptionBudget/manifest/pdb.yaml deleted file mode 100644 index 71f25c83..00000000 --- a/template/manifests/PodDisruptionBudget/manifest/pdb.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: {{.APPNAME}} - labels: - app.kubernetes.io/name: {{.APPNAME}} - app.kubernetes.io/part-of: {{.PARTOF}} - kubernetes.azure.com/generator: {{.GENERATORLABEL}} -spec: - maxUnavailable: {{.MAXUNAVAILABLE}} - selector: - matchLabels: - app: {{.APPNAME}} \ No newline at end of file diff --git a/template/manifests/PodDisruptionBudget/manifest/draft.yaml b/template/manifests/PodDisruptionBudget/manifests/draft.yaml similarity index 80% rename from template/manifests/PodDisruptionBudget/manifest/draft.yaml rename to template/manifests/PodDisruptionBudget/manifests/draft.yaml index 58bc20fa..7602d2d4 100644 --- a/template/manifests/PodDisruptionBudget/manifest/draft.yaml +++ b/template/manifests/PodDisruptionBudget/manifests/draft.yaml @@ -1,24 +1,30 @@ -templateName: "podDisruptionBudget-manifest" +templateName: "podDisruptionBudget-manifests" description: "This template is used to create a PodDisruptionBudget for an application" +versions: "0.0.1" +defaultVersions: "0.0.1" type: "manifest" variables: - name: "APPNAME" type: "string" kind: "kubernetesResourceName" description: "the name of the application" + versions: ">=0.0.1" - name: "PARTOF" type: "string" kind: "label" description: "the label to identify which project the resource belong to" + versions: ">=0.0.1" - name: "GENERATORLABEL" type: "string" kind: "label" description: "the label to identify who generated the resource" + versions: ">=0.0.1" default: value: "draft" - name: "MAXUNAVAILABLE" type: "int" kind: "resourceLimit" description: "specifies the maximum number of pods that can be unavailable during a disruption, such as a pod eviction" + versions: ">=0.0.1" default: value: 1 \ No newline at end of file diff --git a/template/manifests/PodDisruptionBudget/manifests/pdb.yaml b/template/manifests/PodDisruptionBudget/manifests/pdb.yaml new file mode 100644 index 00000000..a9ea9bb2 --- /dev/null +++ b/template/manifests/PodDisruptionBudget/manifests/pdb.yaml @@ -0,0 +1,13 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{.Config.GetVariableValue "APPNAME" }} + labels: + app.kubernetes.io/name: {{ .Config.GetVariableValue "APPNAME"}} + app.kubernetes.io/part-of: {{ .Config.GetVariableValue "PARTOF" }} + kubernetes.azure.com/generator: {{ .Config.GetVariableValue "GENERATORLABEL"}} +spec: + maxUnavailable: {{ .Config.GetVariableValue "MAXUNAVAILABLE" }} + selector: + matchLabels: + app: {{ .Config.GetVariableValue "APPNAME" }} \ No newline at end of file diff --git a/template/manifests/Service/draft.yaml b/template/manifests/Service/manifests/draft.yaml similarity index 81% rename from template/manifests/Service/draft.yaml rename to template/manifests/Service/manifests/draft.yaml index b66fc0c1..3a884919 100644 --- a/template/manifests/Service/draft.yaml +++ b/template/manifests/Service/manifests/draft.yaml @@ -1,30 +1,37 @@ -templateName: "Service" +templateName: "service-manifests" description: "This template is used to create a generic Service for an application" +versions: "0.0.1" +defaultVersion: "0.0.1" type: "manifest" variables: - name: "PORT" type: "int" kind: "port" description: "the port the service uses to make the application accessible from outside the cluster" + versions: ">=0.0.1" default: value: 80 - name: "APPNAME" type: "string" kind: "kubernetesResourceName" description: "the name of the application" + versions: ">=0.0.1" - name: "PARTOF" type: "string" kind: "label" description: "the label to identify which project the resource belong to" + versions: ">=0.0.1" - name: "GENERATORLABEL" type: "string" kind: "label" description: "the label to identify who generated the resource" + versions: ">=0.0.1" default: value: "draft" - name: "TARGETPORT" type: "int" kind: "port" description: "the port exposed in the application" + versions: ">=0.0.1" default: referenceVar: "PORT" \ No newline at end of file diff --git a/template/manifests/Service/manifests/service.yaml b/template/manifests/Service/manifests/service.yaml new file mode 100644 index 00000000..4cac4368 --- /dev/null +++ b/template/manifests/Service/manifests/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Config.GetVariableValue "APPNAME" }} + labels: + app.kubernetes.io/name: {{ .Config.GetVariableValue "APPNAME" }} + app.kubernetes.io/part-of: {{ .Config.GetVariableValue "PARTOF" }} + kubernetes.azure.com/generator: {{ .Config.GetVariableValue "GENERATORLABEL" }} +spec: + type: ClusterIP + selector: + app: {{ .Config.GetVariableValue "APPNAME" }} + ports: + - protocol: TCP + port: {{ .Config.GetVariableValue "PORT" }} + targetPort: {{ .Config.GetVariableValue "TARGETPORT" }} \ No newline at end of file diff --git a/template/manifests/Service/service.yaml b/template/manifests/Service/service.yaml deleted file mode 100644 index 2ab33e33..00000000 --- a/template/manifests/Service/service.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{.APPNAME}} - labels: - app.kubernetes.io/name: {{.APPNAME}} - app.kubernetes.io/part-of: {{.PARTOF}} - kubernetes.azure.com/generator: {{.GENERATORLABEL}} -spec: - type: ClusterIP - selector: - app: {{.APPNAME}} - ports: - - protocol: TCP - port: {{.PORT}} - targetPort: {{.TARGETPORT}} \ No newline at end of file