From 05ed1bf12f47603acc32820db00be079bae28933 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Fri, 5 May 2023 16:56:21 +0200 Subject: [PATCH 1/6] Add blueprint metadata validation tool --- .github/workflows/linting.yml | 5 + .../data-solutions/vertex-mlops/metadata.yaml | 2 +- tools/bpmetadataschema.json | 966 ++++++++++++++++++ tools/validate_metadata.py | 93 ++ 4 files changed, 1065 insertions(+), 1 deletion(-) create mode 100644 tools/bpmetadataschema.json create mode 100755 tools/validate_metadata.py diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 1af27ea98..025c17117 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -75,3 +75,8 @@ jobs: tools/*.py \ blueprints/cloud-operations/network-dashboard/src/*py \ blueprints/cloud-operations/network-dashboard/src/plugins/*py + + - name: Check blueprint metadata + id: metadata + run: | + pythontools/validate_metadata.py -v blueprints diff --git a/blueprints/data-solutions/vertex-mlops/metadata.yaml b/blueprints/data-solutions/vertex-mlops/metadata.yaml index c85c8995b..d09c24473 100644 --- a/blueprints/data-solutions/vertex-mlops/metadata.yaml +++ b/blueprints/data-solutions/vertex-mlops/metadata.yaml @@ -129,7 +129,7 @@ spec: type: string default: null required: false - - name: service_encryption_keys + - name: service_encryption_keys description: Cloud KMS to use to encrypt different services. Key location should match service region. type: |- object({ diff --git a/tools/bpmetadataschema.json b/tools/bpmetadataschema.json new file mode 100644 index 000000000..42ae0d3a4 --- /dev/null +++ b/tools/bpmetadataschema.json @@ -0,0 +1,966 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/GoogleCloudPlatform/cloud-foundation-toolkit/cli/bpmetadata/blueprint-metadata", + "$ref": "#/$defs/BlueprintMetadata", + "$defs": { + "BlueprintActuationTool": { + "properties": { + "type": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object" + }, + "BlueprintArchitecture": { + "properties": { + "diagram": { + "type": "string" + }, + "description": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "diagram", + "description" + ] + }, + "BlueprintAuthor": { + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "title" + ] + }, + "BlueprintCloudProduct": { + "properties": { + "productId": { + "type": "string" + }, + "pageUrl": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "pageUrl" + ] + }, + "BlueprintContent": { + "properties": { + "architecture": { + "$ref": "#/$defs/BlueprintArchitecture" + }, + "diagrams": { + "items": { + "$ref": "#/$defs/BlueprintDiagram" + }, + "type": "array" + }, + "documentation": { + "items": { + "$ref": "#/$defs/BlueprintListContent" + }, + "type": "array" + }, + "subBlueprints": { + "items": { + "$ref": "#/$defs/BlueprintMiscContent" + }, + "type": "array" + }, + "examples": { + "items": { + "$ref": "#/$defs/BlueprintMiscContent" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object" + }, + "BlueprintCostEstimate": { + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "description", + "url" + ] + }, + "BlueprintDescription": { + "properties": { + "tagline": { + "type": "string" + }, + "detailed": { + "type": "string" + }, + "preDeploy": { + "type": "string" + }, + "html": { + "type": "string" + }, + "eulaUrls": { + "items": { + "type": "string" + }, + "type": "array" + }, + "architecture": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object" + }, + "BlueprintDiagram": { + "properties": { + "name": { + "type": "string" + }, + "altText": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ] + }, + "BlueprintInfo": { + "properties": { + "title": { + "type": "string" + }, + "source": { + "$ref": "#/$defs/BlueprintRepoDetail" + }, + "version": { + "type": "string" + }, + "actuationTool": { + "$ref": "#/$defs/BlueprintActuationTool" + }, + "description": { + "$ref": "#/$defs/BlueprintDescription" + }, + "icon": { + "type": "string" + }, + "deploymentDuration": { + "$ref": "#/$defs/BlueprintTimeEstimate" + }, + "costEstimate": { + "$ref": "#/$defs/BlueprintCostEstimate" + }, + "cloudProducts": { + "items": { + "$ref": "#/$defs/BlueprintCloudProduct" + }, + "type": "array" + }, + "quotaDetails": { + "items": { + "$ref": "#/$defs/BlueprintQuotaDetail" + }, + "type": "array" + }, + "author": { + "$ref": "#/$defs/BlueprintAuthor" + }, + "softwareGroups": { + "items": { + "$ref": "#/$defs/BlueprintSoftwareGroup" + }, + "type": "array" + }, + "supportInfo": { + "$ref": "#/$defs/BlueprintSupport" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "title", + "source" + ] + }, + "BlueprintInterface": { + "properties": { + "variables": { + "items": { + "$ref": "#/$defs/BlueprintVariable" + }, + "type": "array" + }, + "variableGroups": { + "items": { + "$ref": "#/$defs/BlueprintVariableGroup" + }, + "type": "array" + }, + "outputs": { + "items": { + "$ref": "#/$defs/BlueprintOutput" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object" + }, + "BlueprintListContent": { + "properties": { + "title": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "title" + ] + }, + "BlueprintMetadata": { + "properties": { + "apiVersion": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/ObjectMeta" + }, + "spec": { + "$ref": "#/$defs/BlueprintMetadataSpec" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "spec" + ] + }, + "BlueprintMetadataSpec": { + "properties": { + "info": { + "$ref": "#/$defs/BlueprintInfo" + }, + "content": { + "$ref": "#/$defs/BlueprintContent" + }, + "interfaces": { + "$ref": "#/$defs/BlueprintInterface" + }, + "requirements": { + "$ref": "#/$defs/BlueprintRequirements" + }, + "ui": { + "$ref": "#/$defs/BlueprintUI" + } + }, + "additionalProperties": false, + "type": "object" + }, + "BlueprintMiscContent": { + "properties": { + "name": { + "type": "string" + }, + "location": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ] + }, + "BlueprintOutput": { + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ] + }, + "BlueprintQuotaDetail": { + "properties": { + "variable": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "GCE_INSTANCE", + "GCE_DISK" + ] + }, + "quotaType": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "type", + "quotaType" + ] + }, + "BlueprintRepoDetail": { + "properties": { + "repo": { + "type": "string" + }, + "sourceType": { + "type": "string" + }, + "dir": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "repo", + "sourceType" + ] + }, + "BlueprintRequirements": { + "properties": { + "roles": { + "items": { + "$ref": "#/$defs/BlueprintRoles" + }, + "type": "array" + }, + "services": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object" + }, + "BlueprintRoles": { + "properties": { + "level": { + "type": "string" + }, + "roles": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "level", + "roles" + ] + }, + "BlueprintSoftware": { + "properties": { + "title": { + "type": "string" + }, + "version": { + "type": "string" + }, + "url": { + "type": "string" + }, + "licenseUrl": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "title" + ] + }, + "BlueprintSoftwareGroup": { + "properties": { + "type": { + "type": "string", + "enum": [ + "UNSPECIFIED", + "OS" + ] + }, + "software": { + "items": { + "$ref": "#/$defs/BlueprintSoftware" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object" + }, + "BlueprintSupport": { + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string" + }, + "entity": { + "type": "string" + }, + "showSupportId": { + "type": "boolean" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "description" + ] + }, + "BlueprintTimeEstimate": { + "properties": { + "configuration": { + "type": "integer" + }, + "deployment": { + "type": "integer" + } + }, + "additionalProperties": false, + "type": "object" + }, + "BlueprintUI": { + "properties": { + "input": { + "$ref": "#/$defs/BlueprintUIInput" + }, + "runtime": { + "$ref": "#/$defs/BlueprintUIOutput" + } + }, + "additionalProperties": false, + "type": "object" + }, + "BlueprintUIInput": { + "properties": { + "variables": { + "patternProperties": { + ".*": { + "$ref": "#/$defs/DisplayVariable" + } + }, + "type": "object" + }, + "sections": { + "items": { + "$ref": "#/$defs/DisplaySection" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object" + }, + "BlueprintUIOutput": { + "properties": { + "outputMessage": { + "type": "string" + }, + "suggestedActions": { + "items": { + "$ref": "#/$defs/UIActionItem" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object" + }, + "BlueprintVariable": { + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string" + }, + "default": true, + "required": { + "type": "boolean" + } + }, + "additionalProperties": false, + "type": "object" + }, + "BlueprintVariableGroup": { + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "variables": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ] + }, + "DisplaySection": { + "properties": { + "name": { + "type": "string" + }, + "title": { + "type": "string" + }, + "tooltip": { + "type": "string" + }, + "subtext": { + "type": "string" + }, + "parent": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ] + }, + "DisplayVariable": { + "properties": { + "name": { + "type": "string" + }, + "title": { + "type": "string" + }, + "invisible": { + "type": "boolean" + }, + "tooltip": { + "type": "string" + }, + "placeholder": { + "type": "string" + }, + "regexValidation": { + "type": "string" + }, + "minItems": { + "type": "integer" + }, + "maxItems": { + "type": "integer" + }, + "minLength": { + "type": "integer" + }, + "maxLength": { + "type": "integer" + }, + "min": { + "type": "integer" + }, + "max": { + "type": "integer" + }, + "section": { + "type": "string" + }, + "x-googleProperty": { + "$ref": "#/$defs/GooglePropertyExtension" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ] + }, + "GCEDiskSizeExtension": { + "properties": { + "diskTypeVariable": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "diskTypeVariable" + ] + }, + "GCEExternalIPExtension": { + "properties": { + "networkVariable": { + "type": "string" + }, + "externalIpType": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "networkVariable" + ] + }, + "GCEFirewallExtension": { + "properties": { + "networkVariable": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "networkVariable" + ] + }, + "GCEFirewallRangeExtension": { + "properties": { + "firewallVariable": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "firewallVariable" + ] + }, + "GCEGPUCountExtension": { + "properties": { + "machineTypeVariable": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "machineTypeVariable" + ] + }, + "GCEGPUTypeExtension": { + "properties": { + "machineType": { + "type": "string" + }, + "gpuType": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "machineType" + ] + }, + "GCEGenericResourceExtension": { + "properties": { + "resourceVariable": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "resourceVariable" + ] + }, + "GCEIPForwardingExtension": { + "properties": { + "networkVariable": { + "type": "string" + }, + "notConfigurable": { + "type": "boolean" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "networkVariable" + ] + }, + "GCELocationExtension": { + "properties": { + "allowlistedZones": { + "items": { + "type": "string" + }, + "type": "array" + }, + "allowlistedRegions": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object" + }, + "GCEMachineTypeExtension": { + "properties": { + "minCpu": { + "type": "integer" + }, + "minRamGb": { + "type": "integer" + }, + "disallowCustomMachineTypes": { + "type": "boolean" + } + }, + "additionalProperties": false, + "type": "object" + }, + "GCENetworkExtension": { + "properties": { + "allowSharedVpcs": { + "type": "boolean" + }, + "machineTypeVariable": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "machineTypeVariable" + ] + }, + "GCESubnetworkExtension": { + "properties": { + "networkVariable": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "networkVariable" + ] + }, + "GooglePropertyExtension": { + "properties": { + "type": { + "type": "string", + "enum": [ + "EMAIL_ADDRESS", + "MULTI_LINE_STRING", + "GCE_DISK_IMAGE", + "GCE_DISK_TYPE", + "GCE_DISK_SIZE", + "GCE_MACHINE_TYPE", + "GCE_NETWORK", + "GCE_ZONE", + "GCE_SUBNETWORK", + "GCE_REGION", + "GCE_GPU_TYPE", + "GCE_GPU_COUNT", + "GCE_EXTERNAL_IP", + "GCE_IP_FORWARDING", + "GCE_FIREWALL", + "GCE_FIREWALL_RANGE", + "GCE_GENERIC_RESOURCE", + "GCS_BUCKET", + "IAM_SERVICE_ACCOUNT" + ] + }, + "zoneProperty": { + "type": "string" + }, + "gceMachineType": { + "$ref": "#/$defs/GCEMachineTypeExtension" + }, + "gceDiskSize": { + "$ref": "#/$defs/GCEDiskSizeExtension" + }, + "gceSubnetwork": { + "$ref": "#/$defs/GCESubnetworkExtension" + }, + "gceResource": { + "$ref": "#/$defs/GCEGenericResourceExtension" + }, + "gceGpuType": { + "$ref": "#/$defs/GCEGPUTypeExtension" + }, + "gceGpuCount": { + "$ref": "#/$defs/GCEGPUCountExtension" + }, + "gceNetwork": { + "$ref": "#/$defs/GCENetworkExtension" + }, + "gceExternalIp": { + "$ref": "#/$defs/GCEExternalIPExtension" + }, + "gceIpForwarding": { + "$ref": "#/$defs/GCEIPForwardingExtension" + }, + "gceFirewall": { + "$ref": "#/$defs/GCEFirewallExtension" + }, + "gceFirewallRange": { + "$ref": "#/$defs/GCEFirewallRangeExtension" + }, + "gceZone": { + "$ref": "#/$defs/GCELocationExtension" + }, + "gceRegion": { + "$ref": "#/$defs/GCELocationExtension" + }, + "iamServiceAccount": { + "$ref": "#/$defs/IAMServiceAccountExtension" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "type" + ] + }, + "IAMServiceAccountExtension": { + "properties": { + "roles": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "roles" + ] + }, + "ObjectMeta": { + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "labels": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "annotations": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "additionalProperties": false, + "type": "object" + }, + "UIActionItem": { + "properties": { + "heading": { + "type": "string" + }, + "description": { + "type": "string" + }, + "snippet": { + "type": "string" + }, + "showIf": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "heading" + ] + } + } +} \ No newline at end of file diff --git a/tools/validate_metadata.py b/tools/validate_metadata.py new file mode 100755 index 000000000..d6d544ed2 --- /dev/null +++ b/tools/validate_metadata.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 + +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +'''Validate a YAML file against the standard blueprint metadata schema[1] + +[1] https://github.com/GoogleCloudPlatform/cloud-foundation-toolkit/blob/master/cli/bpmetadata/schema/bpmetadataschema.json +''' + +import enum +import json +import sys +from dataclasses import dataclass +from pathlib import Path + +import click +import jsonschema +import yaml + +SCHEMA_PATH = Path(__file__).parent / 'bpmetadataschema.json' + + +class State(enum.Enum): + INVALID: int = 0 + OK: int = 1 + + +@dataclass +class ValidationResult: + state: State + errors: dict[str, str] + + +def _validate(path: Path, validator) -> ValidationResult: + with open(path) as f: + metadata = yaml.safe_load(f) + + errors = { + error.json_path: error.message + for error in validator.iter_errors(metadata) + } + + state = State.OK if not errors else State.INVALID + return ValidationResult(state=state, errors=errors) + + +@click.command() +@click.argument('dirs', type=click.Path(exists=True, file_okay=False), nargs=-1) +@click.option('-v', '--verbose', is_flag=True, default=False, + help='Print additional validation details.') +def main(dirs: str, verbose: bool) -> int: + instances = set() + for dir_name in dirs: + instances |= set(Path(dir_name).glob("**/metadata.yaml")) + + with open(SCHEMA_PATH) as f: + schema = json.load(f) + validator = jsonschema.validators.Draft202012Validator(schema) + + results = {} + for instance in instances: + result = _validate(instance, validator) + if result.state == State.OK: + print(f'[✓] {instance}') + else: + print(f'[✗] {instance}') + results[instance] = result.errors + + if verbose: + for file_path, errors in results.items(): + print(f"\n====== {file_path!s} ======") + for path, message in errors.items(): + print(f"{path}: {message}") + + if errors: + return 1 + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) From 873c45d6c61e36e65c4225d3489974eb6b249f96 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Fri, 5 May 2023 17:01:08 +0200 Subject: [PATCH 2/6] Add jsonschema to tools requirements.txt --- tools/requirements.txt | 1 + tools/validate_metadata.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 1b01cfa04..03554bd98 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -6,3 +6,4 @@ marko requests yamale yapf +types-jsonschema diff --git a/tools/validate_metadata.py b/tools/validate_metadata.py index d6d544ed2..abb86b3c1 100755 --- a/tools/validate_metadata.py +++ b/tools/validate_metadata.py @@ -59,7 +59,7 @@ def _validate(path: Path, validator) -> ValidationResult: @click.argument('dirs', type=click.Path(exists=True, file_okay=False), nargs=-1) @click.option('-v', '--verbose', is_flag=True, default=False, help='Print additional validation details.') -def main(dirs: str, verbose: bool) -> int: +def main(dirs: list[str], verbose: bool) -> int: instances = set() for dir_name in dirs: instances |= set(Path(dir_name).glob("**/metadata.yaml")) From 72b5944fb30b2139fbcafb103baa19e2093c25a0 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Fri, 5 May 2023 17:02:26 +0200 Subject: [PATCH 3/6] Simplify return --- .github/workflows/linting.yml | 2 +- tools/validate_metadata.py | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 025c17117..69ba86a5a 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -79,4 +79,4 @@ jobs: - name: Check blueprint metadata id: metadata run: | - pythontools/validate_metadata.py -v blueprints + python tools/validate_metadata.py -v blueprints diff --git a/tools/validate_metadata.py b/tools/validate_metadata.py index abb86b3c1..f58c7dd87 100755 --- a/tools/validate_metadata.py +++ b/tools/validate_metadata.py @@ -83,10 +83,7 @@ def main(dirs: list[str], verbose: bool) -> int: for path, message in errors.items(): print(f"{path}: {message}") - if errors: - return 1 - - return 0 + return 0 if not errors else 1 if __name__ == '__main__': From 176209ccdad5fd9195112b5a159a00c490b35bac Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Fri, 5 May 2023 17:05:03 +0200 Subject: [PATCH 4/6] Fix requirements --- tools/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/requirements.txt b/tools/requirements.txt index 03554bd98..c5d809dd1 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -6,4 +6,4 @@ marko requests yamale yapf -types-jsonschema +jsonschema From 87281f2017f5f689e6c7fd919de124865721ce18 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Fri, 5 May 2023 17:08:24 +0200 Subject: [PATCH 5/6] Fix var name --- tools/validate_metadata.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/validate_metadata.py b/tools/validate_metadata.py index f58c7dd87..08e76ea5b 100755 --- a/tools/validate_metadata.py +++ b/tools/validate_metadata.py @@ -68,22 +68,22 @@ def main(dirs: list[str], verbose: bool) -> int: schema = json.load(f) validator = jsonschema.validators.Draft202012Validator(schema) - results = {} + failed_files = {} for instance in instances: result = _validate(instance, validator) if result.state == State.OK: print(f'[✓] {instance}') else: print(f'[✗] {instance}') - results[instance] = result.errors + failed_files[instance] = result.errors if verbose: - for file_path, errors in results.items(): + for file_path, errors in failed_files.items(): print(f"\n====== {file_path!s} ======") for path, message in errors.items(): print(f"{path}: {message}") - return 0 if not errors else 1 + return 0 if not failed_files else 1 if __name__ == '__main__': From 491b52f02397fbddd26a2a276cc7fd91d7948170 Mon Sep 17 00:00:00 2001 From: Jack P Date: Fri, 5 May 2023 18:42:00 +0100 Subject: [PATCH 6/6] update variables files for gke nodepool taints (#1358) * update variables files for gke node config taints to allow passing of node objects * forgot to run terraform fmt.. * update module docs --- blueprints/gke/multitenant-fleet/README.md | 10 +++++----- blueprints/gke/multitenant-fleet/variables.tf | 6 +++++- fast/stages/3-gke-multitenant/dev/README.md | 10 +++++----- fast/stages/3-gke-multitenant/dev/variables.tf | 6 +++++- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/blueprints/gke/multitenant-fleet/README.md b/blueprints/gke/multitenant-fleet/README.md index c263317b8..0818479b4 100644 --- a/blueprints/gke/multitenant-fleet/README.md +++ b/blueprints/gke/multitenant-fleet/README.md @@ -247,9 +247,9 @@ module "gke" { |---|---|:---:|:---:|:---:| | [billing_account_id](variables.tf#L17) | Billing account id. | string | ✓ | | | [folder_id](variables.tf#L132) | Folder used for the GKE project in folders/nnnnnnnnnnn format. | string | ✓ | | -| [prefix](variables.tf#L179) | Prefix used for resource names. | string | ✓ | | -| [project_id](variables.tf#L188) | ID of the project that will contain all the clusters. | string | ✓ | | -| [vpc_config](variables.tf#L200) | Shared VPC project and VPC details. | object({…}) | ✓ | | +| [prefix](variables.tf#L183) | Prefix used for resource names. | string | ✓ | | +| [project_id](variables.tf#L192) | ID of the project that will contain all the clusters. | string | ✓ | | +| [vpc_config](variables.tf#L204) | Shared VPC project and VPC details. | object({…}) | ✓ | | | [clusters](variables.tf#L22) | Clusters configuration. Refer to the gke-cluster module for type details. | map(object({…})) | | {} | | [fleet_configmanagement_clusters](variables.tf#L70) | Config management features enabled on specific sets of member clusters, in config name => [cluster name] format. | map(list(string)) | | {} | | [fleet_configmanagement_templates](variables.tf#L77) | Sets of config management configurations that can be applied to member clusters, in config name => {options} format. | map(object({…})) | | {} | @@ -258,8 +258,8 @@ module "gke" { | [group_iam](variables.tf#L137) | Project-level IAM bindings for groups. Use group emails as keys, list of roles as values. | map(list(string)) | | {} | | [iam](variables.tf#L144) | Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | | [labels](variables.tf#L151) | Project-level labels. | map(string) | | {} | -| [nodepools](variables.tf#L157) | Nodepools configuration. Refer to the gke-nodepool module for type details. | map(map(object({…}))) | | {} | -| [project_services](variables.tf#L193) | Additional project services to enable. | list(string) | | [] | +| [nodepools](variables.tf#L157) | Nodepools configuration. Refer to the gke-nodepool module for type details. | map(map(object({…}))) | | {} | +| [project_services](variables.tf#L197) | Additional project services to enable. | list(string) | | [] | ## Outputs diff --git a/blueprints/gke/multitenant-fleet/variables.tf b/blueprints/gke/multitenant-fleet/variables.tf index 2cfd26a1b..13760606e 100644 --- a/blueprints/gke/multitenant-fleet/variables.tf +++ b/blueprints/gke/multitenant-fleet/variables.tf @@ -170,7 +170,11 @@ variable "nodepools" { service_account = optional(any) sole_tenant_nodegroup = optional(string) tags = optional(list(string)) - taints = optional(list(any)) + taints = optional(list(object({ + key = string + value = string + effect = string + }))) }))) default = {} nullable = false diff --git a/fast/stages/3-gke-multitenant/dev/README.md b/fast/stages/3-gke-multitenant/dev/README.md index 3cc4e3304..2152003a1 100644 --- a/fast/stages/3-gke-multitenant/dev/README.md +++ b/fast/stages/3-gke-multitenant/dev/README.md @@ -166,8 +166,8 @@ Leave all these variables unset (or set to `null`) to disable fleet management. | [billing_account](variables.tf#L29) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | object({…}) | ✓ | | 0-bootstrap | | [folder_ids](variables.tf#L153) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | object({…}) | ✓ | | 1-resman | | [host_project_ids](variables.tf#L168) | Host project for the shared VPC. | object({…}) | ✓ | | 2-networking | -| [prefix](variables.tf#L217) | Prefix used for resources that need unique names. | string | ✓ | | | -| [vpc_self_links](variables.tf#L233) | Self link for the shared VPC. | object({…}) | ✓ | | 2-networking | +| [prefix](variables.tf#L221) | Prefix used for resources that need unique names. | string | ✓ | | | +| [vpc_self_links](variables.tf#L237) | Self link for the shared VPC. | object({…}) | ✓ | | 2-networking | | [clusters](variables.tf#L42) | Clusters configuration. Refer to the gke-cluster module for type details. | map(object({…})) | | {} | | | [fleet_configmanagement_clusters](variables.tf#L90) | Config management features enabled on specific sets of member clusters, in config name => [cluster name] format. | map(list(string)) | | {} | | | [fleet_configmanagement_templates](variables.tf#L98) | Sets of config management configurations that can be applied to member clusters, in config name => {options} format. | map(object({…})) | | {} | | @@ -176,9 +176,9 @@ Leave all these variables unset (or set to `null`) to disable fleet management. | [group_iam](variables.tf#L161) | Project-level authoritative IAM bindings for groups in {GROUP_EMAIL => [ROLES]} format. Use group emails as keys, list of roles as values. | map(list(string)) | | {} | | | [iam](variables.tf#L176) | Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | | | [labels](variables.tf#L183) | Project-level labels. | map(string) | | {} | | -| [nodepools](variables.tf#L189) | Nodepools configuration. Refer to the gke-nodepool module for type details. | map(map(object({…}))) | | {} | | -| [outputs_location](variables.tf#L211) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | | -| [project_services](variables.tf#L226) | Additional project services to enable. | list(string) | | [] | | +| [nodepools](variables.tf#L189) | Nodepools configuration. Refer to the gke-nodepool module for type details. | map(map(object({…}))) | | {} | | +| [outputs_location](variables.tf#L215) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | | +| [project_services](variables.tf#L230) | Additional project services to enable. | list(string) | | [] | | ## Outputs diff --git a/fast/stages/3-gke-multitenant/dev/variables.tf b/fast/stages/3-gke-multitenant/dev/variables.tf index db532dd0e..a872b49d1 100644 --- a/fast/stages/3-gke-multitenant/dev/variables.tf +++ b/fast/stages/3-gke-multitenant/dev/variables.tf @@ -202,7 +202,11 @@ variable "nodepools" { service_account = optional(any) sole_tenant_nodegroup = optional(string) tags = optional(list(string)) - taints = optional(list(any)) + taints = optional(list(object({ + key = string + value = string + effect = string + }))) }))) default = {} nullable = false