diff --git a/.github/workflows/pr-validation.yaml b/.github/workflows/pr-validation.yaml index cfc8c33..3e35872 100644 --- a/.github/workflows/pr-validation.yaml +++ b/.github/workflows/pr-validation.yaml @@ -39,6 +39,27 @@ jobs: echo 'run make fmt and commit changes' exit 1 fi + + generate-schema: + runs-on: ubuntu-latest + steps: + - name: Clone repo + uses: actions/checkout@v3 + - name: Setup go + uses: actions/setup-go@v4 + with: + go-version: "^1.20.5" + - name: Generate schema + run: | + make generate-schema + - name: Check if working tree is dirty + run: | + if [[ $(git status --porcelain) ]]; then + git diff + echo 'run make generate-schema and commit changes' + exit 1 + fi + build: runs-on: ubuntu-latest steps: @@ -121,4 +142,4 @@ jobs: format: "table" exit-code: "1" ignore-unfixed: true - severity: "CRITICAL,HIGH" \ No newline at end of file + severity: "CRITICAL,HIGH" diff --git a/Makefile b/Makefile index a005772..d1994aa 100644 --- a/Makefile +++ b/Makefile @@ -10,14 +10,18 @@ ifneq (,$(wildcard $(TEST_ENV_FILE))) export endif +.PHONY: all all: fmt vet lint test +.PHONY: lint lint: golangci-lint run ./... +.PHONY: fmt fmt: go fmt ./... +.PHONY: vet vet: go vet ./... @@ -25,25 +29,33 @@ vet: build: CGO_ENABLED=0 go build -installsuffix 'static' -o bin/azcagit ./src/main.go +.PHONY: generate-schema +generate-schema: + go run ./generate_schema.go + .PHONY: test test: fmt vet go test --cover ./... +.PHONY: cover cover: mkdir -p .tmp go test -timeout 5m -coverpkg=./src/... -coverprofile=.tmp/coverage.out ./src/... go tool cover -html=.tmp/coverage.out +.PHONY: terraform-up terraform-up: cd test/terraform terraform init terraform apply -auto-approve -var-file="../../.tmp/lab.tfvars" +.PHONY: terraform-mr-up terraform-mr-up: cd test/terraform-multi-region terraform init terraform apply -auto-approve -var-file="../../.tmp/lab.tfvars" +.PHONY: run run: # AZURE_TENANT_ID=$${TENANT_ID} AZURE_CLIENT_ID=$${CLIENT_ID} AZURE_CLIENT_SECRET=$${CLIENT_SECRET} \ go run ./src \ @@ -62,13 +74,16 @@ run: --notifications-enabled \ --environment $${ENV} +.PHONY: docker-build docker-build: docker build . -t $(IMG) +.PHONY: docker-run docker-run: docker-build docker run -it --rm -e AZURE_TENANT_ID=$${TENANT_ID} -e AZURE_CLIENT_ID=$${CLIENT_ID} -e AZURE_CLIENT_SECRET=$${CLIENT_SECRET} $(IMG) \ --debug \ --resource-group-name $${RG_NAME} \ + --own-resource-group-name $${OWN_RG_NAME} \ --subscription-id $${SUB_ID} \ --managed-environment-id $${ME_ID} \ --key-vault-name $${KV_NAME} \ @@ -77,7 +92,11 @@ docker-run: docker-build --reconcile-interval "10s" \ --git-url $${GIT_URL_AND_CREDS} \ --git-branch "main" \ - --git-yaml-path "yaml/" + --git-yaml-path "yaml/" \ + --notifications-enabled \ + --environment $${ENV} +.PHONY: k6-http-get k6-http-get: - k6 run -e LOAD_TEST_URI=$${LOAD_TEST_URI} test/k6/http_get.js \ No newline at end of file + k6 run -e LOAD_TEST_URI=$${LOAD_TEST_URI} test/k6/http_get.js + diff --git a/README.md b/README.md index 9c01cb5..b545d39 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Platform is used for what we call "platform services", in this case the virtual Tenant is used only to synchronize the Container Apps manifests. The Container Apps that are created by `azcagit` will reside here. -The manifests are in the same format as Kubernetes manifests ([Kubernetes Resource Model aka KRM](https://cloud.google.com/blog/topics/developers-practitioners/build-platform-krm-part-2-how-kubernetes-resource-model-works)), but with a hard coupling to the [Azure Container Apps specification](https://docs.microsoft.com/en-us/azure/templates/microsoft.app/containerapps?pivots=deployment-language-arm-template) for `spec.app` when using `kind: AzureContainerApp` and [Azure Container Jobs specification](https://learn.microsoft.com/en-us/azure/templates/microsoft.app/jobs?pivots=deployment-language-arm-template) for `spec.job` when using `kind: AzureContainerJob`. +The manifests are in the same format as Kubernetes manifests ([Kubernetes Resource Model aka KRM](https://cloud.google.com/blog/topics/developers-practitioners/build-platform-krm-part-2-how-kubernetes-resource-model-works)), but with a hard coupling to the [Azure Container Apps specification](https://docs.microsoft.com/en-us/azure/templates/microsoft.app/containerapps?pivots=deployment-language-arm-template) for `spec.app` when using `kind: AzureContainerApp` and [Azure Container Jobs specification](https://learn.microsoft.com/en-us/azure/templates/microsoft.app/jobs?pivots=deployment-language-arm-template) for `spec.job` when using `kind: AzureContainerJob`. Auto generated schemas can be found in the [schemas](schemas/) directory. An example manifest of an app: diff --git a/generate_schema.go b/generate_schema.go new file mode 100644 index 0000000..a7ff6d9 --- /dev/null +++ b/generate_schema.go @@ -0,0 +1,76 @@ +//go:build generateschema + +package main + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/invopop/jsonschema" + "github.com/invopop/yaml" + "github.com/xenitab/azcagit/src/source" +) + +func main() { + err := run() + if err != nil { + fmt.Fprintf(os.Stderr, "schema generation returned an error: %v\n", err) + os.Exit(1) + } +} + +func run() error { + err := generateSchema(&source.SourceApp{}, "app") + if err != nil { + return err + } + + err = generateSchema(&source.SourceJob{}, "job") + if err != nil { + return err + } + + return nil +} + +func generateSchema[T any](t T, name string) error { + schema := jsonschema.Reflect(&t) + schemaJson, err := schema.MarshalJSON() + if err != nil { + return err + } + + var schemaJsonRaw interface{} + err = json.Unmarshal(schemaJson, &schemaJsonRaw) + if err != nil { + return err + } + + prettySchemaJson, err := json.MarshalIndent(schemaJsonRaw, "", " ") + if err != nil { + return err + } + + schemaYaml, err := yaml.JSONToYAML(schemaJson) + if err != nil { + return err + } + + currDir, err := os.Getwd() + if err != nil { + return err + } + + err = os.WriteFile(fmt.Sprintf("%s/schemas/%s.json", currDir, name), prettySchemaJson, 0644) + if err != nil { + return err + } + + err = os.WriteFile(fmt.Sprintf("%s/schemas/%s.yaml", currDir, name), schemaYaml, 0644) + if err != nil { + return err + } + + return nil +} diff --git a/go.mod b/go.mod index bc75566..a575bc9 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,8 @@ require ( github.com/go-logr/zapr v1.2.4 github.com/google/go-github/v41 v41.0.0 github.com/hashicorp/go-multierror v1.1.1 + github.com/invopop/jsonschema v0.7.0 + github.com/invopop/yaml v0.2.0 github.com/microsoft/azure-devops-go-api/azuredevops/v6 v6.0.1 github.com/stretchr/testify v1.8.4 github.com/whilp/git-urls v1.0.0 @@ -55,6 +57,7 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect diff --git a/go.sum b/go.sum index 30f0978..3040a16 100644 --- a/go.sum +++ b/go.sum @@ -105,8 +105,14 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk= +github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy770So= +github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0= +github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY= +github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= @@ -147,6 +153,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -275,6 +282,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= diff --git a/schemas/app.json b/schemas/app.json new file mode 100644 index 0000000..710e798 --- /dev/null +++ b/schemas/app.json @@ -0,0 +1,1127 @@ +{ + "$defs": { + "Configuration": { + "additionalProperties": false, + "properties": { + "ActiveRevisionsMode": { + "type": "string" + }, + "Dapr": { + "$ref": "#/$defs/Dapr" + }, + "Ingress": { + "$ref": "#/$defs/Ingress" + }, + "MaxInactiveRevisions": { + "type": "integer" + }, + "Registries": { + "items": { + "$ref": "#/$defs/RegistryCredentials" + }, + "type": "array" + }, + "Secrets": { + "items": { + "$ref": "#/$defs/Secret" + }, + "type": "array" + } + }, + "required": [ + "ActiveRevisionsMode", + "Dapr", + "Ingress", + "MaxInactiveRevisions", + "Registries", + "Secrets" + ], + "type": "object" + }, + "Container": { + "additionalProperties": false, + "properties": { + "Args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Env": { + "items": { + "$ref": "#/$defs/EnvironmentVar" + }, + "type": "array" + }, + "Image": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "Probes": { + "items": { + "$ref": "#/$defs/ContainerAppProbe" + }, + "type": "array" + }, + "Resources": { + "$ref": "#/$defs/ContainerResources" + }, + "VolumeMounts": { + "items": { + "$ref": "#/$defs/VolumeMount" + }, + "type": "array" + } + }, + "required": [ + "Args", + "Command", + "Env", + "Image", + "Name", + "Probes", + "Resources", + "VolumeMounts" + ], + "type": "object" + }, + "ContainerApp": { + "additionalProperties": false, + "properties": { + "ExtendedLocation": { + "$ref": "#/$defs/ExtendedLocation" + }, + "ID": { + "type": "string" + }, + "Identity": { + "$ref": "#/$defs/ManagedServiceIdentity" + }, + "Location": { + "type": "string" + }, + "ManagedBy": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "Properties": { + "$ref": "#/$defs/ContainerAppProperties" + }, + "SystemData": { + "$ref": "#/$defs/SystemData" + }, + "Tags": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "Type": { + "type": "string" + } + }, + "required": [ + "Location", + "ExtendedLocation", + "Identity", + "ManagedBy", + "Properties", + "Tags", + "ID", + "Name", + "SystemData", + "Type" + ], + "type": "object" + }, + "ContainerAppProbe": { + "additionalProperties": false, + "properties": { + "FailureThreshold": { + "type": "integer" + }, + "HTTPGet": { + "$ref": "#/$defs/ContainerAppProbeHTTPGet" + }, + "InitialDelaySeconds": { + "type": "integer" + }, + "PeriodSeconds": { + "type": "integer" + }, + "SuccessThreshold": { + "type": "integer" + }, + "TCPSocket": { + "$ref": "#/$defs/ContainerAppProbeTCPSocket" + }, + "TerminationGracePeriodSeconds": { + "type": "integer" + }, + "TimeoutSeconds": { + "type": "integer" + }, + "Type": { + "type": "string" + } + }, + "required": [ + "FailureThreshold", + "HTTPGet", + "InitialDelaySeconds", + "PeriodSeconds", + "SuccessThreshold", + "TCPSocket", + "TerminationGracePeriodSeconds", + "TimeoutSeconds", + "Type" + ], + "type": "object" + }, + "ContainerAppProbeHTTPGet": { + "additionalProperties": false, + "properties": { + "HTTPHeaders": { + "items": { + "$ref": "#/$defs/ContainerAppProbeHTTPGetHTTPHeadersItem" + }, + "type": "array" + }, + "Host": { + "type": "string" + }, + "Path": { + "type": "string" + }, + "Port": { + "type": "integer" + }, + "Scheme": { + "type": "string" + } + }, + "required": [ + "Port", + "HTTPHeaders", + "Host", + "Path", + "Scheme" + ], + "type": "object" + }, + "ContainerAppProbeHTTPGetHTTPHeadersItem": { + "additionalProperties": false, + "properties": { + "Name": { + "type": "string" + }, + "Value": { + "type": "string" + } + }, + "required": [ + "Name", + "Value" + ], + "type": "object" + }, + "ContainerAppProbeTCPSocket": { + "additionalProperties": false, + "properties": { + "Host": { + "type": "string" + }, + "Port": { + "type": "integer" + } + }, + "required": [ + "Port", + "Host" + ], + "type": "object" + }, + "ContainerAppProperties": { + "additionalProperties": false, + "properties": { + "Configuration": { + "$ref": "#/$defs/Configuration" + }, + "CustomDomainVerificationID": { + "type": "string" + }, + "EnvironmentID": { + "type": "string" + }, + "EventStreamEndpoint": { + "type": "string" + }, + "LatestReadyRevisionName": { + "type": "string" + }, + "LatestRevisionFqdn": { + "type": "string" + }, + "LatestRevisionName": { + "type": "string" + }, + "ManagedEnvironmentID": { + "type": "string" + }, + "OutboundIPAddresses": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ProvisioningState": { + "type": "string" + }, + "Template": { + "$ref": "#/$defs/Template" + }, + "WorkloadProfileName": { + "type": "string" + } + }, + "required": [ + "Configuration", + "EnvironmentID", + "ManagedEnvironmentID", + "Template", + "WorkloadProfileName", + "CustomDomainVerificationID", + "EventStreamEndpoint", + "LatestReadyRevisionName", + "LatestRevisionFqdn", + "LatestRevisionName", + "OutboundIPAddresses", + "ProvisioningState" + ], + "type": "object" + }, + "ContainerResources": { + "additionalProperties": false, + "properties": { + "CPU": { + "type": "number" + }, + "EphemeralStorage": { + "type": "string" + }, + "Memory": { + "type": "string" + } + }, + "required": [ + "CPU", + "Memory", + "EphemeralStorage" + ], + "type": "object" + }, + "CorsPolicy": { + "additionalProperties": false, + "properties": { + "AllowCredentials": { + "type": "boolean" + }, + "AllowedHeaders": { + "items": { + "type": "string" + }, + "type": "array" + }, + "AllowedMethods": { + "items": { + "type": "string" + }, + "type": "array" + }, + "AllowedOrigins": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ExposeHeaders": { + "items": { + "type": "string" + }, + "type": "array" + }, + "MaxAge": { + "type": "integer" + } + }, + "required": [ + "AllowedOrigins", + "AllowCredentials", + "AllowedHeaders", + "AllowedMethods", + "ExposeHeaders", + "MaxAge" + ], + "type": "object" + }, + "CustomDomain": { + "additionalProperties": false, + "properties": { + "BindingType": { + "type": "string" + }, + "CertificateID": { + "type": "string" + }, + "Name": { + "type": "string" + } + }, + "required": [ + "Name", + "BindingType", + "CertificateID" + ], + "type": "object" + }, + "CustomScaleRule": { + "additionalProperties": false, + "properties": { + "Auth": { + "items": { + "$ref": "#/$defs/ScaleRuleAuth" + }, + "type": "array" + }, + "Metadata": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "Type": { + "type": "string" + } + }, + "required": [ + "Auth", + "Metadata", + "Type" + ], + "type": "object" + }, + "Dapr": { + "additionalProperties": false, + "properties": { + "AppID": { + "type": "string" + }, + "AppPort": { + "type": "integer" + }, + "AppProtocol": { + "type": "string" + }, + "EnableAPILogging": { + "type": "boolean" + }, + "Enabled": { + "type": "boolean" + }, + "HTTPMaxRequestSize": { + "type": "integer" + }, + "HTTPReadBufferSize": { + "type": "integer" + }, + "LogLevel": { + "type": "string" + } + }, + "required": [ + "AppID", + "AppPort", + "AppProtocol", + "EnableAPILogging", + "Enabled", + "HTTPMaxRequestSize", + "HTTPReadBufferSize", + "LogLevel" + ], + "type": "object" + }, + "EnvironmentVar": { + "additionalProperties": false, + "properties": { + "Name": { + "type": "string" + }, + "SecretRef": { + "type": "string" + }, + "Value": { + "type": "string" + } + }, + "required": [ + "Name", + "SecretRef", + "Value" + ], + "type": "object" + }, + "ExtendedLocation": { + "additionalProperties": false, + "properties": { + "Name": { + "type": "string" + }, + "Type": { + "type": "string" + } + }, + "required": [ + "Name", + "Type" + ], + "type": "object" + }, + "HTTPScaleRule": { + "additionalProperties": false, + "properties": { + "Auth": { + "items": { + "$ref": "#/$defs/ScaleRuleAuth" + }, + "type": "array" + }, + "Metadata": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "required": [ + "Auth", + "Metadata" + ], + "type": "object" + }, + "IPSecurityRestrictionRule": { + "additionalProperties": false, + "properties": { + "Action": { + "type": "string" + }, + "Description": { + "type": "string" + }, + "IPAddressRange": { + "type": "string" + }, + "Name": { + "type": "string" + } + }, + "required": [ + "Action", + "IPAddressRange", + "Name", + "Description" + ], + "type": "object" + }, + "ImageReplacementSpecification": { + "additionalProperties": false, + "properties": { + "imageName": { + "type": "string" + }, + "newImageTag": { + "type": "string" + } + }, + "type": "object" + }, + "Ingress": { + "additionalProperties": false, + "properties": { + "AllowInsecure": { + "type": "boolean" + }, + "ClientCertificateMode": { + "type": "string" + }, + "CorsPolicy": { + "$ref": "#/$defs/CorsPolicy" + }, + "CustomDomains": { + "items": { + "$ref": "#/$defs/CustomDomain" + }, + "type": "array" + }, + "ExposedPort": { + "type": "integer" + }, + "External": { + "type": "boolean" + }, + "Fqdn": { + "type": "string" + }, + "IPSecurityRestrictions": { + "items": { + "$ref": "#/$defs/IPSecurityRestrictionRule" + }, + "type": "array" + }, + "StickySessions": { + "$ref": "#/$defs/IngressStickySessions" + }, + "TargetPort": { + "type": "integer" + }, + "Traffic": { + "items": { + "$ref": "#/$defs/TrafficWeight" + }, + "type": "array" + }, + "Transport": { + "type": "string" + } + }, + "required": [ + "AllowInsecure", + "ClientCertificateMode", + "CorsPolicy", + "CustomDomains", + "ExposedPort", + "External", + "IPSecurityRestrictions", + "StickySessions", + "TargetPort", + "Traffic", + "Transport", + "Fqdn" + ], + "type": "object" + }, + "IngressStickySessions": { + "additionalProperties": false, + "properties": { + "Affinity": { + "type": "string" + } + }, + "required": [ + "Affinity" + ], + "type": "object" + }, + "InitContainer": { + "additionalProperties": false, + "properties": { + "Args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Env": { + "items": { + "$ref": "#/$defs/EnvironmentVar" + }, + "type": "array" + }, + "Image": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "Resources": { + "$ref": "#/$defs/ContainerResources" + }, + "VolumeMounts": { + "items": { + "$ref": "#/$defs/VolumeMount" + }, + "type": "array" + } + }, + "required": [ + "Args", + "Command", + "Env", + "Image", + "Name", + "Resources", + "VolumeMounts" + ], + "type": "object" + }, + "ManagedServiceIdentity": { + "additionalProperties": false, + "properties": { + "PrincipalID": { + "type": "string" + }, + "TenantID": { + "type": "string" + }, + "Type": { + "type": "string" + }, + "UserAssignedIdentities": { + "patternProperties": { + ".*": { + "$ref": "#/$defs/UserAssignedIdentity" + } + }, + "type": "object" + } + }, + "required": [ + "Type", + "UserAssignedIdentities", + "PrincipalID", + "TenantID" + ], + "type": "object" + }, + "QueueScaleRule": { + "additionalProperties": false, + "properties": { + "Auth": { + "items": { + "$ref": "#/$defs/ScaleRuleAuth" + }, + "type": "array" + }, + "QueueLength": { + "type": "integer" + }, + "QueueName": { + "type": "string" + } + }, + "required": [ + "Auth", + "QueueLength", + "QueueName" + ], + "type": "object" + }, + "RegistryCredentials": { + "additionalProperties": false, + "properties": { + "Identity": { + "type": "string" + }, + "PasswordSecretRef": { + "type": "string" + }, + "Server": { + "type": "string" + }, + "Username": { + "type": "string" + } + }, + "required": [ + "Identity", + "PasswordSecretRef", + "Server", + "Username" + ], + "type": "object" + }, + "RemoteSecretSpecification": { + "additionalProperties": false, + "properties": { + "remoteSecretName": { + "type": "string" + }, + "secretName": { + "type": "string" + } + }, + "type": "object" + }, + "ReplacementsSpecification": { + "additionalProperties": false, + "properties": { + "images": { + "items": { + "$ref": "#/$defs/ImageReplacementSpecification" + }, + "type": "array" + } + }, + "type": "object" + }, + "Scale": { + "additionalProperties": false, + "properties": { + "MaxReplicas": { + "type": "integer" + }, + "MinReplicas": { + "type": "integer" + }, + "Rules": { + "items": { + "$ref": "#/$defs/ScaleRule" + }, + "type": "array" + } + }, + "required": [ + "MaxReplicas", + "MinReplicas", + "Rules" + ], + "type": "object" + }, + "ScaleRule": { + "additionalProperties": false, + "properties": { + "AzureQueue": { + "$ref": "#/$defs/QueueScaleRule" + }, + "Custom": { + "$ref": "#/$defs/CustomScaleRule" + }, + "HTTP": { + "$ref": "#/$defs/HTTPScaleRule" + }, + "Name": { + "type": "string" + }, + "TCP": { + "$ref": "#/$defs/TCPScaleRule" + } + }, + "required": [ + "AzureQueue", + "Custom", + "HTTP", + "Name", + "TCP" + ], + "type": "object" + }, + "ScaleRuleAuth": { + "additionalProperties": false, + "properties": { + "SecretRef": { + "type": "string" + }, + "TriggerParameter": { + "type": "string" + } + }, + "required": [ + "SecretRef", + "TriggerParameter" + ], + "type": "object" + }, + "Secret": { + "additionalProperties": false, + "properties": { + "Identity": { + "type": "string" + }, + "KeyVaultURL": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "Value": { + "type": "string" + } + }, + "required": [ + "Identity", + "KeyVaultURL", + "Name", + "Value" + ], + "type": "object" + }, + "SecretVolumeItem": { + "additionalProperties": false, + "properties": { + "Path": { + "type": "string" + }, + "SecretRef": { + "type": "string" + } + }, + "required": [ + "Path", + "SecretRef" + ], + "type": "object" + }, + "SourceApp": { + "additionalProperties": false, + "properties": { + "Err": true, + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "spec": { + "$ref": "#/$defs/SourceAppSpecification" + } + }, + "required": [ + "Err" + ], + "type": "object" + }, + "SourceAppSpecification": { + "additionalProperties": false, + "properties": { + "app": { + "$ref": "#/$defs/ContainerApp" + }, + "locationFilter": { + "items": { + "type": "string" + }, + "type": "array" + }, + "remoteSecrets": { + "items": { + "$ref": "#/$defs/RemoteSecretSpecification" + }, + "type": "array" + }, + "replacements": { + "$ref": "#/$defs/ReplacementsSpecification" + } + }, + "type": "object" + }, + "SystemData": { + "additionalProperties": false, + "properties": { + "CreatedAt": { + "format": "date-time", + "type": "string" + }, + "CreatedBy": { + "type": "string" + }, + "CreatedByType": { + "type": "string" + }, + "LastModifiedAt": { + "format": "date-time", + "type": "string" + }, + "LastModifiedBy": { + "type": "string" + }, + "LastModifiedByType": { + "type": "string" + } + }, + "required": [ + "CreatedAt", + "CreatedBy", + "CreatedByType", + "LastModifiedAt", + "LastModifiedBy", + "LastModifiedByType" + ], + "type": "object" + }, + "TCPScaleRule": { + "additionalProperties": false, + "properties": { + "Auth": { + "items": { + "$ref": "#/$defs/ScaleRuleAuth" + }, + "type": "array" + }, + "Metadata": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "required": [ + "Auth", + "Metadata" + ], + "type": "object" + }, + "Template": { + "additionalProperties": false, + "properties": { + "Containers": { + "items": { + "$ref": "#/$defs/Container" + }, + "type": "array" + }, + "InitContainers": { + "items": { + "$ref": "#/$defs/InitContainer" + }, + "type": "array" + }, + "RevisionSuffix": { + "type": "string" + }, + "Scale": { + "$ref": "#/$defs/Scale" + }, + "Volumes": { + "items": { + "$ref": "#/$defs/Volume" + }, + "type": "array" + } + }, + "required": [ + "Containers", + "InitContainers", + "RevisionSuffix", + "Scale", + "Volumes" + ], + "type": "object" + }, + "TrafficWeight": { + "additionalProperties": false, + "properties": { + "Label": { + "type": "string" + }, + "LatestRevision": { + "type": "boolean" + }, + "RevisionName": { + "type": "string" + }, + "Weight": { + "type": "integer" + } + }, + "required": [ + "Label", + "LatestRevision", + "RevisionName", + "Weight" + ], + "type": "object" + }, + "UserAssignedIdentity": { + "additionalProperties": false, + "properties": { + "ClientID": { + "type": "string" + }, + "PrincipalID": { + "type": "string" + } + }, + "required": [ + "ClientID", + "PrincipalID" + ], + "type": "object" + }, + "Volume": { + "additionalProperties": false, + "properties": { + "Name": { + "type": "string" + }, + "Secrets": { + "items": { + "$ref": "#/$defs/SecretVolumeItem" + }, + "type": "array" + }, + "StorageName": { + "type": "string" + }, + "StorageType": { + "type": "string" + } + }, + "required": [ + "Name", + "Secrets", + "StorageName", + "StorageType" + ], + "type": "object" + }, + "VolumeMount": { + "additionalProperties": false, + "properties": { + "MountPath": { + "type": "string" + }, + "VolumeName": { + "type": "string" + } + }, + "required": [ + "MountPath", + "VolumeName" + ], + "type": "object" + } + }, + "$ref": "#/$defs/SourceApp", + "$schema": "https://json-schema.org/draft/2020-12/schema" +} \ No newline at end of file diff --git a/schemas/app.yaml b/schemas/app.yaml new file mode 100644 index 0000000..397c1d4 --- /dev/null +++ b/schemas/app.yaml @@ -0,0 +1,791 @@ +$defs: + Configuration: + additionalProperties: false + properties: + ActiveRevisionsMode: + type: string + Dapr: + $ref: '#/$defs/Dapr' + Ingress: + $ref: '#/$defs/Ingress' + MaxInactiveRevisions: + type: integer + Registries: + items: + $ref: '#/$defs/RegistryCredentials' + type: array + Secrets: + items: + $ref: '#/$defs/Secret' + type: array + required: + - ActiveRevisionsMode + - Dapr + - Ingress + - MaxInactiveRevisions + - Registries + - Secrets + type: object + Container: + additionalProperties: false + properties: + Args: + items: + type: string + type: array + Command: + items: + type: string + type: array + Env: + items: + $ref: '#/$defs/EnvironmentVar' + type: array + Image: + type: string + Name: + type: string + Probes: + items: + $ref: '#/$defs/ContainerAppProbe' + type: array + Resources: + $ref: '#/$defs/ContainerResources' + VolumeMounts: + items: + $ref: '#/$defs/VolumeMount' + type: array + required: + - Args + - Command + - Env + - Image + - Name + - Probes + - Resources + - VolumeMounts + type: object + ContainerApp: + additionalProperties: false + properties: + ExtendedLocation: + $ref: '#/$defs/ExtendedLocation' + ID: + type: string + Identity: + $ref: '#/$defs/ManagedServiceIdentity' + Location: + type: string + ManagedBy: + type: string + Name: + type: string + Properties: + $ref: '#/$defs/ContainerAppProperties' + SystemData: + $ref: '#/$defs/SystemData' + Tags: + patternProperties: + .*: + type: string + type: object + Type: + type: string + required: + - Location + - ExtendedLocation + - Identity + - ManagedBy + - Properties + - Tags + - ID + - Name + - SystemData + - Type + type: object + ContainerAppProbe: + additionalProperties: false + properties: + FailureThreshold: + type: integer + HTTPGet: + $ref: '#/$defs/ContainerAppProbeHTTPGet' + InitialDelaySeconds: + type: integer + PeriodSeconds: + type: integer + SuccessThreshold: + type: integer + TCPSocket: + $ref: '#/$defs/ContainerAppProbeTCPSocket' + TerminationGracePeriodSeconds: + type: integer + TimeoutSeconds: + type: integer + Type: + type: string + required: + - FailureThreshold + - HTTPGet + - InitialDelaySeconds + - PeriodSeconds + - SuccessThreshold + - TCPSocket + - TerminationGracePeriodSeconds + - TimeoutSeconds + - Type + type: object + ContainerAppProbeHTTPGet: + additionalProperties: false + properties: + HTTPHeaders: + items: + $ref: '#/$defs/ContainerAppProbeHTTPGetHTTPHeadersItem' + type: array + Host: + type: string + Path: + type: string + Port: + type: integer + Scheme: + type: string + required: + - Port + - HTTPHeaders + - Host + - Path + - Scheme + type: object + ContainerAppProbeHTTPGetHTTPHeadersItem: + additionalProperties: false + properties: + Name: + type: string + Value: + type: string + required: + - Name + - Value + type: object + ContainerAppProbeTCPSocket: + additionalProperties: false + properties: + Host: + type: string + Port: + type: integer + required: + - Port + - Host + type: object + ContainerAppProperties: + additionalProperties: false + properties: + Configuration: + $ref: '#/$defs/Configuration' + CustomDomainVerificationID: + type: string + EnvironmentID: + type: string + EventStreamEndpoint: + type: string + LatestReadyRevisionName: + type: string + LatestRevisionFqdn: + type: string + LatestRevisionName: + type: string + ManagedEnvironmentID: + type: string + OutboundIPAddresses: + items: + type: string + type: array + ProvisioningState: + type: string + Template: + $ref: '#/$defs/Template' + WorkloadProfileName: + type: string + required: + - Configuration + - EnvironmentID + - ManagedEnvironmentID + - Template + - WorkloadProfileName + - CustomDomainVerificationID + - EventStreamEndpoint + - LatestReadyRevisionName + - LatestRevisionFqdn + - LatestRevisionName + - OutboundIPAddresses + - ProvisioningState + type: object + ContainerResources: + additionalProperties: false + properties: + CPU: + type: number + EphemeralStorage: + type: string + Memory: + type: string + required: + - CPU + - Memory + - EphemeralStorage + type: object + CorsPolicy: + additionalProperties: false + properties: + AllowCredentials: + type: boolean + AllowedHeaders: + items: + type: string + type: array + AllowedMethods: + items: + type: string + type: array + AllowedOrigins: + items: + type: string + type: array + ExposeHeaders: + items: + type: string + type: array + MaxAge: + type: integer + required: + - AllowedOrigins + - AllowCredentials + - AllowedHeaders + - AllowedMethods + - ExposeHeaders + - MaxAge + type: object + CustomDomain: + additionalProperties: false + properties: + BindingType: + type: string + CertificateID: + type: string + Name: + type: string + required: + - Name + - BindingType + - CertificateID + type: object + CustomScaleRule: + additionalProperties: false + properties: + Auth: + items: + $ref: '#/$defs/ScaleRuleAuth' + type: array + Metadata: + patternProperties: + .*: + type: string + type: object + Type: + type: string + required: + - Auth + - Metadata + - Type + type: object + Dapr: + additionalProperties: false + properties: + AppID: + type: string + AppPort: + type: integer + AppProtocol: + type: string + EnableAPILogging: + type: boolean + Enabled: + type: boolean + HTTPMaxRequestSize: + type: integer + HTTPReadBufferSize: + type: integer + LogLevel: + type: string + required: + - AppID + - AppPort + - AppProtocol + - EnableAPILogging + - Enabled + - HTTPMaxRequestSize + - HTTPReadBufferSize + - LogLevel + type: object + EnvironmentVar: + additionalProperties: false + properties: + Name: + type: string + SecretRef: + type: string + Value: + type: string + required: + - Name + - SecretRef + - Value + type: object + ExtendedLocation: + additionalProperties: false + properties: + Name: + type: string + Type: + type: string + required: + - Name + - Type + type: object + HTTPScaleRule: + additionalProperties: false + properties: + Auth: + items: + $ref: '#/$defs/ScaleRuleAuth' + type: array + Metadata: + patternProperties: + .*: + type: string + type: object + required: + - Auth + - Metadata + type: object + IPSecurityRestrictionRule: + additionalProperties: false + properties: + Action: + type: string + Description: + type: string + IPAddressRange: + type: string + Name: + type: string + required: + - Action + - IPAddressRange + - Name + - Description + type: object + ImageReplacementSpecification: + additionalProperties: false + properties: + imageName: + type: string + newImageTag: + type: string + type: object + Ingress: + additionalProperties: false + properties: + AllowInsecure: + type: boolean + ClientCertificateMode: + type: string + CorsPolicy: + $ref: '#/$defs/CorsPolicy' + CustomDomains: + items: + $ref: '#/$defs/CustomDomain' + type: array + ExposedPort: + type: integer + External: + type: boolean + Fqdn: + type: string + IPSecurityRestrictions: + items: + $ref: '#/$defs/IPSecurityRestrictionRule' + type: array + StickySessions: + $ref: '#/$defs/IngressStickySessions' + TargetPort: + type: integer + Traffic: + items: + $ref: '#/$defs/TrafficWeight' + type: array + Transport: + type: string + required: + - AllowInsecure + - ClientCertificateMode + - CorsPolicy + - CustomDomains + - ExposedPort + - External + - IPSecurityRestrictions + - StickySessions + - TargetPort + - Traffic + - Transport + - Fqdn + type: object + IngressStickySessions: + additionalProperties: false + properties: + Affinity: + type: string + required: + - Affinity + type: object + InitContainer: + additionalProperties: false + properties: + Args: + items: + type: string + type: array + Command: + items: + type: string + type: array + Env: + items: + $ref: '#/$defs/EnvironmentVar' + type: array + Image: + type: string + Name: + type: string + Resources: + $ref: '#/$defs/ContainerResources' + VolumeMounts: + items: + $ref: '#/$defs/VolumeMount' + type: array + required: + - Args + - Command + - Env + - Image + - Name + - Resources + - VolumeMounts + type: object + ManagedServiceIdentity: + additionalProperties: false + properties: + PrincipalID: + type: string + TenantID: + type: string + Type: + type: string + UserAssignedIdentities: + patternProperties: + .*: + $ref: '#/$defs/UserAssignedIdentity' + type: object + required: + - Type + - UserAssignedIdentities + - PrincipalID + - TenantID + type: object + QueueScaleRule: + additionalProperties: false + properties: + Auth: + items: + $ref: '#/$defs/ScaleRuleAuth' + type: array + QueueLength: + type: integer + QueueName: + type: string + required: + - Auth + - QueueLength + - QueueName + type: object + RegistryCredentials: + additionalProperties: false + properties: + Identity: + type: string + PasswordSecretRef: + type: string + Server: + type: string + Username: + type: string + required: + - Identity + - PasswordSecretRef + - Server + - Username + type: object + RemoteSecretSpecification: + additionalProperties: false + properties: + remoteSecretName: + type: string + secretName: + type: string + type: object + ReplacementsSpecification: + additionalProperties: false + properties: + images: + items: + $ref: '#/$defs/ImageReplacementSpecification' + type: array + type: object + Scale: + additionalProperties: false + properties: + MaxReplicas: + type: integer + MinReplicas: + type: integer + Rules: + items: + $ref: '#/$defs/ScaleRule' + type: array + required: + - MaxReplicas + - MinReplicas + - Rules + type: object + ScaleRule: + additionalProperties: false + properties: + AzureQueue: + $ref: '#/$defs/QueueScaleRule' + Custom: + $ref: '#/$defs/CustomScaleRule' + HTTP: + $ref: '#/$defs/HTTPScaleRule' + Name: + type: string + TCP: + $ref: '#/$defs/TCPScaleRule' + required: + - AzureQueue + - Custom + - HTTP + - Name + - TCP + type: object + ScaleRuleAuth: + additionalProperties: false + properties: + SecretRef: + type: string + TriggerParameter: + type: string + required: + - SecretRef + - TriggerParameter + type: object + Secret: + additionalProperties: false + properties: + Identity: + type: string + KeyVaultURL: + type: string + Name: + type: string + Value: + type: string + required: + - Identity + - KeyVaultURL + - Name + - Value + type: object + SecretVolumeItem: + additionalProperties: false + properties: + Path: + type: string + SecretRef: + type: string + required: + - Path + - SecretRef + type: object + SourceApp: + additionalProperties: false + properties: + Err: true + apiVersion: + type: string + kind: + type: string + metadata: + patternProperties: + .*: + type: string + type: object + spec: + $ref: '#/$defs/SourceAppSpecification' + required: + - Err + type: object + SourceAppSpecification: + additionalProperties: false + properties: + app: + $ref: '#/$defs/ContainerApp' + locationFilter: + items: + type: string + type: array + remoteSecrets: + items: + $ref: '#/$defs/RemoteSecretSpecification' + type: array + replacements: + $ref: '#/$defs/ReplacementsSpecification' + type: object + SystemData: + additionalProperties: false + properties: + CreatedAt: + format: date-time + type: string + CreatedBy: + type: string + CreatedByType: + type: string + LastModifiedAt: + format: date-time + type: string + LastModifiedBy: + type: string + LastModifiedByType: + type: string + required: + - CreatedAt + - CreatedBy + - CreatedByType + - LastModifiedAt + - LastModifiedBy + - LastModifiedByType + type: object + TCPScaleRule: + additionalProperties: false + properties: + Auth: + items: + $ref: '#/$defs/ScaleRuleAuth' + type: array + Metadata: + patternProperties: + .*: + type: string + type: object + required: + - Auth + - Metadata + type: object + Template: + additionalProperties: false + properties: + Containers: + items: + $ref: '#/$defs/Container' + type: array + InitContainers: + items: + $ref: '#/$defs/InitContainer' + type: array + RevisionSuffix: + type: string + Scale: + $ref: '#/$defs/Scale' + Volumes: + items: + $ref: '#/$defs/Volume' + type: array + required: + - Containers + - InitContainers + - RevisionSuffix + - Scale + - Volumes + type: object + TrafficWeight: + additionalProperties: false + properties: + Label: + type: string + LatestRevision: + type: boolean + RevisionName: + type: string + Weight: + type: integer + required: + - Label + - LatestRevision + - RevisionName + - Weight + type: object + UserAssignedIdentity: + additionalProperties: false + properties: + ClientID: + type: string + PrincipalID: + type: string + required: + - ClientID + - PrincipalID + type: object + Volume: + additionalProperties: false + properties: + Name: + type: string + Secrets: + items: + $ref: '#/$defs/SecretVolumeItem' + type: array + StorageName: + type: string + StorageType: + type: string + required: + - Name + - Secrets + - StorageName + - StorageType + type: object + VolumeMount: + additionalProperties: false + properties: + MountPath: + type: string + VolumeName: + type: string + required: + - MountPath + - VolumeName + type: object +$ref: '#/$defs/SourceApp' +$schema: https://json-schema.org/draft/2020-12/schema diff --git a/schemas/job.json b/schemas/job.json new file mode 100644 index 0000000..e6c5bd8 --- /dev/null +++ b/schemas/job.json @@ -0,0 +1,720 @@ +{ + "$defs": { + "Container": { + "additionalProperties": false, + "properties": { + "Args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Env": { + "items": { + "$ref": "#/$defs/EnvironmentVar" + }, + "type": "array" + }, + "Image": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "Probes": { + "items": { + "$ref": "#/$defs/ContainerAppProbe" + }, + "type": "array" + }, + "Resources": { + "$ref": "#/$defs/ContainerResources" + }, + "VolumeMounts": { + "items": { + "$ref": "#/$defs/VolumeMount" + }, + "type": "array" + } + }, + "required": [ + "Args", + "Command", + "Env", + "Image", + "Name", + "Probes", + "Resources", + "VolumeMounts" + ], + "type": "object" + }, + "ContainerAppProbe": { + "additionalProperties": false, + "properties": { + "FailureThreshold": { + "type": "integer" + }, + "HTTPGet": { + "$ref": "#/$defs/ContainerAppProbeHTTPGet" + }, + "InitialDelaySeconds": { + "type": "integer" + }, + "PeriodSeconds": { + "type": "integer" + }, + "SuccessThreshold": { + "type": "integer" + }, + "TCPSocket": { + "$ref": "#/$defs/ContainerAppProbeTCPSocket" + }, + "TerminationGracePeriodSeconds": { + "type": "integer" + }, + "TimeoutSeconds": { + "type": "integer" + }, + "Type": { + "type": "string" + } + }, + "required": [ + "FailureThreshold", + "HTTPGet", + "InitialDelaySeconds", + "PeriodSeconds", + "SuccessThreshold", + "TCPSocket", + "TerminationGracePeriodSeconds", + "TimeoutSeconds", + "Type" + ], + "type": "object" + }, + "ContainerAppProbeHTTPGet": { + "additionalProperties": false, + "properties": { + "HTTPHeaders": { + "items": { + "$ref": "#/$defs/ContainerAppProbeHTTPGetHTTPHeadersItem" + }, + "type": "array" + }, + "Host": { + "type": "string" + }, + "Path": { + "type": "string" + }, + "Port": { + "type": "integer" + }, + "Scheme": { + "type": "string" + } + }, + "required": [ + "Port", + "HTTPHeaders", + "Host", + "Path", + "Scheme" + ], + "type": "object" + }, + "ContainerAppProbeHTTPGetHTTPHeadersItem": { + "additionalProperties": false, + "properties": { + "Name": { + "type": "string" + }, + "Value": { + "type": "string" + } + }, + "required": [ + "Name", + "Value" + ], + "type": "object" + }, + "ContainerAppProbeTCPSocket": { + "additionalProperties": false, + "properties": { + "Host": { + "type": "string" + }, + "Port": { + "type": "integer" + } + }, + "required": [ + "Port", + "Host" + ], + "type": "object" + }, + "ContainerResources": { + "additionalProperties": false, + "properties": { + "CPU": { + "type": "number" + }, + "EphemeralStorage": { + "type": "string" + }, + "Memory": { + "type": "string" + } + }, + "required": [ + "CPU", + "Memory", + "EphemeralStorage" + ], + "type": "object" + }, + "EnvironmentVar": { + "additionalProperties": false, + "properties": { + "Name": { + "type": "string" + }, + "SecretRef": { + "type": "string" + }, + "Value": { + "type": "string" + } + }, + "required": [ + "Name", + "SecretRef", + "Value" + ], + "type": "object" + }, + "ImageReplacementSpecification": { + "additionalProperties": false, + "properties": { + "imageName": { + "type": "string" + }, + "newImageTag": { + "type": "string" + } + }, + "type": "object" + }, + "InitContainer": { + "additionalProperties": false, + "properties": { + "Args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Env": { + "items": { + "$ref": "#/$defs/EnvironmentVar" + }, + "type": "array" + }, + "Image": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "Resources": { + "$ref": "#/$defs/ContainerResources" + }, + "VolumeMounts": { + "items": { + "$ref": "#/$defs/VolumeMount" + }, + "type": "array" + } + }, + "required": [ + "Args", + "Command", + "Env", + "Image", + "Name", + "Resources", + "VolumeMounts" + ], + "type": "object" + }, + "Job": { + "additionalProperties": false, + "properties": { + "ID": { + "type": "string" + }, + "Identity": { + "$ref": "#/$defs/ManagedServiceIdentity" + }, + "Location": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "Properties": { + "$ref": "#/$defs/JobProperties" + }, + "SystemData": { + "$ref": "#/$defs/SystemData" + }, + "Tags": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "Type": { + "type": "string" + } + }, + "required": [ + "Location", + "Identity", + "Properties", + "Tags", + "ID", + "Name", + "SystemData", + "Type" + ], + "type": "object" + }, + "JobConfiguration": { + "additionalProperties": false, + "properties": { + "ManualTriggerConfig": { + "$ref": "#/$defs/JobConfigurationManualTriggerConfig" + }, + "Registries": { + "items": { + "$ref": "#/$defs/RegistryCredentials" + }, + "type": "array" + }, + "ReplicaRetryLimit": { + "type": "integer" + }, + "ReplicaTimeout": { + "type": "integer" + }, + "ScheduleTriggerConfig": { + "$ref": "#/$defs/JobConfigurationScheduleTriggerConfig" + }, + "Secrets": { + "items": { + "$ref": "#/$defs/Secret" + }, + "type": "array" + }, + "TriggerType": { + "type": "string" + } + }, + "required": [ + "ReplicaTimeout", + "TriggerType", + "ManualTriggerConfig", + "Registries", + "ReplicaRetryLimit", + "ScheduleTriggerConfig", + "Secrets" + ], + "type": "object" + }, + "JobConfigurationManualTriggerConfig": { + "additionalProperties": false, + "properties": { + "Parallelism": { + "type": "integer" + }, + "ReplicaCompletionCount": { + "type": "integer" + } + }, + "required": [ + "Parallelism", + "ReplicaCompletionCount" + ], + "type": "object" + }, + "JobConfigurationScheduleTriggerConfig": { + "additionalProperties": false, + "properties": { + "CronExpression": { + "type": "string" + }, + "Parallelism": { + "type": "integer" + }, + "ReplicaCompletionCount": { + "type": "integer" + } + }, + "required": [ + "CronExpression", + "Parallelism", + "ReplicaCompletionCount" + ], + "type": "object" + }, + "JobProperties": { + "additionalProperties": false, + "properties": { + "Configuration": { + "$ref": "#/$defs/JobConfiguration" + }, + "EnvironmentID": { + "type": "string" + }, + "EventStreamEndpoint": { + "type": "string" + }, + "OutboundIPAddresses": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ProvisioningState": { + "type": "string" + }, + "Template": { + "$ref": "#/$defs/JobTemplate" + }, + "WorkloadProfileName": { + "type": "string" + } + }, + "required": [ + "Configuration", + "EnvironmentID", + "Template", + "WorkloadProfileName", + "EventStreamEndpoint", + "OutboundIPAddresses", + "ProvisioningState" + ], + "type": "object" + }, + "JobTemplate": { + "additionalProperties": false, + "properties": { + "Containers": { + "items": { + "$ref": "#/$defs/Container" + }, + "type": "array" + }, + "InitContainers": { + "items": { + "$ref": "#/$defs/InitContainer" + }, + "type": "array" + }, + "Volumes": { + "items": { + "$ref": "#/$defs/Volume" + }, + "type": "array" + } + }, + "required": [ + "Containers", + "InitContainers", + "Volumes" + ], + "type": "object" + }, + "ManagedServiceIdentity": { + "additionalProperties": false, + "properties": { + "PrincipalID": { + "type": "string" + }, + "TenantID": { + "type": "string" + }, + "Type": { + "type": "string" + }, + "UserAssignedIdentities": { + "patternProperties": { + ".*": { + "$ref": "#/$defs/UserAssignedIdentity" + } + }, + "type": "object" + } + }, + "required": [ + "Type", + "UserAssignedIdentities", + "PrincipalID", + "TenantID" + ], + "type": "object" + }, + "RegistryCredentials": { + "additionalProperties": false, + "properties": { + "Identity": { + "type": "string" + }, + "PasswordSecretRef": { + "type": "string" + }, + "Server": { + "type": "string" + }, + "Username": { + "type": "string" + } + }, + "required": [ + "Identity", + "PasswordSecretRef", + "Server", + "Username" + ], + "type": "object" + }, + "RemoteSecretSpecification": { + "additionalProperties": false, + "properties": { + "remoteSecretName": { + "type": "string" + }, + "secretName": { + "type": "string" + } + }, + "type": "object" + }, + "ReplacementsSpecification": { + "additionalProperties": false, + "properties": { + "images": { + "items": { + "$ref": "#/$defs/ImageReplacementSpecification" + }, + "type": "array" + } + }, + "type": "object" + }, + "Secret": { + "additionalProperties": false, + "properties": { + "Identity": { + "type": "string" + }, + "KeyVaultURL": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "Value": { + "type": "string" + } + }, + "required": [ + "Identity", + "KeyVaultURL", + "Name", + "Value" + ], + "type": "object" + }, + "SecretVolumeItem": { + "additionalProperties": false, + "properties": { + "Path": { + "type": "string" + }, + "SecretRef": { + "type": "string" + } + }, + "required": [ + "Path", + "SecretRef" + ], + "type": "object" + }, + "SourceJob": { + "additionalProperties": false, + "properties": { + "Err": true, + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "spec": { + "$ref": "#/$defs/SourceJobSpecification" + } + }, + "required": [ + "Err" + ], + "type": "object" + }, + "SourceJobSpecification": { + "additionalProperties": false, + "properties": { + "job": { + "$ref": "#/$defs/Job" + }, + "locationFilter": { + "items": { + "type": "string" + }, + "type": "array" + }, + "remoteSecrets": { + "items": { + "$ref": "#/$defs/RemoteSecretSpecification" + }, + "type": "array" + }, + "replacements": { + "$ref": "#/$defs/ReplacementsSpecification" + } + }, + "type": "object" + }, + "SystemData": { + "additionalProperties": false, + "properties": { + "CreatedAt": { + "format": "date-time", + "type": "string" + }, + "CreatedBy": { + "type": "string" + }, + "CreatedByType": { + "type": "string" + }, + "LastModifiedAt": { + "format": "date-time", + "type": "string" + }, + "LastModifiedBy": { + "type": "string" + }, + "LastModifiedByType": { + "type": "string" + } + }, + "required": [ + "CreatedAt", + "CreatedBy", + "CreatedByType", + "LastModifiedAt", + "LastModifiedBy", + "LastModifiedByType" + ], + "type": "object" + }, + "UserAssignedIdentity": { + "additionalProperties": false, + "properties": { + "ClientID": { + "type": "string" + }, + "PrincipalID": { + "type": "string" + } + }, + "required": [ + "ClientID", + "PrincipalID" + ], + "type": "object" + }, + "Volume": { + "additionalProperties": false, + "properties": { + "Name": { + "type": "string" + }, + "Secrets": { + "items": { + "$ref": "#/$defs/SecretVolumeItem" + }, + "type": "array" + }, + "StorageName": { + "type": "string" + }, + "StorageType": { + "type": "string" + } + }, + "required": [ + "Name", + "Secrets", + "StorageName", + "StorageType" + ], + "type": "object" + }, + "VolumeMount": { + "additionalProperties": false, + "properties": { + "MountPath": { + "type": "string" + }, + "VolumeName": { + "type": "string" + } + }, + "required": [ + "MountPath", + "VolumeName" + ], + "type": "object" + } + }, + "$ref": "#/$defs/SourceJob", + "$schema": "https://json-schema.org/draft/2020-12/schema" +} \ No newline at end of file diff --git a/schemas/job.yaml b/schemas/job.yaml new file mode 100644 index 0000000..97a0d4e --- /dev/null +++ b/schemas/job.yaml @@ -0,0 +1,504 @@ +$defs: + Container: + additionalProperties: false + properties: + Args: + items: + type: string + type: array + Command: + items: + type: string + type: array + Env: + items: + $ref: '#/$defs/EnvironmentVar' + type: array + Image: + type: string + Name: + type: string + Probes: + items: + $ref: '#/$defs/ContainerAppProbe' + type: array + Resources: + $ref: '#/$defs/ContainerResources' + VolumeMounts: + items: + $ref: '#/$defs/VolumeMount' + type: array + required: + - Args + - Command + - Env + - Image + - Name + - Probes + - Resources + - VolumeMounts + type: object + ContainerAppProbe: + additionalProperties: false + properties: + FailureThreshold: + type: integer + HTTPGet: + $ref: '#/$defs/ContainerAppProbeHTTPGet' + InitialDelaySeconds: + type: integer + PeriodSeconds: + type: integer + SuccessThreshold: + type: integer + TCPSocket: + $ref: '#/$defs/ContainerAppProbeTCPSocket' + TerminationGracePeriodSeconds: + type: integer + TimeoutSeconds: + type: integer + Type: + type: string + required: + - FailureThreshold + - HTTPGet + - InitialDelaySeconds + - PeriodSeconds + - SuccessThreshold + - TCPSocket + - TerminationGracePeriodSeconds + - TimeoutSeconds + - Type + type: object + ContainerAppProbeHTTPGet: + additionalProperties: false + properties: + HTTPHeaders: + items: + $ref: '#/$defs/ContainerAppProbeHTTPGetHTTPHeadersItem' + type: array + Host: + type: string + Path: + type: string + Port: + type: integer + Scheme: + type: string + required: + - Port + - HTTPHeaders + - Host + - Path + - Scheme + type: object + ContainerAppProbeHTTPGetHTTPHeadersItem: + additionalProperties: false + properties: + Name: + type: string + Value: + type: string + required: + - Name + - Value + type: object + ContainerAppProbeTCPSocket: + additionalProperties: false + properties: + Host: + type: string + Port: + type: integer + required: + - Port + - Host + type: object + ContainerResources: + additionalProperties: false + properties: + CPU: + type: number + EphemeralStorage: + type: string + Memory: + type: string + required: + - CPU + - Memory + - EphemeralStorage + type: object + EnvironmentVar: + additionalProperties: false + properties: + Name: + type: string + SecretRef: + type: string + Value: + type: string + required: + - Name + - SecretRef + - Value + type: object + ImageReplacementSpecification: + additionalProperties: false + properties: + imageName: + type: string + newImageTag: + type: string + type: object + InitContainer: + additionalProperties: false + properties: + Args: + items: + type: string + type: array + Command: + items: + type: string + type: array + Env: + items: + $ref: '#/$defs/EnvironmentVar' + type: array + Image: + type: string + Name: + type: string + Resources: + $ref: '#/$defs/ContainerResources' + VolumeMounts: + items: + $ref: '#/$defs/VolumeMount' + type: array + required: + - Args + - Command + - Env + - Image + - Name + - Resources + - VolumeMounts + type: object + Job: + additionalProperties: false + properties: + ID: + type: string + Identity: + $ref: '#/$defs/ManagedServiceIdentity' + Location: + type: string + Name: + type: string + Properties: + $ref: '#/$defs/JobProperties' + SystemData: + $ref: '#/$defs/SystemData' + Tags: + patternProperties: + .*: + type: string + type: object + Type: + type: string + required: + - Location + - Identity + - Properties + - Tags + - ID + - Name + - SystemData + - Type + type: object + JobConfiguration: + additionalProperties: false + properties: + ManualTriggerConfig: + $ref: '#/$defs/JobConfigurationManualTriggerConfig' + Registries: + items: + $ref: '#/$defs/RegistryCredentials' + type: array + ReplicaRetryLimit: + type: integer + ReplicaTimeout: + type: integer + ScheduleTriggerConfig: + $ref: '#/$defs/JobConfigurationScheduleTriggerConfig' + Secrets: + items: + $ref: '#/$defs/Secret' + type: array + TriggerType: + type: string + required: + - ReplicaTimeout + - TriggerType + - ManualTriggerConfig + - Registries + - ReplicaRetryLimit + - ScheduleTriggerConfig + - Secrets + type: object + JobConfigurationManualTriggerConfig: + additionalProperties: false + properties: + Parallelism: + type: integer + ReplicaCompletionCount: + type: integer + required: + - Parallelism + - ReplicaCompletionCount + type: object + JobConfigurationScheduleTriggerConfig: + additionalProperties: false + properties: + CronExpression: + type: string + Parallelism: + type: integer + ReplicaCompletionCount: + type: integer + required: + - CronExpression + - Parallelism + - ReplicaCompletionCount + type: object + JobProperties: + additionalProperties: false + properties: + Configuration: + $ref: '#/$defs/JobConfiguration' + EnvironmentID: + type: string + EventStreamEndpoint: + type: string + OutboundIPAddresses: + items: + type: string + type: array + ProvisioningState: + type: string + Template: + $ref: '#/$defs/JobTemplate' + WorkloadProfileName: + type: string + required: + - Configuration + - EnvironmentID + - Template + - WorkloadProfileName + - EventStreamEndpoint + - OutboundIPAddresses + - ProvisioningState + type: object + JobTemplate: + additionalProperties: false + properties: + Containers: + items: + $ref: '#/$defs/Container' + type: array + InitContainers: + items: + $ref: '#/$defs/InitContainer' + type: array + Volumes: + items: + $ref: '#/$defs/Volume' + type: array + required: + - Containers + - InitContainers + - Volumes + type: object + ManagedServiceIdentity: + additionalProperties: false + properties: + PrincipalID: + type: string + TenantID: + type: string + Type: + type: string + UserAssignedIdentities: + patternProperties: + .*: + $ref: '#/$defs/UserAssignedIdentity' + type: object + required: + - Type + - UserAssignedIdentities + - PrincipalID + - TenantID + type: object + RegistryCredentials: + additionalProperties: false + properties: + Identity: + type: string + PasswordSecretRef: + type: string + Server: + type: string + Username: + type: string + required: + - Identity + - PasswordSecretRef + - Server + - Username + type: object + RemoteSecretSpecification: + additionalProperties: false + properties: + remoteSecretName: + type: string + secretName: + type: string + type: object + ReplacementsSpecification: + additionalProperties: false + properties: + images: + items: + $ref: '#/$defs/ImageReplacementSpecification' + type: array + type: object + Secret: + additionalProperties: false + properties: + Identity: + type: string + KeyVaultURL: + type: string + Name: + type: string + Value: + type: string + required: + - Identity + - KeyVaultURL + - Name + - Value + type: object + SecretVolumeItem: + additionalProperties: false + properties: + Path: + type: string + SecretRef: + type: string + required: + - Path + - SecretRef + type: object + SourceJob: + additionalProperties: false + properties: + Err: true + apiVersion: + type: string + kind: + type: string + metadata: + patternProperties: + .*: + type: string + type: object + spec: + $ref: '#/$defs/SourceJobSpecification' + required: + - Err + type: object + SourceJobSpecification: + additionalProperties: false + properties: + job: + $ref: '#/$defs/Job' + locationFilter: + items: + type: string + type: array + remoteSecrets: + items: + $ref: '#/$defs/RemoteSecretSpecification' + type: array + replacements: + $ref: '#/$defs/ReplacementsSpecification' + type: object + SystemData: + additionalProperties: false + properties: + CreatedAt: + format: date-time + type: string + CreatedBy: + type: string + CreatedByType: + type: string + LastModifiedAt: + format: date-time + type: string + LastModifiedBy: + type: string + LastModifiedByType: + type: string + required: + - CreatedAt + - CreatedBy + - CreatedByType + - LastModifiedAt + - LastModifiedBy + - LastModifiedByType + type: object + UserAssignedIdentity: + additionalProperties: false + properties: + ClientID: + type: string + PrincipalID: + type: string + required: + - ClientID + - PrincipalID + type: object + Volume: + additionalProperties: false + properties: + Name: + type: string + Secrets: + items: + $ref: '#/$defs/SecretVolumeItem' + type: array + StorageName: + type: string + StorageType: + type: string + required: + - Name + - Secrets + - StorageName + - StorageType + type: object + VolumeMount: + additionalProperties: false + properties: + MountPath: + type: string + VolumeName: + type: string + required: + - MountPath + - VolumeName + type: object +$ref: '#/$defs/SourceJob' +$schema: https://json-schema.org/draft/2020-12/schema