From 1db0b18d0c10d5874ec77d22616a6b84a8332a54 Mon Sep 17 00:00:00 2001 From: Richard Killen Date: Wed, 18 Jan 2023 14:59:19 -0600 Subject: [PATCH 01/10] Added CRD schemas for Verrazzano, moved existing schemas to crds directory --- .../main/python/wlsdeploy/tool/util/targets/schema_helper.py | 2 +- .../weblogic/deploy/{wko => crds}/cluster-crd-schema-v1.json | 0 .../weblogic/deploy/{wko => crds}/domain-crd-schema-v8.json | 0 .../weblogic/deploy/{wko => crds}/domain-crd-schema-v9.json | 0 .../oracle/weblogic/deploy/crds/vz-application-v1alpha2.json | 1 + .../oracle/weblogic/deploy/crds/vz-configmap-v1alpha2.json | 1 + .../oracle/weblogic/deploy/crds/vz-weblogic-v1alpha2.json | 1 + 7 files changed, 4 insertions(+), 1 deletion(-) rename core/src/main/resources/oracle/weblogic/deploy/{wko => crds}/cluster-crd-schema-v1.json (100%) rename core/src/main/resources/oracle/weblogic/deploy/{wko => crds}/domain-crd-schema-v8.json (100%) rename core/src/main/resources/oracle/weblogic/deploy/{wko => crds}/domain-crd-schema-v9.json (100%) create mode 100644 core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha2.json create mode 100644 core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha2.json create mode 100644 core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha2.json diff --git a/core/src/main/python/wlsdeploy/tool/util/targets/schema_helper.py b/core/src/main/python/wlsdeploy/tool/util/targets/schema_helper.py index 1949b3c68..c6b0670ef 100644 --- a/core/src/main/python/wlsdeploy/tool/util/targets/schema_helper.py +++ b/core/src/main/python/wlsdeploy/tool/util/targets/schema_helper.py @@ -12,7 +12,7 @@ DOMAIN_RESOURCE_SCHEMA_ROOT = "openAPIV3Schema" SCHEMA_RESOURCE_EXTENSION = '.json' -SCHEMA_RESOURCE_PATH = 'oracle/weblogic/deploy/wko' +SCHEMA_RESOURCE_PATH = 'oracle/weblogic/deploy/crds' SIMPLE_TYPES = [ 'integer', diff --git a/core/src/main/resources/oracle/weblogic/deploy/wko/cluster-crd-schema-v1.json b/core/src/main/resources/oracle/weblogic/deploy/crds/cluster-crd-schema-v1.json similarity index 100% rename from core/src/main/resources/oracle/weblogic/deploy/wko/cluster-crd-schema-v1.json rename to core/src/main/resources/oracle/weblogic/deploy/crds/cluster-crd-schema-v1.json diff --git a/core/src/main/resources/oracle/weblogic/deploy/wko/domain-crd-schema-v8.json b/core/src/main/resources/oracle/weblogic/deploy/crds/domain-crd-schema-v8.json similarity index 100% rename from core/src/main/resources/oracle/weblogic/deploy/wko/domain-crd-schema-v8.json rename to core/src/main/resources/oracle/weblogic/deploy/crds/domain-crd-schema-v8.json diff --git a/core/src/main/resources/oracle/weblogic/deploy/wko/domain-crd-schema-v9.json b/core/src/main/resources/oracle/weblogic/deploy/crds/domain-crd-schema-v9.json similarity index 100% rename from core/src/main/resources/oracle/weblogic/deploy/wko/domain-crd-schema-v9.json rename to core/src/main/resources/oracle/weblogic/deploy/crds/domain-crd-schema-v9.json diff --git a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha2.json b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha2.json new file mode 100644 index 000000000..982720bd8 --- /dev/null +++ b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha2.json @@ -0,0 +1 @@ +{"openAPIV3Schema":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"type":"object"},"spec":{"properties":{"components":{"items":{"properties":{"componentName":{"type":"string"},"dataInputs":{"items":{"properties":{"toFieldPaths":{"items":{"type":"string"},"type":"array"},"valueFrom":{"properties":{"dataOutputName":{"type":"string"}},"required":["dataOutputName"],"type":"object"}},"type":"object"},"type":"array"},"dataOutputs":{"items":{"properties":{"conditions":{"items":{"properties":{"fieldPath":{"type":"string"},"op":{"type":"string"},"value":{"type":"string"},"valueFrom":{"properties":{"fieldPath":{"type":"string"}},"required":["fieldPath"],"type":"object"}},"required":["op"],"type":"object"},"type":"array"},"fieldPath":{"type":"string"},"name":{"type":"string"}},"type":"object"},"type":"array"},"parameterValues":{"items":{"properties":{"name":{"type":"string"},"value":{"anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}},"required":["name","value"],"type":"object"},"type":"array"},"revisionName":{"type":"string"},"scopes":{"items":{"properties":{"scopeRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["scopeRef"],"type":"object"},"type":"array"},"traits":{"items":{"properties":{"dataInputs":{"items":{"properties":{"toFieldPaths":{"items":{"type":"string"},"type":"array"},"valueFrom":{"properties":{"dataOutputName":{"type":"string"}},"required":["dataOutputName"],"type":"object"}},"type":"object"},"type":"array"},"dataOutputs":{"items":{"properties":{"conditions":{"items":{"properties":{"fieldPath":{"type":"string"},"op":{"type":"string"},"value":{"type":"string"},"valueFrom":{"properties":{"fieldPath":{"type":"string"}},"required":["fieldPath"],"type":"object"}},"required":["op"],"type":"object"},"type":"array"},"fieldPath":{"type":"string"},"name":{"type":"string"}},"type":"object"},"type":"array"},"trait":{"type":"object","x-kubernetes-embedded-resource":true,"x-kubernetes-preserve-unknown-fields":true}},"required":["trait"],"type":"object"},"type":"array"}},"type":"object"},"type":"array"}},"required":["components"],"type":"object"},"status":{"properties":{"conditions":{"items":{"properties":{"lastTransitionTime":{"format":"date-time","type":"string"},"message":{"type":"string"},"reason":{"type":"string"},"status":{"type":"string"},"type":{"type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"},"dependency":{"properties":{"unsatisfied":{"items":{"properties":{"from":{"properties":{"apiVersion":{"type":"string"},"fieldPath":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"},"reason":{"type":"string"},"to":{"properties":{"apiVersion":{"type":"string"},"fieldPaths":{"items":{"type":"string"},"type":"array"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["from","reason","to"],"type":"object"},"type":"array"}},"type":"object"},"historyWorkloads":{"items":{"properties":{"revision":{"type":"string"},"workloadRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"type":"object"},"type":"array"},"observedGeneration":{"format":"int64","type":"integer"},"status":{"type":"string"},"workloads":{"items":{"properties":{"componentName":{"type":"string"},"componentRevisionName":{"type":"string"},"scopes":{"items":{"properties":{"scopeRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"},"status":{"type":"string"}},"required":["scopeRef"],"type":"object"},"type":"array"},"status":{"type":"string"},"traits":{"items":{"properties":{"message":{"type":"string"},"status":{"type":"string"},"traitRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["traitRef"],"type":"object"},"type":"array"},"workloadRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"type":"object"},"type":"array"}},"type":"object"}},"type":"object"}} diff --git a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha2.json b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha2.json new file mode 100644 index 000000000..f8be3126d --- /dev/null +++ b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha2.json @@ -0,0 +1 @@ +{"openAPIV3Schema":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"type":"object"},"spec":{"properties":{"parameters":{"items":{"properties":{"description":{"type":"string"},"fieldPaths":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"required":{"default":false,"type":"boolean"}},"required":["fieldPaths","name"],"type":"object"},"type":"array"},"workload":{"properties":{"apiVersion":{"type":"string"},"binaryData":{"additionalProperties":{"format":"byte","type":"string"},"type":"object"},"data":{"additionalProperties":{"type":"string"},"type":"object"},"kind":{"enum":["ConfigMap"],"type":"string"},"metadata":{"properties":{"annotations":{"additionalProperties":{"type":"string"},"type":"object"},"clusterName":{"type":"string"},"creationTimestamp":{"format":"date-time","type":"string"},"deletionGracePeriodSeconds":{"format":"int64","type":"integer"},"deletionTimestamp":{"format":"date-time","type":"string"},"finalizers":{"items":{"type":"string"},"type":"array","x-kubernetes-patch-strategy":"merge"},"generateName":{"type":"string"},"generation":{"format":"int64","type":"integer"},"initializers":{"properties":{"pending":{"items":{"properties":{"name":{"type":"string"}},"required":["name"]},"type":"array","x-kubernetes-patch-merge-key":"name","x-kubernetes-patch-strategy":"merge"},"result":{"properties":{"apiVersion":{"type":"string"},"code":{"format":"int32","type":"integer"},"details":{"properties":{"causes":{"items":{"properties":{"field":{"type":"string"},"message":{"type":"string"},"reason":{"type":"string"}}},"type":"array"},"group":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"retryAfterSeconds":{"format":"int32","type":"integer"},"uid":{"type":"string"}}},"kind":{"enum":["Status"],"type":"string"},"message":{"type":"string"},"metadata":{"properties":{"continue":{"type":"string"},"resourceVersion":{"type":"string"},"selfLink":{"type":"string"}}},"reason":{"type":"string"},"status":{"type":"string"}},"x-kubernetes-group-version-kind":[{"group":"","kind":"Status","version":"v1"}]}},"required":["pending"]},"labels":{"additionalProperties":{"type":"string"},"type":"object"},"name":{"type":"string"},"namespace":{"type":"string"},"ownerReferences":{"items":{"properties":{"apiVersion":{"type":"string"},"blockOwnerDeletion":{"type":"boolean"},"controller":{"type":"boolean"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name","uid"]},"type":"array","x-kubernetes-patch-merge-key":"uid","x-kubernetes-patch-strategy":"merge"},"resourceVersion":{"type":"string"},"selfLink":{"type":"string"},"uid":{"type":"string"}}}},"type":"object","x-kubernetes-embedded-resource":true,"x-kubernetes-group-version-kind":[{"group":"","kind":"ConfigMap","version":"v1"}],"x-kubernetes-preserve-unknown-fields":true}},"required":["workload"],"type":"object"},"status":{"properties":{"conditions":{"items":{"properties":{"lastTransitionTime":{"format":"date-time","type":"string"},"message":{"type":"string"},"reason":{"type":"string"},"status":{"type":"string"},"type":{"type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"},"latestRevision":{"properties":{"name":{"type":"string"},"revision":{"format":"int64","type":"integer"}},"required":["name","revision"],"type":"object"},"observedGeneration":{"format":"int64","type":"integer"}},"type":"object"}},"type":"object"}} diff --git a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha2.json b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha2.json new file mode 100644 index 000000000..bbed4809c --- /dev/null +++ b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha2.json @@ -0,0 +1 @@ +{"openAPIV3Schema":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"type":"object"},"spec":{"properties":{"parameters":{"items":{"properties":{"description":{"type":"string"},"fieldPaths":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"required":{"default":false,"type":"boolean"}},"required":["fieldPaths","name"],"type":"object"},"type":"array"},"workload":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"type":"object"},"spec":{"properties":{"clusters":{"items":{"properties":{"apiVersion":{"type":"string"},"metadata":{"type":"object","x-kubernetes-preserve-unknown-fields":true},"spec":{"type":"object","x-kubernetes-preserve-unknown-fields":true}},"required":["spec"],"type":"object"},"type":"array"},"template":{"properties":{"apiVersion":{"type":"string"},"metadata":{"type":"object","x-kubernetes-preserve-unknown-fields":true},"spec":{"type":"object","x-kubernetes-preserve-unknown-fields":true}},"required":["spec"],"type":"object","x-kubernetes-preserve-unknown-fields":true}},"required":["template"],"type":"object"},"status":{"properties":{"lastGeneration":{"type":"string"},"lastLifecycleAction":{"type":"string"},"lastRestartVersion":{"type":"string"}},"type":"object"}},"type":"object","x-kubernetes-embedded-resource":true,"x-kubernetes-preserve-unknown-fields":true}},"required":["workload"],"type":"object"},"status":{"properties":{"conditions":{"items":{"properties":{"lastTransitionTime":{"format":"date-time","type":"string"},"message":{"type":"string"},"reason":{"type":"string"},"status":{"type":"string"},"type":{"type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"},"latestRevision":{"properties":{"name":{"type":"string"},"revision":{"format":"int64","type":"integer"}},"required":["name","revision"],"type":"object"},"observedGeneration":{"format":"int64","type":"integer"}},"type":"object"}},"type":"object"}} From b26f86053e41abfff217db0e4f602269fb5cb4cf Mon Sep 17 00:00:00 2001 From: Richard Killen Date: Wed, 18 Jan 2023 16:00:38 -0600 Subject: [PATCH 02/10] Added verrazzano section to model, associate schemas to its CRD folders --- .../wlsdeploy/aliases/model_constants.py | 10 +- ...rinter.py => model_crd_section_printer.py} | 11 +- .../tool/modelhelp/model_help_printer.py | 11 +- .../tool/util/targets/model_crd_helper.py | 123 ++++++++++++++++-- ...validator.py => crd_sections_validator.py} | 27 ++-- .../wlsdeploy/tool/validate/validator.py | 6 +- .../wlsdeploy/util/target_configuration.py | 22 +++- .../deploy/messages/wlsdeploy_rb.properties | 7 +- .../src/main/targetconfigs/vz-dii/target.json | 1 + core/src/main/targetconfigs/vz-pv/target.json | 1 + core/src/main/targetconfigs/vz/target.json | 1 + .../util/targets/kubernetes_schema_test.py | 25 ++-- 12 files changed, 190 insertions(+), 55 deletions(-) rename core/src/main/python/wlsdeploy/tool/modelhelp/{model_kubernetes_printer.py => model_crd_section_printer.py} (96%) rename core/src/main/python/wlsdeploy/tool/validate/{kubernetes_validator.py => crd_sections_validator.py} (90%) diff --git a/core/src/main/python/wlsdeploy/aliases/model_constants.py b/core/src/main/python/wlsdeploy/aliases/model_constants.py index 023414169..3a5857808 100644 --- a/core/src/main/python/wlsdeploy/aliases/model_constants.py +++ b/core/src/main/python/wlsdeploy/aliases/model_constants.py @@ -312,6 +312,7 @@ USER_ATTRIBUTES = 'UserAttribute' USE_SAMPLE_DATABASE = 'UseSampleDatabase' USE_SSL = "useSSL" +VERRAZZANO = "verrazzano" VIRTUAL_HOST = 'VirtualHost' VIRTUAL_TARGET = 'VirtualTarget' VIRTUAL_USER_AUTHENTICATOR = 'VirtualUserAuthenticator' @@ -427,7 +428,14 @@ TOPOLOGY, RESOURCES, APP_DEPLOYMENTS, - KUBERNETES + KUBERNETES, + VERRAZZANO +] + +# the contents of these sections are based on CRD schemas +CRD_MODEL_SECTIONS = [ + KUBERNETES, + VERRAZZANO ] # these domain attributes have special processing in create, diff --git a/core/src/main/python/wlsdeploy/tool/modelhelp/model_kubernetes_printer.py b/core/src/main/python/wlsdeploy/tool/modelhelp/model_crd_section_printer.py similarity index 96% rename from core/src/main/python/wlsdeploy/tool/modelhelp/model_kubernetes_printer.py rename to core/src/main/python/wlsdeploy/tool/modelhelp/model_crd_section_printer.py index 91a1dc1f4..016131b6f 100644 --- a/core/src/main/python/wlsdeploy/tool/modelhelp/model_kubernetes_printer.py +++ b/core/src/main/python/wlsdeploy/tool/modelhelp/model_crd_section_printer.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2020, 2022, Oracle and/or its affiliates. +Copyright (c) 2020, 2023, Oracle and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ from wlsdeploy.exception import exception_helper @@ -12,15 +12,16 @@ from wlsdeploy.util.exit_code import ExitCode -class ModelKubernetesPrinter(object): +class ModelCrdSectionPrinter(object): """ Class for printing kubernetes sections as model samples. """ - _class_name = "ModelKubernetesPrinter" + _class_name = "ModelCrdSectionPrinter" _logger = PlatformLogger('wlsdeploy.modelhelp') def __init__(self, model_context): self._crd_helper = model_crd_helper.get_helper(model_context) + self._target = model_context.get_target() def print_model_sample(self, model_path_tokens, control_option): """ @@ -30,6 +31,10 @@ def print_model_sample(self, model_path_tokens, control_option): :raises CLAException: if a problem is encountered """ section_name = model_path_tokens[0] + if section_name != self._crd_helper.get_model_section(): + print("") + print(exception_helper.get_message('WLSDPLY-10113', section_name)) + return if len(model_path_tokens) == 1: self._print_model_section_sample(section_name, control_option) diff --git a/core/src/main/python/wlsdeploy/tool/modelhelp/model_help_printer.py b/core/src/main/python/wlsdeploy/tool/modelhelp/model_help_printer.py index c01a01dca..5b2926e76 100644 --- a/core/src/main/python/wlsdeploy/tool/modelhelp/model_help_printer.py +++ b/core/src/main/python/wlsdeploy/tool/modelhelp/model_help_printer.py @@ -1,16 +1,17 @@ """ -Copyright (c) 2020, 2022, Oracle Corporation and/or its affiliates. +Copyright (c) 2020, 2023, Oracle Corporation and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ import re from oracle.weblogic.deploy.exception import ExceptionHelper +from wlsdeploy.aliases.model_constants import CRD_MODEL_SECTIONS from wlsdeploy.aliases.model_constants import KNOWN_TOPLEVEL_MODEL_SECTIONS from wlsdeploy.aliases.model_constants import KUBERNETES from wlsdeploy.exception import exception_helper from wlsdeploy.tool.modelhelp.model_help_utils import ControlOptions -from wlsdeploy.tool.modelhelp.model_kubernetes_printer import ModelKubernetesPrinter +from wlsdeploy.tool.modelhelp.model_crd_section_printer import ModelCrdSectionPrinter from wlsdeploy.tool.modelhelp.model_sample_printer import ModelSamplePrinter from wlsdeploy.util import model import wlsdeploy.util.unicode_helper as str_helper @@ -64,12 +65,12 @@ def print_model_help(self, model_path, control_option): elif control_option == ControlOptions.FOLDERS_ONLY: print(_format_message('WLSDPLY-10103', model_path)) elif control_option == ControlOptions.ATTRIBUTES_ONLY: - print( _format_message('WLSDPLY-10104', model_path)) + print(_format_message('WLSDPLY-10104', model_path)) else: print(_format_message('WLSDPLY-10105', model_path)) - if model_path_tokens[0] == KUBERNETES: - sample_printer = ModelKubernetesPrinter(self._model_context) + if model_path_tokens[0] in CRD_MODEL_SECTIONS: + sample_printer = ModelCrdSectionPrinter(self._model_context) sample_printer.print_model_sample(model_path_tokens, control_option) else: sample_printer = ModelSamplePrinter(self._aliases, self._logger) diff --git a/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py b/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py index da5e2220a..37af34fae 100644 --- a/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py +++ b/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py @@ -1,7 +1,10 @@ """ -Copyright (c) 2022, Oracle and/or its affiliates. +Copyright (c) 2022, 2023, Oracle and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ +from wlsdeploy.aliases.model_constants import KUBERNETES +from wlsdeploy.aliases.model_constants import VERRAZZANO +from wlsdeploy.exception import exception_helper from wlsdeploy.exception.expection_types import ExceptionType from wlsdeploy.logging import platform_logger from wlsdeploy.tool.util.targets import model_crd_folder @@ -12,8 +15,22 @@ _logger = platform_logger.PlatformLogger('wlsdeploy.deploy') _class_name = 'model_crd_helper' -WKO_PRODUCT_KEY = "wko" +VERRAZZANO_PRODUCT_KEY = "vz" +VERRAZZANO_VERSION_1 = "v1" + +VERRAZZANO_VALID_VERSIONS = [ + VERRAZZANO_VERSION_1 +] + +VZ_APPLICATION_SCHEMA_NAME = 'vz-application' +VZ_CONFIGMAP_SCHEMA_NAME = 'vz-configmap' +VZ_WEBLOGIC_SCHEMA_NAME = 'vz-weblogic' +VZ_1_SCHEMA_SUFFIX = '-v1alpha2' +VZ_1_APPLICATION_SCHEMA_NAME = VZ_APPLICATION_SCHEMA_NAME + VZ_1_SCHEMA_SUFFIX +VZ_1_CONFIGMAP_SCHEMA_NAME = VZ_CONFIGMAP_SCHEMA_NAME + VZ_1_SCHEMA_SUFFIX +VZ_1_WEBLOGIC_SCHEMA_NAME = VZ_WEBLOGIC_SCHEMA_NAME + VZ_1_SCHEMA_SUFFIX +WKO_PRODUCT_KEY = "wko" WKO_VERSION_3 = 'v3' WKO_VERSION_4 = 'v4' @@ -24,6 +41,9 @@ WKO_CLUSTER_SCHEMA_NAME = 'cluster-crd-schema' WKO_DOMAIN_SCHEMA_NAME = 'domain-crd-schema' +WKO_3_DOMAIN_SCHEMA_NAME = WKO_DOMAIN_SCHEMA_NAME + "-v8" +WKO_4_CLUSTER_SCHEMA_NAME = WKO_CLUSTER_SCHEMA_NAME + "-v1" +WKO_4_DOMAIN_SCHEMA_NAME = WKO_DOMAIN_SCHEMA_NAME + "-v9" class ModelCrdHelper: @@ -35,12 +55,11 @@ class ModelCrdHelper: """ _class_name = "ModelCrdHelper" - def __init__(self, product_name, product_version, exception_type): - self._product = product_name - self._version = product_version + def __init__(self, exception_type): self._exception_type = exception_type self._crd_folders = [] self._crd_folder_map = {} + self._model_section = None # get CRD information for model folders directly under kubernetes, def get_crd_folders(self): @@ -61,31 +80,58 @@ def add_crd_folder(self, crd_folder): self._crd_folders.append(crd_folder) self._crd_folder_map[crd_folder.get_model_key()] = crd_folder + def get_model_section(self): + return self._model_section + + def set_model_section(self, model_section): + self._model_section = model_section + # get a helper for on the version in the model context def get_helper(model_context, exception_type=ExceptionType.DEPLOY): - # product key could be in target config if more products come along, such as VZ + product_key = model_context.get_target_configuration().get_product_key() product_version = model_context.get_target_configuration().get_product_version() - return get_product_helper(WKO_PRODUCT_KEY, product_version, exception_type) + return get_product_helper(product_key, product_version, exception_type) # get a helper for the specified product and version def get_product_helper(product_key, product_version, exception_type=ExceptionType.DEPLOY): - helper = ModelCrdHelper(product_key, product_version, exception_type) + helper = ModelCrdHelper(exception_type) - if product_version == WKO_VERSION_4: - cluster_schema = schema_helper.get_schema(WKO_CLUSTER_SCHEMA_NAME + "-v1", exception_type) + if product_key == VERRAZZANO_PRODUCT_KEY: + helper.set_model_section(VERRAZZANO) + + application_schema = schema_helper.get_schema(VZ_1_APPLICATION_SCHEMA_NAME, exception_type) + application_folder = ModelCrdFolder("application", application_schema, False) + helper.add_crd_folder(application_folder) + + weblogic_schema_name = VZ_1_WEBLOGIC_SCHEMA_NAME + weblogic_schema = schema_helper.get_schema(weblogic_schema_name, exception_type) + _update_weblogic_schema(weblogic_schema, weblogic_schema_name, exception_type) + weblogic_folder = ModelCrdFolder("weblogic", weblogic_schema, False) + helper.add_crd_folder(weblogic_folder) + + configmap_schema = schema_helper.get_schema(VZ_1_CONFIGMAP_SCHEMA_NAME, exception_type) + configmap_folder = ModelCrdFolder("configmap", configmap_schema, False) + helper.add_crd_folder(configmap_folder) + + elif product_version == WKO_VERSION_4: + helper.set_model_section(KUBERNETES) + + cluster_schema = schema_helper.get_schema(WKO_4_CLUSTER_SCHEMA_NAME, exception_type) cluster_folder = ModelCrdFolder("clusters", cluster_schema, True) helper.add_crd_folder(cluster_folder) - domain_schema = schema_helper.get_schema(WKO_DOMAIN_SCHEMA_NAME + "-v9", exception_type) + domain_schema = schema_helper.get_schema(WKO_4_DOMAIN_SCHEMA_NAME, exception_type) domain_folder = ModelCrdFolder("domain", domain_schema, False) domain_folder.add_object_list_key('spec/adminServer/adminService/channels', 'channelName') domain_folder.add_object_list_key('spec/managedServers', 'serverName') helper.add_crd_folder(domain_folder) elif product_version == WKO_VERSION_3: - domain_schema = schema_helper.get_schema(WKO_DOMAIN_SCHEMA_NAME + "-v8", exception_type) + helper.set_model_section(KUBERNETES) + + domain_schema = schema_helper.get_schema(WKO_3_DOMAIN_SCHEMA_NAME, exception_type) domain_folder = ModelCrdFolder(model_crd_folder.NO_FOLDER_KEY, domain_schema, False) domain_folder.add_object_list_key('spec/adminServer/adminService/channels', 'channelName') domain_folder.add_object_list_key('spec/managedServers', 'serverName') @@ -99,4 +145,57 @@ def get_product_helper(product_key, product_version, exception_type=ExceptionTyp def get_valid_versions(product_key): if product_key == WKO_PRODUCT_KEY: return WKO_VALID_VERSIONS + if product_key == VERRAZZANO_PRODUCT_KEY: + return VERRAZZANO_VALID_VERSIONS return [] + + +def get_default_version(product_key): + if product_key == WKO_PRODUCT_KEY: + return WKO_VERSION_3 + if product_key == VERRAZZANO_PRODUCT_KEY: + return VERRAZZANO_VERSION_1 + return None + + +def _update_weblogic_schema(schema, schema_name, exception_type): + """ + Update the Verrazzano WebLogic workload schema with the WKO domain and cluster schemas. + These are combined at runtime to reduce the size of the workload schema file. + :param schema: the WebLogic workload schema + :param schema_name: the WebLogic workload schema name, used for logging + :param exception_type: the exception type to be thrown + """ + workload_spec_folder = _get_nested_folder(schema, schema_name, exception_type, 'properties', + 'spec', 'properties', 'workload', 'properties', 'spec', 'properties') + + domain_schema = schema_helper.get_schema(WKO_4_DOMAIN_SCHEMA_NAME, exception_type) + domain_folder = _get_nested_folder(workload_spec_folder, schema_name, exception_type, 'template') + for key in domain_schema.keys(): + domain_folder[key] = domain_schema[key] + + cluster_schema = schema_helper.get_schema(WKO_4_CLUSTER_SCHEMA_NAME, exception_type) + cluster_folder = _get_nested_folder(workload_spec_folder, schema_name, exception_type, 'clusters', 'items') + for key in cluster_schema.keys(): + cluster_folder[key] = cluster_schema[key] + + +def _get_nested_folder(parent_folder, schema_name, exception_type, *names): + """ + Get the folder inside parent_folder at the path specified by the list of names. + :param parent_folder: the folder to be examined + :param exception_type: the exception type to throw if the lookup fails + :param names: a list of names specifying the path inside parent_folder + :return: the nested folder + """ + _method_name = '_get_nested_folder' + + folder = parent_folder + for name in names: + if name not in folder: + ex = exception_helper.create_exception(exception_type, 'WLSDPLY-10050', name, '/'.join(names), + schema_name) + _logger.throwing(ex, class_name=_class_name, method_name=_method_name) + raise ex + folder = folder[name] + return folder diff --git a/core/src/main/python/wlsdeploy/tool/validate/kubernetes_validator.py b/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py similarity index 90% rename from core/src/main/python/wlsdeploy/tool/validate/kubernetes_validator.py rename to core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py index 0f0f76dc0..e24de4e19 100644 --- a/core/src/main/python/wlsdeploy/tool/validate/kubernetes_validator.py +++ b/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py @@ -3,7 +3,6 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ -from wlsdeploy.aliases.model_constants import KUBERNETES from wlsdeploy.exception.expection_types import ExceptionType from wlsdeploy.logging.platform_logger import PlatformLogger from wlsdeploy.tool.util.targets import model_crd_helper @@ -12,39 +11,41 @@ import wlsdeploy.util.unicode_helper as str_helper -class KubernetesValidator(object): +class CrdSectionsValidator(object): """ - Class for validating the kubernetes section of a model file + Class for validating a CRD-based section of a model file. + This includes kubernetes and verrazzano sections. """ - _class_name = 'KubernetesValidator' + _class_name = 'CrdSectionsValidator' _logger = PlatformLogger('wlsdeploy.validate') def __init__(self, model_context): self._model_context = model_context self._crd_helper = model_crd_helper.get_helper(model_context, ExceptionType.VALIDATE) + self._section_name = self._crd_helper.get_model_section() def validate_model(self, model_dict): """ - Validate the kubernetes section of the specified model. + Validate the CRD-based section of the specified model. :param model_dict: A Python dictionary of the model to be validated :raises ValidationException: if problems occur during validation """ _method_name = 'validate_model' - kubernetes_section = dictionary_utils.get_dictionary_element(model_dict, KUBERNETES) - if not kubernetes_section: + crd_section = dictionary_utils.get_dictionary_element(model_dict, self._section_name) + if not crd_section: return - model_path = KUBERNETES + ":" + model_path = self._section_name + ":" keyless_crd_folder = self._crd_helper.get_keyless_crd_folder() if keyless_crd_folder: - # this WKO version does not require kubernetes sub-folders, continue with that schema + # this WKO version does not require CRD sub-folders for this section, continue with the keyless schema schema = keyless_crd_folder.get_schema() - self.validate_folder(kubernetes_section, schema, None, model_path) + self.validate_folder(crd_section, schema, None, model_path) else: - # this WKO version requires kubernetes sub-folders, validate and process each folder - for key in kubernetes_section: + # this WKO version requires CRD sub-folders for this section, validate and process each folder + for key in crd_section: crd_folder = self._crd_helper.get_crd_folder(key) if not crd_folder: valid_keys = self._crd_helper.get_crd_folder_keys() @@ -53,7 +54,7 @@ def validate_model(self, model_dict): class_name=self._class_name, method_name=_method_name) continue - model_content = kubernetes_section[key] + model_content = crd_section[key] model_path += '/' + key schema = crd_folder.get_schema() if crd_folder.is_array(): diff --git a/core/src/main/python/wlsdeploy/tool/validate/validator.py b/core/src/main/python/wlsdeploy/tool/validate/validator.py index 098863038..8f86a2bef 100644 --- a/core/src/main/python/wlsdeploy/tool/validate/validator.py +++ b/core/src/main/python/wlsdeploy/tool/validate/validator.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2017, 2022, Oracle Corporation and/or its affiliates. +Copyright (c) 2017, 2023, Oracle Corporation and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ import os @@ -21,7 +21,7 @@ from wlsdeploy.tool.create import wlsroles_helper from wlsdeploy.tool.util.archive_helper import ArchiveHelper from wlsdeploy.tool.validate import validation_utils -from wlsdeploy.tool.validate.kubernetes_validator import KubernetesValidator +from wlsdeploy.tool.validate.crd_sections_validator import CrdSectionsValidator from wlsdeploy.tool.validate.validator_logger import ValidatorLogger from wlsdeploy.util import dictionary_utils from wlsdeploy.util import model @@ -262,7 +262,7 @@ def __validate_model_file(self, model_dict, variables_map, archive_file_name): self._aliases.get_model_app_deployments_top_level_folder_names()) if self._validate_crd_sections: - k8s_validator = KubernetesValidator(self._model_context) + k8s_validator = CrdSectionsValidator(self._model_context) k8s_validator.validate_model(model_dict) self._logger.exiting(class_name=_class_name, method_name=_method_name) diff --git a/core/src/main/python/wlsdeploy/util/target_configuration.py b/core/src/main/python/wlsdeploy/util/target_configuration.py index 644c9bce7..4d653bfd2 100644 --- a/core/src/main/python/wlsdeploy/util/target_configuration.py +++ b/core/src/main/python/wlsdeploy/util/target_configuration.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2020, 2022, Oracle and/or its affiliates. +Copyright (c) 2020, 2023, Oracle and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ from wlsdeploy.exception import exception_helper @@ -32,9 +32,12 @@ # Determines if replica count is applied at the cluster level SET_CLUSTER_REPLICAS = "set_cluster_replicas" +# Determines the target product key. +PRODUCT_KEY = 'product_key' +DEFAULT_PRODUCT_KEY = 'wko' + # Determines the version of the target product. PRODUCT_VERSION = 'product_version' -DEFAULT_PRODUCT_VERSION = 'v3' # default for WKO and WKO in VZ # put secret tokens in the model, and build a script to create the secrets. SECRETS_METHOD = 'secrets' @@ -224,6 +227,16 @@ def sets_cluster_replicas(self): result = dictionary_utils.get_element(self.config_dictionary, SET_CLUSTER_REPLICAS) return result or False + def get_product_key(self): + """ + Return the key of the product being targeted, such as "wko" or "vz". + :return: the product key + """ + result = dictionary_utils.get_element(self.config_dictionary, PRODUCT_KEY) + if result is not None: + return result + return DEFAULT_PRODUCT_KEY + def get_product_version(self): """ Return the version of the product being targeted, such as WKO or VZ. @@ -232,7 +245,8 @@ def get_product_version(self): result = dictionary_utils.get_element(self.config_dictionary, PRODUCT_VERSION) if result is not None: return result - return DEFAULT_PRODUCT_VERSION + + return model_crd_helper.get_default_version(self.get_product_key()) def validate_configuration(self, exit_code, target_configuration_file): validation_method = self.get_validation_method() @@ -244,7 +258,7 @@ def validate_configuration(self, exit_code, target_configuration_file): target_configuration_file) product_version = self.get_product_version() - valid_product_versions = model_crd_helper.get_valid_versions(model_crd_helper.WKO_PRODUCT_KEY) + valid_product_versions = model_crd_helper.get_valid_versions(self.get_product_key()) self._validate_enumerated_field(PRODUCT_VERSION, product_version, valid_product_versions, exit_code, target_configuration_file) diff --git a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties index f74f89e42..1662fc2d2 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties +++ b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties @@ -512,7 +512,7 @@ WLSDPLY-05038=Expected a section with subfolders and attributes in model locatio WLSDPLY-05039=Expected a section with named subfolders in model location {0} WLSDPLY-05040=Expected a list of objects in model location {0} -# wlsdeploy/tool/validate/kubernetes_validator.py +# wlsdeploy/tool/validate/crd_sections_validator.py WLSDPLY-05090=Model folder {0} is not supported, will be skipped # wlsdeploy/tools/validate/validation_utils.py @@ -1223,8 +1223,8 @@ WLSDPLY-09701=In online WLST, unable to target resources from extension template WLSDPLY-10010=Failed to load WKO domain resource schema {0} WLSDPLY-10011=No {0} schema for WKO version {1}, available for version {2} -# extract_resource.py -WLSDPLY-10040=The {0} argument has been deprecated, use {1} to specify output directory +# model_crd_helper.py +WLSDPLY-10050=The folder {0} was not found in path {1} in schema {2} ############################################################################### # model help messages (10100 - 10199) # @@ -1244,6 +1244,7 @@ WLSDPLY-10109={0} is not a recognized top level section name. The recognized top WLSDPLY-10110=Model section {0} has no folder {1} beneath it. Valid folders are: {2} WLSDPLY-10111=Model folder {0} has no folder {1} beneath it. Valid folders are: {2} WLSDPLY-10112={0} encountered an error: {1} +WLSDPLY-10113=Model section {0} is not valid for the specified target ############################################################################### # create messages (12000 - 14999) # diff --git a/core/src/main/targetconfigs/vz-dii/target.json b/core/src/main/targetconfigs/vz-dii/target.json index e8f9ca7ae..bb7def788 100644 --- a/core/src/main/targetconfigs/vz-dii/target.json +++ b/core/src/main/targetconfigs/vz-dii/target.json @@ -6,6 +6,7 @@ }, "variable_injectors" : {"PORT": {},"HOST": {},"URL": {}}, "validation_method" : "lax", + "product_key": "vz", "domain_home_source_type" : "dii", "credentials_output_method" : "script", "exclude_domain_bin_contents": true, diff --git a/core/src/main/targetconfigs/vz-pv/target.json b/core/src/main/targetconfigs/vz-pv/target.json index 796311623..169ec0d67 100644 --- a/core/src/main/targetconfigs/vz-pv/target.json +++ b/core/src/main/targetconfigs/vz-pv/target.json @@ -6,6 +6,7 @@ }, "variable_injectors" : {"PORT": {},"HOST": {},"URL": {}}, "validation_method" : "lax", + "product_key": "vz", "domain_home_source_type" : "pv", "credentials_output_method" : "script", "exclude_domain_bin_contents": true, diff --git a/core/src/main/targetconfigs/vz/target.json b/core/src/main/targetconfigs/vz/target.json index 65186d445..c82a7d7af 100644 --- a/core/src/main/targetconfigs/vz/target.json +++ b/core/src/main/targetconfigs/vz/target.json @@ -7,6 +7,7 @@ }, "variable_injectors" : {"PORT": {},"HOST": {},"URL": {}}, "validation_method" : "lax", + "product_key": "vz", "domain_home_source_type" : "mii", "credentials_method" : "secrets", "credentials_output_method" : "script", diff --git a/core/src/test/python/wlsdeploy/tool/util/targets/kubernetes_schema_test.py b/core/src/test/python/wlsdeploy/tool/util/targets/kubernetes_schema_test.py index 16ebe5473..a26803ef3 100644 --- a/core/src/test/python/wlsdeploy/tool/util/targets/kubernetes_schema_test.py +++ b/core/src/test/python/wlsdeploy/tool/util/targets/kubernetes_schema_test.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2020, 2022, Oracle and/or its affiliates. +Copyright (c) 2020, 2023, Oracle and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ import os @@ -12,27 +12,30 @@ from wlsdeploy.tool.util.targets import schema_helper -class KubernetesSchemaTest(unittest.TestCase): - _model_dir = '../../unit-tests/wko' +class CrdSchemaTest(unittest.TestCase): + _model_dir = '../../unit-tests/crd-models' - def testKubernetesSchema(self): - self._testSchemas(model_crd_helper.WKO_VERSION_3) + def testWkoSchema(self): + self._testSchemas(model_crd_helper.WKO_PRODUCT_KEY, model_crd_helper.WKO_VERSION_3) - def testKubernetes4Schemas(self): - self._testSchemas(model_crd_helper.WKO_VERSION_4) + def testWko4Schemas(self): + self._testSchemas(model_crd_helper.WKO_PRODUCT_KEY, model_crd_helper.WKO_VERSION_4) - def _testSchemas(self, wko_version): + def testVerrazzanoSchemas(self): + self._testSchemas(model_crd_helper.VERRAZZANO_PRODUCT_KEY, model_crd_helper.VERRAZZANO_VERSION_1) + + def _testSchemas(self, product_key, product_version): # create a model with every element. # verify that there are no unknown types or structures. try: if not os.path.exists(self._model_dir): os.makedirs(self._model_dir) - file_path = self._model_dir + "/model-" + wko_version + ".yaml" + file_path = self._model_dir + "/" + product_key + "-" + product_version + ".yaml" self.out_file = open(file_path, "w") - self._write_line(KUBERNETES + ": # " + wko_version) + this_crd_helper = model_crd_helper.get_product_helper(product_key, product_version) + self._write_line(this_crd_helper.get_model_section() + ": # " + product_version) - this_crd_helper = model_crd_helper.get_product_helper(model_crd_helper.WKO_PRODUCT_KEY, wko_version) crd_folders = this_crd_helper.get_crd_folders() for crd_folder in crd_folders: indent = " " From 3484f012ed37b9bd794fdab0a62e0b84d4374064 Mon Sep 17 00:00:00 2001 From: Richard Killen Date: Thu, 19 Jan 2023 17:31:48 -0600 Subject: [PATCH 03/10] Merge Verrazzano model contents to CRD; added unit tests to verify --- .../tool/util/targets/crd_file_updater.py | 128 ++++++++++++++---- .../tool/util/targets/model_crd_helper.py | 5 + core/src/main/python/wlsdeploy/util/model.py | 11 +- ...pplication.yaml => vz-application-v1.yaml} | 43 +++--- .../util/targets/crd_file_updater_test.py | 68 ++++++++-- .../resources/{wko => crd}/k8s-model-v4.yaml | 18 ++- .../resources/{wko => crd}/k8s-model.yaml | 18 ++- core/src/test/resources/crd/vz-crd.yaml | 98 ++++++++++++++ core/src/test/resources/crd/vz-model.yaml | 67 +++++++++ .../resources/{wko => crd}/wko-domain-v4.yaml | 12 +- .../resources/{wko => crd}/wko-domain.yaml | 12 +- 11 files changed, 423 insertions(+), 57 deletions(-) rename core/src/main/targetconfigs/templates/{vz-application.yaml => vz-application-v1.yaml} (83%) rename core/src/test/resources/{wko => crd}/k8s-model-v4.yaml (57%) rename core/src/test/resources/{wko => crd}/k8s-model.yaml (55%) create mode 100644 core/src/test/resources/crd/vz-crd.yaml create mode 100644 core/src/test/resources/crd/vz-model.yaml rename core/src/test/resources/{wko => crd}/wko-domain-v4.yaml (78%) rename core/src/test/resources/{wko => crd}/wko-domain.yaml (72%) diff --git a/core/src/main/python/wlsdeploy/tool/util/targets/crd_file_updater.py b/core/src/main/python/wlsdeploy/tool/util/targets/crd_file_updater.py index aae564a20..50e84fbb8 100644 --- a/core/src/main/python/wlsdeploy/tool/util/targets/crd_file_updater.py +++ b/core/src/main/python/wlsdeploy/tool/util/targets/crd_file_updater.py @@ -34,9 +34,11 @@ REPLICAS = 'replicas' # specific to Verrazzano -COMPONENT_KIND = 'Component' +CONFIG_MAP_WORKLOAD_KIND = 'ConfigMap' +OAM_COMPONENT_KIND = 'Component' TEMPLATE = 'template' VERRAZZANO_WEBLOGIC_WORKLOAD_KIND = 'VerrazzanoWebLogicWorkload' +VERRAZZANO_APPLICATION_KIND = 'ApplicationConfiguration' WORKLOAD = 'workload' @@ -49,12 +51,13 @@ def update_from_model(crd_file, model, crd_helper): """ _method_name = 'update_from_model' - kubernetes_content = model.get_model_kubernetes() + model_section = crd_helper.get_model_section() + model_crd_content = dictionary_utils.get_dictionary_element(model.get_model(), model_section) # failures will be logged as severe, but not cause tool failure. # this will allow the unaltered output file to be examined for problems. - __logger.info('WLSDPLY-01675', crd_file, KUBERNETES, class_name=__class_name, method_name=_method_name) + __logger.info('WLSDPLY-01675', crd_file, model_section, class_name=__class_name, method_name=_method_name) try: reader = YamlToPython(crd_file.getPath(), True) @@ -64,7 +67,7 @@ def update_from_model(crd_file, model, crd_helper): method_name=_method_name) return - _update_documents(documents, kubernetes_content, crd_helper, crd_file.getPath()) + _update_documents(documents, model_crd_content, crd_helper, crd_file.getPath()) try: writer = PythonToYaml(documents) @@ -103,17 +106,13 @@ def _update_documents(crd_documents, model_content, crd_helper, output_file_path _add_cluster_comments(crd_document) found = True - # is this a Verrazzano WebLogic workload document? - elif kind == COMPONENT_KIND: - spec = dictionary_utils.get_dictionary_element(crd_document, SPEC) - workload = dictionary_utils.get_dictionary_element(spec, WORKLOAD) - component_kind = dictionary_utils.get_element(workload, KIND) - if component_kind == VERRAZZANO_WEBLOGIC_WORKLOAD_KIND: - component_spec = _get_or_create_dictionary(workload, SPEC) - component_template = _get_or_create_dictionary(component_spec, TEMPLATE) - _update_crd_domain(component_template, model_content, crd_helper, output_file_path) - _add_domain_comments(component_template) - found = True + elif kind == OAM_COMPONENT_KIND: + _update_crd_component(crd_document, model_content, crd_helper, output_file_path) + found = True + + elif kind == VERRAZZANO_APPLICATION_KIND: + _update_crd(crd_document, model_content, 'application', crd_helper, output_file_path) + found = True if not found: __logger.warning('WLSDPLY-01676', output_file_path, class_name=__class_name, method_name=_method_name) @@ -134,12 +133,7 @@ def _update_crd_domain(crd_dictionary, model_dictionary, crd_helper, output_file _update_dictionary(crd_dictionary, model_dictionary, schema, None, keyless_crd_folder, output_file_path) else: # this WKO version uses CRD sub-folders, use the domain folder - folder_key = 'domain' - domain_crd_folder = crd_helper.get_crd_folder(folder_key) - model_content = dictionary_utils.get_element(model_dictionary, folder_key) - if model_content: - schema = domain_crd_folder.get_schema() - _update_dictionary(crd_dictionary, model_content, schema, None, domain_crd_folder, output_file_path) + _update_crd(crd_dictionary, model_dictionary, 'domain', crd_helper, output_file_path) def _update_crd_cluster(crd_dictionary, model_dictionary, crd_helper, output_file_path): @@ -163,6 +157,46 @@ def _update_crd_cluster(crd_dictionary, model_dictionary, crd_helper, output_fil _update_dictionary(crd_dictionary, model_cluster, schema, None, cluster_crd_folder, output_file_path) +def _update_crd_component(crd_dictionary, model_dictionary, crd_helper, output_file_path): + """ + Update the CRD component dictionary from the model. + :param crd_dictionary: the CRD dictionary to be updated + :param model_dictionary: the model content to use for update + :param crd_helper: used to get CRD folder information + :param output_file_path: used for logging + """ + _method_name = '_update_crd_component' + + spec_folder = dictionary_utils.get_dictionary_element(crd_dictionary, SPEC) + workload_folder = dictionary_utils.get_dictionary_element(spec_folder, WORKLOAD) + workload_kind = dictionary_utils.get_element(workload_folder, KIND) + + if workload_kind == VERRAZZANO_WEBLOGIC_WORKLOAD_KIND: + _update_crd(crd_dictionary, model_dictionary, 'weblogic', crd_helper, output_file_path) + _add_weblogic_workload_comments(crd_dictionary) + + elif workload_kind == CONFIG_MAP_WORKLOAD_KIND: + _update_crd(crd_dictionary, model_dictionary, 'configmap', crd_helper, output_file_path) + + +def _update_crd(crd_dictionary, model_dictionary, folder_key, crd_helper, output_file_path): + """ + Update the CRD dictionary for folder_key from the model. + :param crd_dictionary: the CRD dictionary to be updated + :param model_dictionary: the model content to use for update + :param folder_key: the model key for the CRD section subfolder + :param crd_helper: used to get CRD folder information + :param output_file_path: used for logging + """ + _method_name = '_update_crd' + + domain_crd_folder = crd_helper.get_crd_folder(folder_key) + model_content = dictionary_utils.get_element(model_dictionary, folder_key) + if model_content: + schema = domain_crd_folder.get_schema() + _update_dictionary(crd_dictionary, model_content, schema, None, domain_crd_folder, output_file_path) + + def _find_model_cluster(crd_name, model_clusters): for model_cluster in model_clusters: model_name = _get_cluster_name(model_cluster) @@ -265,15 +299,32 @@ def _find_object_match(item, match_list, schema_path, model_crd_folder): :return: a matching dictionary object """ key = model_crd_folder.get_object_list_key(schema_path) - item_key = item[key] + item_key = _get_key_value(item, key) if item_key: for match_item in match_list: if isinstance(match_item, dict): - if item_key == match_item[key]: + if item_key == _get_key_value(match_item, key): return match_item return None +def _get_key_value(item, key): + """ + Return the value for the specified key in the specified item object. + The key may be nested, such as spec/clusterName. + :param item: the item to be examined + :param key: the key to be evaluated + :return: the value if found, otherwise None + """ + key_parts = key.split('/') + key_folders = key_parts[:-1] + match_key = key_parts[-1] + match_folder = item + for key_folder in key_folders: + match_folder = dictionary_utils.get_dictionary_element(match_folder, key_folder) + return dictionary_utils.get_element(match_folder, match_key) + + def _convert_value(model_value, type_name): """ Convert the specified model value to match the schema type for the domain resource file. @@ -322,11 +373,36 @@ def _add_cluster_comments(wko_dictionary): :param wko_dictionary: the WKO dictionary containing metadata, spec, etc. """ spec = dictionary_utils.get_dictionary_element(wko_dictionary, SPEC) - cluster_keys = spec.keys() + _add_cluster_spec_comments(spec) + + +def _add_cluster_spec_comments(spec_dictionary): + """ + Add relevant comments to a cluster spec dictionary to provide additional information. + :param spec_dictionary: the spec dictionary containing cluster attributes + """ + cluster_keys = spec_dictionary.keys() if CLUSTER_NAME in cluster_keys and REPLICAS not in cluster_keys: - last_key = spec.keys()[-1] + last_key = spec_dictionary.keys()[-1] message = exception_helper.get_message('WLSDPLY-01680') - spec.addComment(last_key, REPLICAS + ': 99 # ' + message) + spec_dictionary.addComment(last_key, REPLICAS + ': 99 # ' + message) + + +def _add_weblogic_workload_comments(vz_dictionary): + """ + Add relevant comments to the Verrazzano WebLogic workload CRD dictionary for additional information. + :param vz_dictionary: the Verrazzano dictionary + """ + spec_folder = dictionary_utils.get_dictionary_element(vz_dictionary, SPEC) + workload_folder = dictionary_utils.get_dictionary_element(spec_folder, WORKLOAD) + workload_spec_folder = dictionary_utils.get_dictionary_element(workload_folder, SPEC) + + template_folder = dictionary_utils.get_dictionary_element(workload_spec_folder, TEMPLATE) + _add_domain_comments(template_folder) + + clusters_folder = dictionary_utils.get_dictionary_element(workload_spec_folder, CLUSTERS) + for cluster_spec in clusters_folder: + _add_cluster_spec_comments(cluster_spec) def _get_or_create_dictionary(dictionary, key): diff --git a/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py b/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py index 37af34fae..9f0569e87 100644 --- a/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py +++ b/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py @@ -103,12 +103,17 @@ def get_product_helper(product_key, product_version, exception_type=ExceptionTyp application_schema = schema_helper.get_schema(VZ_1_APPLICATION_SCHEMA_NAME, exception_type) application_folder = ModelCrdFolder("application", application_schema, False) + application_folder.add_object_list_key('spec/components', 'componentName') helper.add_crd_folder(application_folder) weblogic_schema_name = VZ_1_WEBLOGIC_SCHEMA_NAME weblogic_schema = schema_helper.get_schema(weblogic_schema_name, exception_type) _update_weblogic_schema(weblogic_schema, weblogic_schema_name, exception_type) weblogic_folder = ModelCrdFolder("weblogic", weblogic_schema, False) + weblogic_folder.add_object_list_key('spec/workload/spec/clusters', 'spec/clusterName') + weblogic_folder.add_object_list_key('spec/workload/spec/template/spec/adminServer/adminService/channels', + 'channelName') + weblogic_folder.add_object_list_key('spec/workload/spec/template/spec/managedServers', 'serverName') helper.add_crd_folder(weblogic_folder) configmap_schema = schema_helper.get_schema(VZ_1_CONFIGMAP_SCHEMA_NAME, exception_type) diff --git a/core/src/main/python/wlsdeploy/util/model.py b/core/src/main/python/wlsdeploy/util/model.py index 395d3f606..aac35132e 100644 --- a/core/src/main/python/wlsdeploy/util/model.py +++ b/core/src/main/python/wlsdeploy/util/model.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2017, 2022, Oracle Corporation and/or its affiliates. +Copyright (c) 2017, 2023, Oracle Corporation and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. This module serves as a wrapper for the model dictionary. @@ -11,6 +11,7 @@ import oracle.weblogic.deploy.util.PyOrderedDict as OrderedDict from wlsdeploy.aliases.model_constants import KNOWN_TOPLEVEL_MODEL_SECTIONS from wlsdeploy.aliases.model_constants import KUBERNETES +from wlsdeploy.aliases.model_constants import VERRAZZANO from wlsdeploy.logging.platform_logger import PlatformLogger from wlsdeploy.util.weblogic_helper import WebLogicHelper @@ -29,6 +30,7 @@ def __init__(self, model_dictionary=None, wls_version=None): self._deployments = OrderedDict() self._domain_info = OrderedDict() self._kubernetes = OrderedDict() + self._verrazzano = OrderedDict() if model_dictionary is not None: if 'topology' in model_dictionary: @@ -46,6 +48,9 @@ def __init__(self, model_dictionary=None, wls_version=None): if KUBERNETES in model_dictionary: self._kubernetes = model_dictionary[KUBERNETES] + if VERRAZZANO in model_dictionary: + self._verrazzano = model_dictionary[VERRAZZANO] + def get_model_resources(self): """ Get the resources section of the model. @@ -95,6 +100,10 @@ def get_model(self): model['resources'] = self._resources if len(self._deployments) > 0: model['appDeployments'] = self._deployments + if len(self._kubernetes) > 0: + model[KUBERNETES] = self._kubernetes + if len(self._verrazzano) > 0: + model[VERRAZZANO] = self._verrazzano return model def log_model(self, level, message, method_name, class_name='Model'): diff --git a/core/src/main/targetconfigs/templates/vz-application.yaml b/core/src/main/targetconfigs/templates/vz-application-v1.yaml similarity index 83% rename from core/src/main/targetconfigs/templates/vz-application.yaml rename to core/src/main/targetconfigs/templates/vz-application-v1.yaml index c78b85c8a..fe27c928b 100644 --- a/core/src/main/targetconfigs/templates/vz-application.yaml +++ b/core/src/main/targetconfigs/templates/vz-application-v1.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2022, Oracle and/or its affiliates. +# Copyright (c) 2022, 2023, Oracle and/or its affiliates. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. apiVersion: core.oam.dev/v1alpha2 @@ -88,23 +88,7 @@ spec: clusters: {{/hasClusters}} {{#clusters}} - - clusterName: {{{clusterName}}} - serverPod: - affinity: - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 100 - podAffinityTerm: - labelSelector: - matchExpressions: - - key: "weblogic.clusterName" - operator: In - values: - - $(CLUSTER_NAME) - topologyKey: "kubernetes.io/hostname" -{{#setClusterReplicas}} - replicas: {{{replicas}}} -{{/setClusterReplicas}} + - name: {{{clusterName}}} {{/clusters}} serverPod: @@ -124,6 +108,29 @@ spec: - mountPath: /shared name: weblogic-domain-storage-volume {{/usePersistentVolume}} +{{#hasClusters}} + + clusters: +{{/hasClusters}} +{{#clusters}} + - clusterName: {{{clusterName}}} + serverPod: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: "weblogic.clusterName" + operator: In + values: + - $(CLUSTER_NAME) + topologyKey: "kubernetes.io/hostname" +{{#setClusterReplicas}} + replicas: {{{replicas}}} +{{/setClusterReplicas}} +{{/clusters}} --- apiVersion: core.oam.dev/v1alpha2 kind: Component diff --git a/core/src/test/python/wlsdeploy/tool/util/targets/crd_file_updater_test.py b/core/src/test/python/wlsdeploy/tool/util/targets/crd_file_updater_test.py index d55f3c09a..58aba1078 100644 --- a/core/src/test/python/wlsdeploy/tool/util/targets/crd_file_updater_test.py +++ b/core/src/test/python/wlsdeploy/tool/util/targets/crd_file_updater_test.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2022, Oracle and/or its affiliates. +Copyright (c) 2022, 2023, Oracle and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ import os @@ -18,8 +18,8 @@ class CrdFileUpdaterTest(BaseTestCase): def __init__(self, *args): BaseTestCase.__init__(self, *args) - self.MODELS_DIR = os.path.join(self.TEST_CLASSES_DIR, 'wko') - self.OUTPUT_DIR = os.path.join(self.TEST_OUTPUT_DIR, 'wko') + self.MODELS_DIR = os.path.join(self.TEST_CLASSES_DIR, 'crd') + self.OUTPUT_DIR = os.path.join(self.TEST_OUTPUT_DIR, 'crd') def setUp(self): BaseTestCase.setUp(self) @@ -30,7 +30,8 @@ def test_crd_file_updater(self): Test that kubernetes section of the model is merged into the domain resource file correctly. """ - documents = self._merge_and_read('k8s-model.yaml', 'wko-domain.yaml', model_crd_helper.WKO_VERSION_3) + documents = self._merge_and_read('k8s-model.yaml', 'wko-domain.yaml', + model_crd_helper.WKO_PRODUCT_KEY, model_crd_helper.WKO_VERSION_3) self._match_values("Document count", len(documents), 1) domain_resource = documents[0] @@ -50,7 +51,8 @@ def test_crd_file_updater_v4(self): Test that kubernetes section of the model is merged into the domain resource file correctly. """ - documents = self._merge_and_read('k8s-model-v4.yaml', 'wko-domain-v4.yaml', model_crd_helper.WKO_VERSION_4) + documents = self._merge_and_read('k8s-model-v4.yaml', 'wko-domain-v4.yaml', + model_crd_helper.WKO_PRODUCT_KEY, model_crd_helper.WKO_VERSION_4) self._match_values("Document count", len(documents), 4) domain_resource = documents[0] @@ -67,14 +69,64 @@ def test_crd_file_updater_v4(self): replica_count = self._traverse(cluster_resource, 'spec', 'replicas') self._match_values("First cluster replicas", replica_count, 999) + def test_verrazzano_crd_update(self): + """ + Test that verrazzano section of the model is merged into the + resource file correctly. + """ + documents = self._merge_and_read('vz-model.yaml', 'vz-crd.yaml', + model_crd_helper.VERRAZZANO_PRODUCT_KEY, + model_crd_helper.VERRAZZANO_VERSION_1) + self._match_values("Document count", len(documents), 3) + + # application document + application_resource = documents[0] + # two existing components, one added, one merged + component_list = self._traverse(application_resource, 'spec', 'components') + self._match_values("Application component count", len(component_list), 3) + + # weblogic document + weblogic_resource = documents[1] + domain_resource = self._traverse(weblogic_resource, 'spec', 'workload', 'spec', 'template') + + # check simple fields + self._check_domain_crd(domain_resource) + + # only one cluster was added + cluster_list = self._traverse(domain_resource, 'spec', 'clusters') + self._match_values("Domain cluster count", len(cluster_list), 3) + self._match_values("Third domain cluster name", cluster_list[2]['name'], 'cluster3') + + # workload clusters section + cluster_resource = self._traverse(weblogic_resource, 'spec', 'workload', 'spec', 'clusters') + self._match_values("Cluster count", len(cluster_resource), 3) + self._match_values("Third cluster name", cluster_resource[2]['spec']['clusterName'], 'cluster3') + self._match_values("Third cluster replicas", cluster_resource[2]['spec']['replicas'], 1103) + + # configmap document + configmap_resource = documents[2] + data_map = self._traverse(configmap_resource, 'spec', 'workload', 'data') + self._match_values("Data count", len(data_map), 2) + self._match_values("Second data value", data_map['test.yaml'], 'alsoModel') + def _check_domain_crd(self, domain_resource): # domain home was overridden domain_home = self._traverse(domain_resource, 'spec', 'domainHome') self._match_values("Domain home", domain_home, "modelHome") + # only one adminServer/adminServer/channels was added + channel_list = self._traverse(domain_resource, 'spec', 'adminServer', 'adminService', 'channels') + self._match_values("Channel count", len(channel_list), 2) + self._match_values("Second channel", channel_list[1]['channelName'], 'channel-2') + + # only one managedServers was added + server_list = self._traverse(domain_resource, 'spec', 'managedServers') + self._match_values("Server count", len(server_list), 2) + self._match_values("Second server", server_list[1]['serverName'], 'server-2') + # only one secret was added secret_list = self._traverse(domain_resource, 'spec', 'configuration', 'secrets') - self._match_values("Cluster count", len(secret_list), 3) + self._match_values("Secret count", len(secret_list), 3) self._match_values("Third secret", secret_list[2], 'secret-three') # only one env was added @@ -85,7 +137,7 @@ def _check_domain_crd(self, domain_resource): # value of the first env was overridden self._match_values("First env value", env_list[0]['value'], '-DfromModel') - def _merge_and_read(self, model_name, crd_name, wko_version): + def _merge_and_read(self, model_name, crd_name, product_key, product_version): """ Merge the specified model to the specified CRD, then read and return the result. """ @@ -99,7 +151,7 @@ def _merge_and_read(self, model_name, crd_name, wko_version): output_file = os.path.join(self.OUTPUT_DIR, crd_name) shutil.copyfile(source_file, output_file) - crd_helper = model_crd_helper.get_product_helper(model_crd_helper.WKO_PRODUCT_KEY, wko_version) + crd_helper = model_crd_helper.get_product_helper(product_key, product_version) crd_file_updater.update_from_model(File(output_file), model, crd_helper) # re-read the output file diff --git a/core/src/test/resources/wko/k8s-model-v4.yaml b/core/src/test/resources/crd/k8s-model-v4.yaml similarity index 57% rename from core/src/test/resources/wko/k8s-model-v4.yaml rename to core/src/test/resources/crd/k8s-model-v4.yaml index 19d435bc1..ab4eec9e1 100644 --- a/core/src/test/resources/wko/k8s-model-v4.yaml +++ b/core/src/test/resources/crd/k8s-model-v4.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2022, Oracle and/or its affiliates. +# Copyright (c) 2022, 2023, Oracle and/or its affiliates. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. kubernetes: @@ -7,6 +7,15 @@ kubernetes: # override this domainHome: modelHome + adminServer: + adminService: + # merge should occur based on channelName + channels: + - channelName: channel-1 # should merge with existing + nodePort: 1101 + - channelName: channel-2 # should be added + nodePort: 1102 + clusters: # should merge cluster1 and add cluster3, based on key "clusterName" - name: cluster1 @@ -18,6 +27,13 @@ kubernetes: - secret-one - secret-three + # merge should occur based on serverName + managedServers: + - serverName: server-1 # should merge with existing + restartVersion: restart-1-model + - serverName: server-2 # should be added + restartVersion: restart-2-model + serverPod: env: # should merge JAVA_OPTIONS and add FROM_MODEL, based on default key "name" diff --git a/core/src/test/resources/wko/k8s-model.yaml b/core/src/test/resources/crd/k8s-model.yaml similarity index 55% rename from core/src/test/resources/wko/k8s-model.yaml rename to core/src/test/resources/crd/k8s-model.yaml index c48f21640..f3ea8d5c5 100644 --- a/core/src/test/resources/wko/k8s-model.yaml +++ b/core/src/test/resources/crd/k8s-model.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2022, Oracle and/or its affiliates. +# Copyright (c) 2022, 2023, Oracle and/or its affiliates. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. kubernetes: @@ -6,6 +6,15 @@ kubernetes: # override this domainHome: modelHome + adminServer: + adminService: + # merge should occur based on channelName + channels: + - channelName: channel-1 # should merge with existing + nodePort: 1101 + - channelName: channel-2 # should be added + nodePort: 1102 + clusters: # should merge cluster1 and add cluster3, based on key "clusterName" - clusterName: cluster1 @@ -19,6 +28,13 @@ kubernetes: - secret-one - secret-three + # merge should occur based on serverName + managedServers: + - serverName: server-1 # should merge with existing + restartVersion: restart-1-model + - serverName: server-2 # should be added + restartVersion: restart-2-model + serverPod: env: # should merge JAVA_OPTIONS and add FROM_MODEL, based on default key "name" diff --git a/core/src/test/resources/crd/vz-crd.yaml b/core/src/test/resources/crd/vz-crd.yaml new file mode 100644 index 000000000..ebf09a6d5 --- /dev/null +++ b/core/src/test/resources/crd/vz-crd.yaml @@ -0,0 +1,98 @@ +# Copyright (c) 2023, Oracle and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +apiVersion: weblogic.oracle/v8 +kind: ApplicationConfiguration +metadata: + name: demodomain + namespace: demodomain +spec: + components: + - componentName: demodomain-domain + traits: + - trait: + apiVersion: oam.verrazzano.io/v1alpha1 + kind: MetricsTrait + spec: + scraper: verrazzano-system/vmi-system-prometheus-0 + - trait: + apiVersion: oam.verrazzano.io/v1alpha1 + kind: IngressTrait + spec: + rules: + - paths: + - path: "myApp" + pathType: Prefix + - componentName: demodomain-configmap +--- +apiVersion: core.oam.dev/v1alpha2 +kind: Component +metadata: + name: demodomain-domain + namespace: demodomain +spec: + workload: + apiVersion: oam.verrazzano.io/v1alpha1 + kind: VerrazzanoWebLogicWorkload + spec: + template: + metadata: + name: demodomain-domain + namespace: demodomain + spec: + domainHome: --FIX ME-- + + adminServer: + adminService: + channels: + - channelName: channel-1 + nodePort: 1001 + + clusters: + - name: cluster1 + - name: cluster2 + + configuration: + secrets: + - secret-one + - secret-two + + managedServers: + - serverName: server-1 + restartVersion: restart-1 + + serverPod: + env: + - name: JAVA_OPTIONS + value: "-Dweblogic.StdoutDebugEnabled=false" + - name: USER_MEM_ARGS + value: "-Djava.security.egd=file:/dev/./urandom -Xms64m -Xmx256m " + clusters: + - spec: + clusterName: cluster1 + replicas: 1001 + - spec: + clusterName: cluster2 + replicas: 1002 +--- +apiVersion: core.oam.dev/v1alpha2 +kind: Component +metadata: + name: demodomain-configmap + namespace: demodomain +spec: + workload: + apiVersion: v1 + kind: ConfigMap + metadata: + name: demodomain-configmap + namespace: demodomain + data: + wdt_jdbc.yaml: | + resources: + JDBCSystemResource: + myDs: + JdbcResource: + JDBCDriverParams: + # This is the URL of the database used by the WebLogic Server application + URL: http://mydb diff --git a/core/src/test/resources/crd/vz-model.yaml b/core/src/test/resources/crd/vz-model.yaml new file mode 100644 index 000000000..57645e745 --- /dev/null +++ b/core/src/test/resources/crd/vz-model.yaml @@ -0,0 +1,67 @@ +# Copyright (c) 2023, Oracle and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +verrazzano: + application: + spec: + components: + - componentName: demodomain-domain # should merge with existing component + - componentName: demodomain-from-model # should add this component + + weblogic: + spec: + workload: + spec: + template: + spec: + # simple override + domainHome: modelHome + + adminServer: + adminService: + # merge should occur based on channelName + channels: + - channelName: channel-1 # should merge with existing + nodePort: 1101 + - channelName: channel-2 # should be added + nodePort: 1102 + + clusters: + - name: cluster1 # should merge with existing + - name: cluster3 # should be added + + configuration: + secrets: + - secret-one # should merge with existing + - secret-three # should be added + + # merge should occur based on serverName + managedServers: + - serverName: server-1 # should merge with existing + restartVersion: restart-1-model + - serverName: server-2 # should be added + restartVersion: restart-2-model + + serverPod: + env: + # should merge JAVA_OPTIONS and add FROM_MODEL, based on default key "name" + - name: JAVA_OPTIONS + value: '-DfromModel' + - name: FROM_MODEL + value: '-DfromModel' + + # merge should occur based on spec/clusterName + clusters: + - spec: + clusterName: cluster1 # should merge with existing + replicas: 1101 + - spec: + clusterName: cluster3 # should be added + replicas: 1103 + + configmap: + spec: + workload: + data: + wdt_jdbc.yaml: fromModel # should merge with existing + test.yaml: alsoModel # should be added diff --git a/core/src/test/resources/wko/wko-domain-v4.yaml b/core/src/test/resources/crd/wko-domain-v4.yaml similarity index 78% rename from core/src/test/resources/wko/wko-domain-v4.yaml rename to core/src/test/resources/crd/wko-domain-v4.yaml index 74948690d..6712f3a44 100644 --- a/core/src/test/resources/wko/wko-domain-v4.yaml +++ b/core/src/test/resources/crd/wko-domain-v4.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2022, Oracle and/or its affiliates. +# Copyright (c) 2022, 2023, Oracle and/or its affiliates. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. apiVersion: weblogic.oracle/v8 @@ -8,6 +8,12 @@ metadata: spec: domainHome: --FIX ME-- + adminServer: + adminService: + channels: + - channelName: channel-1 + nodePort: 1001 + # a list of objects clusters: - name: cluster1 @@ -19,6 +25,10 @@ spec: - secret-one - secret-two + managedServers: + - serverName: server-1 + restartVersion: restart-1 + serverPod: # a list of objects env: diff --git a/core/src/test/resources/wko/wko-domain.yaml b/core/src/test/resources/crd/wko-domain.yaml similarity index 72% rename from core/src/test/resources/wko/wko-domain.yaml rename to core/src/test/resources/crd/wko-domain.yaml index eaa1a535f..8148e5ee2 100644 --- a/core/src/test/resources/wko/wko-domain.yaml +++ b/core/src/test/resources/crd/wko-domain.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2022, Oracle and/or its affiliates. +# Copyright (c) 2022, 2023, Oracle and/or its affiliates. # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. apiVersion: weblogic.oracle/v8 @@ -8,6 +8,12 @@ metadata: spec: domainHome: --FIX ME-- + adminServer: + adminService: + channels: + - channelName: channel-1 + nodePort: 1001 + # a list of objects clusters: - clusterName: cluster1 @@ -21,6 +27,10 @@ spec: - secret-one - secret-two + managedServers: + - serverName: server-1 + restartVersion: restart-1 + serverPod: # a list of objects env: From bc302b9bc90ac09041e1fb0900e7e30d09879d12 Mon Sep 17 00:00:00 2001 From: Richard Killen Date: Fri, 20 Jan 2023 15:27:03 -0600 Subject: [PATCH 04/10] Add ability for multiple object formats in CRD schemas; renamed schema files --- .../tool/util/targets/model_crd_helper.py | 2 +- .../tool/util/targets/schema_helper.py | 6 +- .../deploy/crds/vz-application-v1alpha1.json | 1166 +++++++++++++++++ .../deploy/crds/vz-application-v1alpha2.json | 1 - .../deploy/crds/vz-configmap-v1alpha1.json | 384 ++++++ .../deploy/crds/vz-configmap-v1alpha2.json | 1 - .../deploy/crds/vz-weblogic-v1alpha1.json | 197 +++ .../deploy/crds/vz-weblogic-v1alpha2.json | 1 - ...etes_schema_test.py => crd_schema_test.py} | 19 +- 9 files changed, 1771 insertions(+), 6 deletions(-) create mode 100644 core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha1.json delete mode 100644 core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha2.json create mode 100644 core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha1.json delete mode 100644 core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha2.json create mode 100644 core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha1.json delete mode 100644 core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha2.json rename core/src/test/python/wlsdeploy/tool/util/targets/{kubernetes_schema_test.py => crd_schema_test.py} (86%) diff --git a/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py b/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py index 9f0569e87..15b13e056 100644 --- a/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py +++ b/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py @@ -25,7 +25,7 @@ VZ_APPLICATION_SCHEMA_NAME = 'vz-application' VZ_CONFIGMAP_SCHEMA_NAME = 'vz-configmap' VZ_WEBLOGIC_SCHEMA_NAME = 'vz-weblogic' -VZ_1_SCHEMA_SUFFIX = '-v1alpha2' +VZ_1_SCHEMA_SUFFIX = '-v1alpha1' VZ_1_APPLICATION_SCHEMA_NAME = VZ_APPLICATION_SCHEMA_NAME + VZ_1_SCHEMA_SUFFIX VZ_1_CONFIGMAP_SCHEMA_NAME = VZ_CONFIGMAP_SCHEMA_NAME + VZ_1_SCHEMA_SUFFIX VZ_1_WEBLOGIC_SCHEMA_NAME = VZ_WEBLOGIC_SCHEMA_NAME + VZ_1_SCHEMA_SUFFIX diff --git a/core/src/main/python/wlsdeploy/tool/util/targets/schema_helper.py b/core/src/main/python/wlsdeploy/tool/util/targets/schema_helper.py index c6b0670ef..18d6d2c7a 100644 --- a/core/src/main/python/wlsdeploy/tool/util/targets/schema_helper.py +++ b/core/src/main/python/wlsdeploy/tool/util/targets/schema_helper.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2020, 2022, Oracle and/or its affiliates. +Copyright (c) 2020, 2023, Oracle and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ from oracle.weblogic.deploy.util import FileUtils @@ -159,6 +159,10 @@ def get_enum_values(schema_map): return dictionary_utils.get_element(schema_map, 'enum') +def get_one_of_options(schema_map): + return dictionary_utils.get_dictionary_element(schema_map, 'oneOf') + + def is_unsupported_folder(path): return path in UNSUPPORTED_FOLDERS diff --git a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha1.json b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha1.json new file mode 100644 index 000000000..78bda4f5c --- /dev/null +++ b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha1.json @@ -0,0 +1,1166 @@ +{ + "openAPIV3Schema" : { + "description" : "An ApplicationConfiguration represents an OAM application.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type" : "string" + }, + "kind" : { + "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type" : "string" + }, + "metadata" : { + "type" : "object" + }, + "spec" : { + "description" : "An ApplicationConfigurationSpec defines the desired state of a ApplicationConfiguration.", + "properties" : { + "components" : { + "description" : "Components of which this ApplicationConfiguration consists. Each component will be used to instantiate a workload.", + "items" : { + "description" : "An ApplicationConfigurationComponent specifies a component of an ApplicationConfiguration. Each component is used to instantiate a workload.", + "properties" : { + "componentName" : { + "description" : "ComponentName specifies a component whose latest revision will be bind with ApplicationConfiguration. When the spec of the referenced component changes, ApplicationConfiguration will automatically migrate all trait affect from the prior revision to the new one. This is mutually exclusive with RevisionName.", + "type" : "string" + }, + "dataInputs" : { + "description" : "DataInputs specify the data input sinks into this component.", + "items" : { + "description" : "DataInput specifies a data input sink to an object. If input is array, it will be appended to the target field paths.", + "properties" : { + "toFieldPaths" : { + "description" : "ToFieldPaths specifies the field paths of an object to fill passed value.", + "items" : { + "type" : "string" + }, + "type" : "array" + }, + "valueFrom" : { + "description" : "ValueFrom specifies the value source.", + "properties" : { + "dataOutputName" : { + "description" : "DataOutputName matches a name of a DataOutput in the same AppConfig.", + "type" : "string" + } + }, + "required" : [ "dataOutputName" ], + "type" : "object" + } + }, + "type" : "object" + }, + "type" : "array" + }, + "dataOutputs" : { + "description" : "DataOutputs specify the data output sources from this component.", + "items" : { + "description" : "DataOutput specifies a data output source from an object.", + "properties" : { + "conditions" : { + "description" : "Conditions specify the conditions that should be satisfied before emitting a data output. Different conditions are AND-ed together. If no conditions is specified, it is by default to check output value not empty.", + "items" : { + "description" : "ConditionRequirement specifies the requirement to match a value.", + "properties" : { + "fieldPath" : { + "description" : "FieldPath specifies got value from workload/trait object", + "type" : "string" + }, + "op" : { + "description" : "ConditionOperator specifies the operator to match a value.", + "type" : "string" + }, + "value" : { + "description" : "Value specifies an expected value This is mutually exclusive with ValueFrom", + "type" : "string" + }, + "valueFrom" : { + "description" : "ValueFrom specifies expected value from AppConfig This is mutually exclusive with Value", + "properties" : { + "fieldPath" : { + "type" : "string" + } + }, + "required" : [ "fieldPath" ], + "type" : "object" + } + }, + "required" : [ "op" ], + "type" : "object" + }, + "type" : "array" + }, + "fieldPath" : { + "description" : "FieldPath refers to the value of an object's field.", + "type" : "string" + }, + "name" : { + "description" : "Name is the unique name of a DataOutput in an ApplicationConfiguration.", + "type" : "string" + } + }, + "type" : "object" + }, + "type" : "array" + }, + "parameterValues" : { + "description" : "ParameterValues specify values for the the specified component's parameters. Any parameter required by the component must be specified.", + "items" : { + "description" : "A ComponentParameterValue specifies a value for a named parameter. The associated component must publish a parameter with this name.", + "properties" : { + "name" : { + "description" : "Name of the component parameter to set.", + "type" : "string" + }, + "value" : { + "anyOf" : [ { + "type" : "integer" + }, { + "type" : "string" + } ], + "description" : "Value to set.", + "x-kubernetes-int-or-string" : true + } + }, + "required" : [ "name", "value" ], + "type" : "object" + }, + "type" : "array" + }, + "revisionName" : { + "description" : "RevisionName of a specific component revision to which to bind ApplicationConfiguration. This is mutually exclusive with componentName.", + "type" : "string" + }, + "scopes" : { + "description" : "Scopes in which the specified component should exist.", + "items" : { + "description" : "A ComponentScope specifies a scope in which a component should exist.", + "properties" : { + "scopeRef" : { + "description" : "A ScopeReference must refer to an OAM scope resource.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + } + }, + "required" : [ "scopeRef" ], + "type" : "object" + }, + "type" : "array" + }, + "traits" : { + "description" : "Traits of the specified component.", + "items" : { + "description" : "A ComponentTrait specifies a trait that should be applied to a component.", + "properties" : { + "dataInputs" : { + "description" : "DataInputs specify the data input sinks into this trait.", + "items" : { + "description" : "DataInput specifies a data input sink to an object. If input is array, it will be appended to the target field paths.", + "properties" : { + "toFieldPaths" : { + "description" : "ToFieldPaths specifies the field paths of an object to fill passed value.", + "items" : { + "type" : "string" + }, + "type" : "array" + }, + "valueFrom" : { + "description" : "ValueFrom specifies the value source.", + "properties" : { + "dataOutputName" : { + "description" : "DataOutputName matches a name of a DataOutput in the same AppConfig.", + "type" : "string" + } + }, + "required" : [ "dataOutputName" ], + "type" : "object" + } + }, + "type" : "object" + }, + "type" : "array" + }, + "dataOutputs" : { + "description" : "DataOutputs specify the data output sources from this trait.", + "items" : { + "description" : "DataOutput specifies a data output source from an object.", + "properties" : { + "conditions" : { + "description" : "Conditions specify the conditions that should be satisfied before emitting a data output. Different conditions are AND-ed together. If no conditions is specified, it is by default to check output value not empty.", + "items" : { + "description" : "ConditionRequirement specifies the requirement to match a value.", + "properties" : { + "fieldPath" : { + "description" : "FieldPath specifies got value from workload/trait object", + "type" : "string" + }, + "op" : { + "description" : "ConditionOperator specifies the operator to match a value.", + "type" : "string" + }, + "value" : { + "description" : "Value specifies an expected value This is mutually exclusive with ValueFrom", + "type" : "string" + }, + "valueFrom" : { + "description" : "ValueFrom specifies expected value from AppConfig This is mutually exclusive with Value", + "properties" : { + "fieldPath" : { + "type" : "string" + } + }, + "required" : [ "fieldPath" ], + "type" : "object" + } + }, + "required" : [ "op" ], + "type" : "object" + }, + "type" : "array" + }, + "fieldPath" : { + "description" : "FieldPath refers to the value of an object's field.", + "type" : "string" + }, + "name" : { + "description" : "Name is the unique name of a DataOutput in an ApplicationConfiguration.", + "type" : "string" + } + }, + "type" : "object" + }, + "type" : "array" + }, + "trait" : { + "description" : "A Trait that will be created for the component", + "oneOf" : [ { + "description" : "IngressTrait specifies the ingress traits API.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type" : "string" + }, + "kind" : { + "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type" : "string" + }, + "metadata" : { + "type" : "object" + }, + "spec" : { + "description" : "IngressTraitSpec specifies the desired state of an ingress trait.", + "properties" : { + "rules" : { + "description" : "A list of ingress rules for an ingress trait.", + "items" : { + "description" : "IngressRule specifies a rule for an ingress trait.", + "properties" : { + "destination" : { + "description" : "The destination host and port for the ingress paths.", + "properties" : { + "host" : { + "description" : "Destination host.", + "type" : "string" + }, + "httpCookie" : { + "description" : "Session affinity cookie.", + "properties" : { + "name" : { + "description" : "The name of the HTTP cookie.", + "type" : "string" + }, + "path" : { + "description" : "The path of the HTTP cookie.", + "type" : "string" + }, + "ttl" : { + "description" : "The lifetime of the HTTP cookie (in seconds).", + "format" : "int64", + "type" : "integer" + } + }, + "type" : "object" + }, + "port" : { + "description" : "Destination port.", + "format" : "int32", + "type" : "integer" + } + }, + "type" : "object" + }, + "hosts" : { + "description" : "One or more hosts exposed by the ingress trait. Wildcard hosts or hosts that are empty are filtered out. If there are no valid hosts provided, then a DNS host name is automatically generated and used.", + "items" : { + "type" : "string" + }, + "type" : "array" + }, + "paths" : { + "description" : "The paths to be exposed for an ingress trait.", + "items" : { + "description" : "IngressPath specifies a specific path to be exposed for an ingress trait.", + "properties" : { + "authorizationPolicy" : { + "description" : "Defines the set of rules for authorizing a request.", + "properties" : { + "rules" : { + "description" : "Rules are used to match requests from request principals to specific paths given an optional list of conditions.", + "items" : { + "description" : "AuthorizationRule matches requests from a list of request principals that access a specific path subject to a list of conditions.", + "properties" : { + "from" : { + "description" : "Specifies the request principals for access to a request. An asterisk (*) will match when the value is not empty, for example, if any request principal is found in the request.", + "properties" : { + "requestPrincipals" : { + "description" : "Specifies the request principals for access to a request.", + "items" : { + "type" : "string" + }, + "type" : "array" + } + }, + "type" : "object" + }, + "when" : { + "description" : "Specifies a list of additional conditions for access to a request.", + "items" : { + "description" : "AuthorizationRuleCondition provides additional required attributes for authorization.", + "properties" : { + "key" : { + "description" : "The name of a request attribute.", + "type" : "string" + }, + "values" : { + "description" : "A list of allowed values for the attribute.", + "items" : { + "type" : "string" + }, + "type" : "array" + } + }, + "type" : "object" + }, + "type" : "array" + } + }, + "type" : "object" + }, + "type" : "array" + } + }, + "type" : "object" + }, + "path" : { + "description" : "If no path is provided, then it defaults to forward slash (`/`).", + "type" : "string" + }, + "pathType" : { + "description" : "Path type values are case-sensitive and formatted as follows:
  • `exact`: exact string match
  • `prefix`: prefix-based match
  • `regex`: regex-based match
Defaults to `prefix` if `path` specified is `/`; otherwise, defaults to `exact`.", + "type" : "string" + } + }, + "type" : "object" + }, + "type" : "array" + } + }, + "type" : "object" + }, + "type" : "array" + }, + "tls" : { + "description" : "The security parameters for an ingress trait. This is required only if specific hosts are given in an [IngressRule](#oam.verrazzano.io/v1alpha1.IngressRule).", + "properties" : { + "secretName" : { + "description" : "The name of a secret containing the certificate securing the transport. The specification of a secret here implies that a certificate was created for specific hosts, as specified in an [IngressRule](#oam.verrazzano.io/v1alpha1.IngressRule).", + "type" : "string" + } + }, + "type" : "object" + }, + "workloadRef" : { + "description" : "The WorkloadReference of the workload to which this trait applies. This value is populated by the OAM runtime when an ApplicationConfiguration resource is processed. When the ApplicationConfiguration is processed, a trait and a workload resource are created from the content of the ApplicationConfiguration. The WorkloadReference is provided in the trait by OAM to ensure that the trait controller can find the workload associated with the component containing the trait within the original ApplicationConfiguration.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + } + }, + "required" : [ "workloadRef" ], + "type" : "object" + }, + "status" : { + "description" : "The observed state of an ingress trait and related resources.", + "properties" : { + "conditions" : { + "description" : "Conditions of the resource.", + "items" : { + "description" : "A Condition that may apply to a resource.", + "properties" : { + "lastTransitionTime" : { + "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", + "format" : "date-time", + "type" : "string" + }, + "message" : { + "description" : "A Message containing details about this condition's last transition from one status to another, if any.", + "type" : "string" + }, + "reason" : { + "description" : "A Reason for this condition's last transition from one status to another.", + "type" : "string" + }, + "status" : { + "description" : "Status of this condition; is it currently True, False, or Unknown?", + "type" : "string" + }, + "type" : { + "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", + "type" : "string" + } + }, + "required" : [ "lastTransitionTime", "reason", "status", "type" ], + "type" : "object" + }, + "type" : "array" + }, + "resources" : { + "description" : "The resources managed by this ingress trait.", + "items" : { + "description" : "A TypedReference refers to an object by Name, Kind, and APIVersion. It is commonly used to reference cluster-scoped objects or objects where the namespace is already known.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + }, + "type" : "array" + } + }, + "type" : "object" + } + }, + "type" : "object" + }, { + "description" : "LoggingTrait specifies the logging traits API.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type" : "string" + }, + "kind" : { + "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type" : "string" + }, + "metadata" : { + "type" : "object" + }, + "spec" : { + "description" : "LoggingTraitSpec specifies the desired state of a logging trait.", + "properties" : { + "imagePullPolicy" : { + "description" : "The optional image pull policy for the Fluentd image provided by the user.", + "type" : "string" + }, + "loggingConfig" : { + "description" : "The configuration provided by the user for the Fluentd configuration that consists of fluentd.conf: `\\n ... and so on ...\\n`.", + "type" : "string" + }, + "loggingImage" : { + "description" : "The name of the custom Fluentd image.", + "type" : "string" + }, + "workloadRef" : { + "description" : "The WorkloadReference of the workload to which this trait applies. This value is populated by the OAM runtime when an ApplicationConfiguration resource is processed. When the ApplicationConfiguration is processed, a trait and a workload resource are created from the content of the ApplicationConfiguration. The WorkloadReference is provided in the trait by OAM to ensure that the trait controller can find the workload associated with the component containing the trait within the original ApplicationConfiguration.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + } + }, + "required" : [ "workloadRef" ], + "type" : "object" + }, + "status" : { + "description" : "The observed state of a logging trait and related resources.", + "properties" : { + "conditions" : { + "description" : "Conditions of the resource.", + "items" : { + "description" : "A Condition that may apply to a resource.", + "properties" : { + "lastTransitionTime" : { + "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", + "format" : "date-time", + "type" : "string" + }, + "message" : { + "description" : "A Message containing details about this condition's last transition from one status to another, if any.", + "type" : "string" + }, + "reason" : { + "description" : "A Reason for this condition's last transition from one status to another.", + "type" : "string" + }, + "status" : { + "description" : "Status of this condition; is it currently True, False, or Unknown?", + "type" : "string" + }, + "type" : { + "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", + "type" : "string" + } + }, + "required" : [ "lastTransitionTime", "reason", "status", "type" ], + "type" : "object" + }, + "type" : "array" + }, + "resources" : { + "description" : "The resources managed by this logging trait.", + "items" : { + "description" : "A TypedReference refers to an object by Name, Kind, and APIVersion. It is commonly used to reference cluster-scoped objects or objects where the namespace is already known.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + }, + "type" : "array" + } + }, + "type" : "object" + } + }, + "type" : "object" + }, { + "description" : "A ManualScalerTrait determines how many replicas a workload should have.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type" : "string" + }, + "kind" : { + "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type" : "string" + }, + "metadata" : { + "type" : "object" + }, + "spec" : { + "description" : "A ManualScalerTraitSpec defines the desired state of a ManualScalerTrait.", + "properties" : { + "replicaCount" : { + "description" : "ReplicaCount of the workload this trait applies to.", + "format" : "int32", + "type" : "integer" + }, + "workloadRef" : { + "description" : "WorkloadReference to the workload this trait applies to.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + } + }, + "required" : [ "replicaCount", "workloadRef" ], + "type" : "object" + }, + "status" : { + "description" : "A ManualScalerTraitStatus represents the observed state of a ManualScalerTrait.", + "properties" : { + "conditions" : { + "description" : "Conditions of the resource.", + "items" : { + "description" : "A Condition that may apply to a resource.", + "properties" : { + "lastTransitionTime" : { + "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", + "format" : "date-time", + "type" : "string" + }, + "message" : { + "description" : "A Message containing details about this condition's last transition from one status to another, if any.", + "type" : "string" + }, + "reason" : { + "description" : "A Reason for this condition's last transition from one status to another.", + "type" : "string" + }, + "status" : { + "description" : "Status of this condition; is it currently True, False, or Unknown?", + "type" : "string" + }, + "type" : { + "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", + "type" : "string" + } + }, + "required" : [ "lastTransitionTime", "reason", "status", "type" ], + "type" : "object" + }, + "type" : "array" + } + }, + "type" : "object" + } + }, + "type" : "object" + }, { + "description" : "MetricsTrait specifies the metrics trait API.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type" : "string" + }, + "kind" : { + "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type" : "string" + }, + "metadata" : { + "type" : "object" + }, + "spec" : { + "description" : "MetricsTraitSpec specifies the desired state of a metrics trait.", + "properties" : { + "enabled" : { + "description" : "Specifies whether metrics collection is enabled. Defaults to `true`.", + "type" : "boolean" + }, + "path" : { + "description" : "The HTTP path for the related metrics endpoint. Defaults to `/metrics`.", + "type" : "string" + }, + "port" : { + "description" : "The HTTP port for the related metrics trait. Defaults to `8080`.", + "type" : "integer" + }, + "ports" : { + "description" : "The HTTP endpoints for the related metrics.", + "items" : { + "description" : "PortSpec defines an HTTP port and path combination.", + "properties" : { + "path" : { + "description" : "The HTTP path for the related metrics endpoint. Defaults to `/metrics`.", + "type" : "string" + }, + "port" : { + "description" : "The HTTP port for the related metrics trait. Defaults to `8080`.", + "type" : "integer" + } + }, + "type" : "object" + }, + "type" : "array" + }, + "scraper" : { + "description" : "The Prometheus deployment used to scrape the related metrics endpoints. By default, the Verrazzano-supplied Prometheus component is used to scrape the endpoint.", + "type" : "string" + }, + "secret" : { + "description" : "The name of an opaque secret (for example, `username` and `password`) within the workload’s namespace for metrics endpoint access.", + "type" : "string" + }, + "workloadRef" : { + "description" : "The WorkloadReference of the workload to which this trait applies. This value is populated by the OAM runtime when an ApplicationConfiguration resource is processed. When the ApplicationConfiguration is processed, a trait and a workload resource are created from the content of the ApplicationConfiguration. The WorkloadReference is provided in the trait by OAM to ensure that the trait controller can find the workload associated with the component containing the trait within the original ApplicationConfiguration.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + } + }, + "required" : [ "workloadRef" ], + "type" : "object" + }, + "status" : { + "description" : "The observed state of a metrics trait and related resources.", + "properties" : { + "conditions" : { + "description" : "Conditions of the resource.", + "items" : { + "description" : "A Condition that may apply to a resource.", + "properties" : { + "lastTransitionTime" : { + "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", + "format" : "date-time", + "type" : "string" + }, + "message" : { + "description" : "A Message containing details about this condition's last transition from one status to another, if any.", + "type" : "string" + }, + "reason" : { + "description" : "A Reason for this condition's last transition from one status to another.", + "type" : "string" + }, + "status" : { + "description" : "Status of this condition; is it currently True, False, or Unknown?", + "type" : "string" + }, + "type" : { + "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", + "type" : "string" + } + }, + "required" : [ "lastTransitionTime", "reason", "status", "type" ], + "type" : "object" + }, + "type" : "array" + }, + "resources" : { + "description" : "Related resources affected by this metrics trait.", + "items" : { + "description" : "QualifiedResourceRelation identifies a specific related resource.", + "properties" : { + "apiversion" : { + "description" : "API version of the related resource.", + "type" : "string" + }, + "kind" : { + "description" : "Kind of the related resource.", + "type" : "string" + }, + "name" : { + "description" : "Name of the related resource.", + "type" : "string" + }, + "namespace" : { + "description" : "Namespace of the related resource.", + "type" : "string" + }, + "role" : { + "description" : "Role of the related resource, for example, `Deployment`.", + "type" : "string" + } + }, + "required" : [ "apiversion", "kind", "name", "namespace", "role" ], + "type" : "object" + }, + "type" : "array" + } + }, + "type" : "object" + } + }, + "type" : "object" + } ], + "type" : "object", + "x-kubernetes-embedded-resource" : true, + "x-kubernetes-preserve-unknown-fields" : true + } + }, + "required" : [ "trait" ], + "type" : "object" + }, + "type" : "array" + } + }, + "type" : "object" + }, + "type" : "array" + } + }, + "required" : [ "components" ], + "type" : "object" + }, + "status" : { + "description" : "An ApplicationConfigurationStatus represents the observed state of a ApplicationConfiguration.", + "properties" : { + "conditions" : { + "description" : "Conditions of the resource.", + "items" : { + "description" : "A Condition that may apply to a resource.", + "properties" : { + "lastTransitionTime" : { + "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", + "format" : "date-time", + "type" : "string" + }, + "message" : { + "description" : "A Message containing details about this condition's last transition from one status to another, if any.", + "type" : "string" + }, + "reason" : { + "description" : "A Reason for this condition's last transition from one status to another.", + "type" : "string" + }, + "status" : { + "description" : "Status of this condition; is it currently True, False, or Unknown?", + "type" : "string" + }, + "type" : { + "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", + "type" : "string" + } + }, + "required" : [ "lastTransitionTime", "reason", "status", "type" ], + "type" : "object" + }, + "type" : "array" + }, + "dependency" : { + "description" : "DependencyStatus represents the observed state of the dependency of an ApplicationConfiguration.", + "properties" : { + "unsatisfied" : { + "items" : { + "description" : "UnstaifiedDependency describes unsatisfied dependency flow between one pair of objects.", + "properties" : { + "from" : { + "description" : "DependencyFromObject represents the object that dependency data comes from.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "fieldPath" : { + "type" : "string" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + }, + "reason" : { + "type" : "string" + }, + "to" : { + "description" : "DependencyToObject represents the object that dependency data goes to.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "fieldPaths" : { + "items" : { + "type" : "string" + }, + "type" : "array" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + } + }, + "required" : [ "from", "reason", "to" ], + "type" : "object" + }, + "type" : "array" + } + }, + "type" : "object" + }, + "historyWorkloads" : { + "description" : "HistoryWorkloads will record history but still working revision workloads.", + "items" : { + "description" : "HistoryWorkload contain the old component revision that are still running", + "properties" : { + "revision" : { + "description" : "Revision of this workload", + "type" : "string" + }, + "workloadRef" : { + "description" : "Reference to running workload.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + } + }, + "type" : "object" + }, + "type" : "array" + }, + "observedGeneration" : { + "description" : "The generation observed by the appConfig controller.", + "format" : "int64", + "type" : "integer" + }, + "status" : { + "description" : "Status is a place holder for a customized controller to fill if it needs a single place to summarize the status of the entire application", + "type" : "string" + }, + "workloads" : { + "description" : "Workloads created by this ApplicationConfiguration.", + "items" : { + "description" : "A WorkloadStatus represents the status of a workload.", + "properties" : { + "componentName" : { + "description" : "ComponentName that produced this workload.", + "type" : "string" + }, + "componentRevisionName" : { + "description" : "ComponentRevisionName of current component", + "type" : "string" + }, + "scopes" : { + "description" : "Scopes associated with this workload.", + "items" : { + "description" : "A WorkloadScope represents a scope associated with a workload and its status", + "properties" : { + "scopeRef" : { + "description" : "Reference to a scope created by an ApplicationConfiguration.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + }, + "status" : { + "description" : "Status is a place holder for a customized controller to fill if it needs a single place to summarize the status of the scope", + "type" : "string" + } + }, + "required" : [ "scopeRef" ], + "type" : "object" + }, + "type" : "array" + }, + "status" : { + "description" : "Status is a place holder for a customized controller to fill if it needs a single place to summarize the entire status of the workload", + "type" : "string" + }, + "traits" : { + "description" : "Traits associated with this workload.", + "items" : { + "description" : "A WorkloadTrait represents a trait associated with a workload and its status", + "properties" : { + "message" : { + "description" : "Message will allow controller to leave some additional information for this trait", + "type" : "string" + }, + "status" : { + "description" : "Status is a place holder for a customized controller to fill if it needs a single place to summarize the status of the trait", + "type" : "string" + }, + "traitRef" : { + "description" : "Reference to a trait created by an ApplicationConfiguration.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + } + }, + "required" : [ "traitRef" ], + "type" : "object" + }, + "type" : "array" + }, + "workloadRef" : { + "description" : "Reference to a workload created by an ApplicationConfiguration.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion of the referenced object.", + "type" : "string" + }, + "kind" : { + "description" : "Kind of the referenced object.", + "type" : "string" + }, + "name" : { + "description" : "Name of the referenced object.", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referenced object.", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name" ], + "type" : "object" + } + }, + "type" : "object" + }, + "type" : "array" + } + }, + "type" : "object" + } + }, + "type" : "object" + } +} diff --git a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha2.json b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha2.json deleted file mode 100644 index 982720bd8..000000000 --- a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha2.json +++ /dev/null @@ -1 +0,0 @@ -{"openAPIV3Schema":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"type":"object"},"spec":{"properties":{"components":{"items":{"properties":{"componentName":{"type":"string"},"dataInputs":{"items":{"properties":{"toFieldPaths":{"items":{"type":"string"},"type":"array"},"valueFrom":{"properties":{"dataOutputName":{"type":"string"}},"required":["dataOutputName"],"type":"object"}},"type":"object"},"type":"array"},"dataOutputs":{"items":{"properties":{"conditions":{"items":{"properties":{"fieldPath":{"type":"string"},"op":{"type":"string"},"value":{"type":"string"},"valueFrom":{"properties":{"fieldPath":{"type":"string"}},"required":["fieldPath"],"type":"object"}},"required":["op"],"type":"object"},"type":"array"},"fieldPath":{"type":"string"},"name":{"type":"string"}},"type":"object"},"type":"array"},"parameterValues":{"items":{"properties":{"name":{"type":"string"},"value":{"anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}},"required":["name","value"],"type":"object"},"type":"array"},"revisionName":{"type":"string"},"scopes":{"items":{"properties":{"scopeRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["scopeRef"],"type":"object"},"type":"array"},"traits":{"items":{"properties":{"dataInputs":{"items":{"properties":{"toFieldPaths":{"items":{"type":"string"},"type":"array"},"valueFrom":{"properties":{"dataOutputName":{"type":"string"}},"required":["dataOutputName"],"type":"object"}},"type":"object"},"type":"array"},"dataOutputs":{"items":{"properties":{"conditions":{"items":{"properties":{"fieldPath":{"type":"string"},"op":{"type":"string"},"value":{"type":"string"},"valueFrom":{"properties":{"fieldPath":{"type":"string"}},"required":["fieldPath"],"type":"object"}},"required":["op"],"type":"object"},"type":"array"},"fieldPath":{"type":"string"},"name":{"type":"string"}},"type":"object"},"type":"array"},"trait":{"type":"object","x-kubernetes-embedded-resource":true,"x-kubernetes-preserve-unknown-fields":true}},"required":["trait"],"type":"object"},"type":"array"}},"type":"object"},"type":"array"}},"required":["components"],"type":"object"},"status":{"properties":{"conditions":{"items":{"properties":{"lastTransitionTime":{"format":"date-time","type":"string"},"message":{"type":"string"},"reason":{"type":"string"},"status":{"type":"string"},"type":{"type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"},"dependency":{"properties":{"unsatisfied":{"items":{"properties":{"from":{"properties":{"apiVersion":{"type":"string"},"fieldPath":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"},"reason":{"type":"string"},"to":{"properties":{"apiVersion":{"type":"string"},"fieldPaths":{"items":{"type":"string"},"type":"array"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["from","reason","to"],"type":"object"},"type":"array"}},"type":"object"},"historyWorkloads":{"items":{"properties":{"revision":{"type":"string"},"workloadRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"type":"object"},"type":"array"},"observedGeneration":{"format":"int64","type":"integer"},"status":{"type":"string"},"workloads":{"items":{"properties":{"componentName":{"type":"string"},"componentRevisionName":{"type":"string"},"scopes":{"items":{"properties":{"scopeRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"},"status":{"type":"string"}},"required":["scopeRef"],"type":"object"},"type":"array"},"status":{"type":"string"},"traits":{"items":{"properties":{"message":{"type":"string"},"status":{"type":"string"},"traitRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["traitRef"],"type":"object"},"type":"array"},"workloadRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"type":"object"},"type":"array"}},"type":"object"}},"type":"object"}} diff --git a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha1.json b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha1.json new file mode 100644 index 000000000..f1e87528f --- /dev/null +++ b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha1.json @@ -0,0 +1,384 @@ +{ + "openAPIV3Schema" : { + "description" : "A Component describes how an OAM workload kind may be instantiated.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type" : "string" + }, + "kind" : { + "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type" : "string" + }, + "metadata" : { + "type" : "object" + }, + "spec" : { + "description" : "A ComponentSpec defines the desired state of a Component.", + "properties" : { + "parameters" : { + "description" : "Parameters exposed by this component. ApplicationConfigurations that reference this component may specify values for these parameters, which will in turn be injected into the embedded workload.", + "items" : { + "description" : "A ComponentParameter defines a configurable parameter of a component.", + "properties" : { + "description" : { + "description" : "Description of this parameter.", + "type" : "string" + }, + "fieldPaths" : { + "description" : "FieldPaths specifies an array of fields within this Component's workload that will be overwritten by the value of this parameter. The type of the parameter (e.g. int, string) is inferred from the type of these fields; All fields must be of the same type. Fields are specified as JSON field paths without a leading dot, for example 'spec.replicas'.", + "items" : { + "type" : "string" + }, + "type" : "array" + }, + "name" : { + "description" : "Name of this parameter. OAM ApplicationConfigurations will specify parameter values using this name.", + "type" : "string" + }, + "required" : { + "default" : false, + "description" : "Required specifies whether or not a value for this parameter must be supplied when authoring an ApplicationConfiguration.", + "type" : "boolean" + } + }, + "required" : [ "fieldPaths", "name" ], + "type" : "object" + }, + "type" : "array" + }, + "workload" : { + "description" : "ConfigMap holds configuration data for pods to consume.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "type" : "string" + }, + "binaryData" : { + "additionalProperties" : { + "format" : "byte", + "type" : "string" + }, + "description" : "BinaryData contains the binary data. Each key must consist of alphanumeric characters, '-', '_' or '.'. BinaryData can contain byte sequences that are not in the UTF-8 range. The keys stored in BinaryData must not overlap with the ones in the Data field, this is enforced during validation process. Using this field will require 1.10+ apiserver and kubelet.", + "type" : "object" + }, + "data" : { + "additionalProperties" : { + "type" : "string" + }, + "description" : "Data contains the configuration data. Each key must consist of alphanumeric characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use the BinaryData field. The keys stored in Data must not overlap with the keys in the BinaryData field, this is enforced during validation process.", + "type" : "object" + }, + "kind" : { + "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "enum" : [ "ConfigMap" ], + "type" : "string" + }, + "metadata" : { + "description" : "ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create.", + "properties" : { + "annotations" : { + "additionalProperties" : { + "type" : "string" + }, + "description" : "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations", + "type" : "object" + }, + "clusterName" : { + "description" : "The name of the cluster which the object belongs to. This is used to distinguish resources with same name and namespace in different clusters. This field is not set anywhere right now and apiserver is going to ignore it if set in create or update request.", + "type" : "string" + }, + "creationTimestamp" : { + "description" : "Time is a wrapper around time.Time which supports correct marshaling to YAML and JSON. Wrappers are provided for many of the factory methods that the time package offers.", + "format" : "date-time", + "type" : "string" + }, + "deletionGracePeriodSeconds" : { + "description" : "Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only.", + "format" : "int64", + "type" : "integer" + }, + "deletionTimestamp" : { + "description" : "Time is a wrapper around time.Time which supports correct marshaling to YAML and JSON. Wrappers are provided for many of the factory methods that the time package offers.", + "format" : "date-time", + "type" : "string" + }, + "finalizers" : { + "description" : "Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed.", + "items" : { + "type" : "string" + }, + "type" : "array", + "x-kubernetes-patch-strategy" : "merge" + }, + "generateName" : { + "description" : "GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server.\n\nIf this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header).\n\nApplied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#idempotency", + "type" : "string" + }, + "generation" : { + "description" : "A sequence number representing a specific generation of the desired state. Populated by the system. Read-only.", + "format" : "int64", + "type" : "integer" + }, + "initializers" : { + "description" : "Initializers tracks the progress of initialization.", + "properties" : { + "pending" : { + "description" : "Pending is a list of initializers that must execute in order before this object is visible. When the last pending initializer is removed, and no failing result is set, the initializers struct will be set to nil and the object is considered as initialized and visible to all clients.", + "items" : { + "description" : "Initializer is information about an initializer that has not yet completed.", + "properties" : { + "name" : { + "description" : "name of the process that is responsible for initializing this object.", + "type" : "string" + } + }, + "required" : [ "name" ] + }, + "type" : "array", + "x-kubernetes-patch-merge-key" : "name", + "x-kubernetes-patch-strategy" : "merge" + }, + "result" : { + "description" : "Status is a return value for calls that don't return other objects.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "type" : "string" + }, + "code" : { + "description" : "Suggested HTTP return code for this status, 0 if not set.", + "format" : "int32", + "type" : "integer" + }, + "details" : { + "description" : "StatusDetails is a set of additional properties that MAY be set by the server to provide additional information about a response. The Reason field of a Status object defines what attributes will be set. Clients must ignore fields that do not match the defined type of each attribute, and should assume that any attribute may be empty, invalid, or under defined.", + "properties" : { + "causes" : { + "description" : "The Causes array includes more details associated with the StatusReason failure. Not all StatusReasons may provide detailed causes.", + "items" : { + "description" : "StatusCause provides more information about an api.Status failure, including cases when multiple errors are encountered.", + "properties" : { + "field" : { + "description" : "The field of the resource that has caused this error, as named by its JSON serialization. May include dot and postfix notation for nested attributes. Arrays are zero-indexed. Fields may appear more than once in an array of causes due to fields having multiple errors. Optional.\n\nExamples:\n \"name\" - the field \"name\" on the current resource\n \"items[0].name\" - the field \"name\" on the first array entry in \"items\"", + "type" : "string" + }, + "message" : { + "description" : "A human-readable description of the cause of the error. This field may be presented as-is to a reader.", + "type" : "string" + }, + "reason" : { + "description" : "A machine-readable description of the cause of the error. If this value is empty there is no information available.", + "type" : "string" + } + } + }, + "type" : "array" + }, + "group" : { + "description" : "The group attribute of the resource associated with the status StatusReason.", + "type" : "string" + }, + "kind" : { + "description" : "The kind attribute of the resource associated with the status StatusReason. On some operations may differ from the requested resource Kind. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "type" : "string" + }, + "name" : { + "description" : "The name attribute of the resource associated with the status StatusReason (when there is a single name which can be described).", + "type" : "string" + }, + "retryAfterSeconds" : { + "description" : "If specified, the time in seconds before the operation should be retried. Some errors may indicate the client must take an alternate action - for those errors this field may indicate how long to wait before taking the alternate action.", + "format" : "int32", + "type" : "integer" + }, + "uid" : { + "description" : "UID of the resource. (when there is a single resource which can be described). More info: http://kubernetes.io/docs/user-guide/identifiers#uids", + "type" : "string" + } + } + }, + "kind" : { + "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "enum" : [ "Status" ], + "type" : "string" + }, + "message" : { + "description" : "A human-readable description of the status of this operation.", + "type" : "string" + }, + "metadata" : { + "description" : "ListMeta describes metadata that synthetic resources must have, including lists and various status objects. A resource may have only one of {ObjectMeta, ListMeta}.", + "properties" : { + "continue" : { + "description" : "continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message.", + "type" : "string" + }, + "resourceVersion" : { + "description" : "String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency", + "type" : "string" + }, + "selfLink" : { + "description" : "selfLink is a URL representing this object. Populated by the system. Read-only.", + "type" : "string" + } + } + }, + "reason" : { + "description" : "A machine-readable description of why this operation is in the \"Failure\" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it.", + "type" : "string" + }, + "status" : { + "description" : "Status of the operation. One of: \"Success\" or \"Failure\". More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", + "type" : "string" + } + }, + "x-kubernetes-group-version-kind" : [ { + "group" : "", + "kind" : "Status", + "version" : "v1" + } ] + } + }, + "required" : [ "pending" ] + }, + "labels" : { + "additionalProperties" : { + "type" : "string" + }, + "description" : "Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels", + "type" : "object" + }, + "name" : { + "description" : "Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names", + "type" : "string" + }, + "namespace" : { + "description" : "Namespace defines the space within each name must be unique. An empty namespace is equivalent to the \"default\" namespace, but \"default\" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty.\n\nMust be a DNS_LABEL. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/namespaces", + "type" : "string" + }, + "ownerReferences" : { + "description" : "List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller.", + "items" : { + "description" : "OwnerReference contains enough information to let you identify an owning object. An owning object must be in the same namespace as the dependent, or be cluster-scoped, so there is no namespace field.", + "properties" : { + "apiVersion" : { + "description" : "API version of the referent.", + "type" : "string" + }, + "blockOwnerDeletion" : { + "description" : "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. Defaults to false. To set this field, a user needs \"delete\" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned.", + "type" : "boolean" + }, + "controller" : { + "description" : "If true, this reference points to the managing controller.", + "type" : "boolean" + }, + "kind" : { + "description" : "Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "type" : "string" + }, + "name" : { + "description" : "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names", + "type" : "string" + }, + "uid" : { + "description" : "UID of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#uids", + "type" : "string" + } + }, + "required" : [ "apiVersion", "kind", "name", "uid" ] + }, + "type" : "array", + "x-kubernetes-patch-merge-key" : "uid", + "x-kubernetes-patch-strategy" : "merge" + }, + "resourceVersion" : { + "description" : "An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources.\n\nPopulated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency", + "type" : "string" + }, + "selfLink" : { + "description" : "SelfLink is a URL representing this object. Populated by the system. Read-only.", + "type" : "string" + }, + "uid" : { + "description" : "UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations.\n\nPopulated by the system. Read-only. More info: http://kubernetes.io/docs/user-guide/identifiers#uids", + "type" : "string" + } + } + } + }, + "type" : "object", + "x-kubernetes-embedded-resource" : true, + "x-kubernetes-group-version-kind" : [ { + "group" : "", + "kind" : "ConfigMap", + "version" : "v1" + } ], + "x-kubernetes-preserve-unknown-fields" : true + } + }, + "required" : [ "workload" ], + "type" : "object" + }, + "status" : { + "description" : "A ComponentStatus represents the observed state of a Component.", + "properties" : { + "conditions" : { + "description" : "Conditions of the resource.", + "items" : { + "description" : "A Condition that may apply to a resource.", + "properties" : { + "lastTransitionTime" : { + "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", + "format" : "date-time", + "type" : "string" + }, + "message" : { + "description" : "A Message containing details about this condition's last transition from one status to another, if any.", + "type" : "string" + }, + "reason" : { + "description" : "A Reason for this condition's last transition from one status to another.", + "type" : "string" + }, + "status" : { + "description" : "Status of this condition; is it currently True, False, or Unknown?", + "type" : "string" + }, + "type" : { + "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", + "type" : "string" + } + }, + "required" : [ "lastTransitionTime", "reason", "status", "type" ], + "type" : "object" + }, + "type" : "array" + }, + "latestRevision" : { + "description" : "LatestRevision of component", + "properties" : { + "name" : { + "type" : "string" + }, + "revision" : { + "format" : "int64", + "type" : "integer" + } + }, + "required" : [ "name", "revision" ], + "type" : "object" + }, + "observedGeneration" : { + "description" : "The generation observed by the component controller.", + "format" : "int64", + "type" : "integer" + } + }, + "type" : "object" + } + }, + "type" : "object" + } +} diff --git a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha2.json b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha2.json deleted file mode 100644 index f8be3126d..000000000 --- a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha2.json +++ /dev/null @@ -1 +0,0 @@ -{"openAPIV3Schema":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"type":"object"},"spec":{"properties":{"parameters":{"items":{"properties":{"description":{"type":"string"},"fieldPaths":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"required":{"default":false,"type":"boolean"}},"required":["fieldPaths","name"],"type":"object"},"type":"array"},"workload":{"properties":{"apiVersion":{"type":"string"},"binaryData":{"additionalProperties":{"format":"byte","type":"string"},"type":"object"},"data":{"additionalProperties":{"type":"string"},"type":"object"},"kind":{"enum":["ConfigMap"],"type":"string"},"metadata":{"properties":{"annotations":{"additionalProperties":{"type":"string"},"type":"object"},"clusterName":{"type":"string"},"creationTimestamp":{"format":"date-time","type":"string"},"deletionGracePeriodSeconds":{"format":"int64","type":"integer"},"deletionTimestamp":{"format":"date-time","type":"string"},"finalizers":{"items":{"type":"string"},"type":"array","x-kubernetes-patch-strategy":"merge"},"generateName":{"type":"string"},"generation":{"format":"int64","type":"integer"},"initializers":{"properties":{"pending":{"items":{"properties":{"name":{"type":"string"}},"required":["name"]},"type":"array","x-kubernetes-patch-merge-key":"name","x-kubernetes-patch-strategy":"merge"},"result":{"properties":{"apiVersion":{"type":"string"},"code":{"format":"int32","type":"integer"},"details":{"properties":{"causes":{"items":{"properties":{"field":{"type":"string"},"message":{"type":"string"},"reason":{"type":"string"}}},"type":"array"},"group":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"retryAfterSeconds":{"format":"int32","type":"integer"},"uid":{"type":"string"}}},"kind":{"enum":["Status"],"type":"string"},"message":{"type":"string"},"metadata":{"properties":{"continue":{"type":"string"},"resourceVersion":{"type":"string"},"selfLink":{"type":"string"}}},"reason":{"type":"string"},"status":{"type":"string"}},"x-kubernetes-group-version-kind":[{"group":"","kind":"Status","version":"v1"}]}},"required":["pending"]},"labels":{"additionalProperties":{"type":"string"},"type":"object"},"name":{"type":"string"},"namespace":{"type":"string"},"ownerReferences":{"items":{"properties":{"apiVersion":{"type":"string"},"blockOwnerDeletion":{"type":"boolean"},"controller":{"type":"boolean"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name","uid"]},"type":"array","x-kubernetes-patch-merge-key":"uid","x-kubernetes-patch-strategy":"merge"},"resourceVersion":{"type":"string"},"selfLink":{"type":"string"},"uid":{"type":"string"}}}},"type":"object","x-kubernetes-embedded-resource":true,"x-kubernetes-group-version-kind":[{"group":"","kind":"ConfigMap","version":"v1"}],"x-kubernetes-preserve-unknown-fields":true}},"required":["workload"],"type":"object"},"status":{"properties":{"conditions":{"items":{"properties":{"lastTransitionTime":{"format":"date-time","type":"string"},"message":{"type":"string"},"reason":{"type":"string"},"status":{"type":"string"},"type":{"type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"},"latestRevision":{"properties":{"name":{"type":"string"},"revision":{"format":"int64","type":"integer"}},"required":["name","revision"],"type":"object"},"observedGeneration":{"format":"int64","type":"integer"}},"type":"object"}},"type":"object"}} diff --git a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha1.json b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha1.json new file mode 100644 index 000000000..13ca2cf04 --- /dev/null +++ b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha1.json @@ -0,0 +1,197 @@ +{ + "openAPIV3Schema" : { + "description" : "A Component describes how an OAM workload kind may be instantiated.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type" : "string" + }, + "kind" : { + "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type" : "string" + }, + "metadata" : { + "type" : "object" + }, + "spec" : { + "description" : "A ComponentSpec defines the desired state of a Component.", + "properties" : { + "parameters" : { + "description" : "Parameters exposed by this component. ApplicationConfigurations that reference this component may specify values for these parameters, which will in turn be injected into the embedded workload.", + "items" : { + "description" : "A ComponentParameter defines a configurable parameter of a component.", + "properties" : { + "description" : { + "description" : "Description of this parameter.", + "type" : "string" + }, + "fieldPaths" : { + "description" : "FieldPaths specifies an array of fields within this Component's workload that will be overwritten by the value of this parameter. The type of the parameter (e.g. int, string) is inferred from the type of these fields; All fields must be of the same type. Fields are specified as JSON field paths without a leading dot, for example 'spec.replicas'.", + "items" : { + "type" : "string" + }, + "type" : "array" + }, + "name" : { + "description" : "Name of this parameter. OAM ApplicationConfigurations will specify parameter values using this name.", + "type" : "string" + }, + "required" : { + "default" : false, + "description" : "Required specifies whether or not a value for this parameter must be supplied when authoring an ApplicationConfiguration.", + "type" : "boolean" + } + }, + "required" : [ "fieldPaths", "name" ], + "type" : "object" + }, + "type" : "array" + }, + "workload" : { + "description" : "VerrazzanoWebLogicWorkload specifies the Verrazzano WebLogic workload API.", + "properties" : { + "apiVersion" : { + "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type" : "string" + }, + "kind" : { + "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type" : "string" + }, + "metadata" : { + "type" : "object" + }, + "spec" : { + "description" : "The desired state of a Verrazzano WebLogic workload.", + "properties" : { + "clusters" : { + "items" : { + "properties" : { + "apiVersion" : { + "type" : "string" + }, + "metadata" : { + "type" : "object", + "x-kubernetes-preserve-unknown-fields" : true + }, + "spec" : { + "type" : "object", + "x-kubernetes-preserve-unknown-fields" : true + } + }, + "required" : [ "spec" ], + "type" : "object" + }, + "type" : "array" + }, + "template" : { + "description" : "The metadata and spec for the underlying Domain resource.", + "properties" : { + "apiVersion" : { + "type" : "string" + }, + "metadata" : { + "type" : "object", + "x-kubernetes-preserve-unknown-fields" : true + }, + "spec" : { + "type" : "object", + "x-kubernetes-preserve-unknown-fields" : true + } + }, + "required" : [ "spec" ], + "type" : "object", + "x-kubernetes-preserve-unknown-fields" : true + } + }, + "required" : [ "template" ], + "type" : "object" + }, + "status" : { + "description" : "The observed state of a Verrazzano WebLogic workload.", + "properties" : { + "lastGeneration" : { + "description" : "The last generation of the Verrazzano WebLogic workload that was reconciled.", + "type" : "string" + }, + "lastLifecycleAction" : { + "description" : "The last value of the `verrazzano.io/lifecycle-action`.", + "type" : "string" + }, + "lastRestartVersion" : { + "description" : "The last value of the `verrazzano.io/restart-version` annotation.", + "type" : "string" + } + }, + "type" : "object" + } + }, + "type" : "object", + "x-kubernetes-embedded-resource" : true, + "x-kubernetes-preserve-unknown-fields" : true + } + }, + "required" : [ "workload" ], + "type" : "object" + }, + "status" : { + "description" : "A ComponentStatus represents the observed state of a Component.", + "properties" : { + "conditions" : { + "description" : "Conditions of the resource.", + "items" : { + "description" : "A Condition that may apply to a resource.", + "properties" : { + "lastTransitionTime" : { + "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", + "format" : "date-time", + "type" : "string" + }, + "message" : { + "description" : "A Message containing details about this condition's last transition from one status to another, if any.", + "type" : "string" + }, + "reason" : { + "description" : "A Reason for this condition's last transition from one status to another.", + "type" : "string" + }, + "status" : { + "description" : "Status of this condition; is it currently True, False, or Unknown?", + "type" : "string" + }, + "type" : { + "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", + "type" : "string" + } + }, + "required" : [ "lastTransitionTime", "reason", "status", "type" ], + "type" : "object" + }, + "type" : "array" + }, + "latestRevision" : { + "description" : "LatestRevision of component", + "properties" : { + "name" : { + "type" : "string" + }, + "revision" : { + "format" : "int64", + "type" : "integer" + } + }, + "required" : [ "name", "revision" ], + "type" : "object" + }, + "observedGeneration" : { + "description" : "The generation observed by the component controller.", + "format" : "int64", + "type" : "integer" + } + }, + "type" : "object" + } + }, + "type" : "object" + } +} diff --git a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha2.json b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha2.json deleted file mode 100644 index bbed4809c..000000000 --- a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha2.json +++ /dev/null @@ -1 +0,0 @@ -{"openAPIV3Schema":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"type":"object"},"spec":{"properties":{"parameters":{"items":{"properties":{"description":{"type":"string"},"fieldPaths":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"required":{"default":false,"type":"boolean"}},"required":["fieldPaths","name"],"type":"object"},"type":"array"},"workload":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"type":"object"},"spec":{"properties":{"clusters":{"items":{"properties":{"apiVersion":{"type":"string"},"metadata":{"type":"object","x-kubernetes-preserve-unknown-fields":true},"spec":{"type":"object","x-kubernetes-preserve-unknown-fields":true}},"required":["spec"],"type":"object"},"type":"array"},"template":{"properties":{"apiVersion":{"type":"string"},"metadata":{"type":"object","x-kubernetes-preserve-unknown-fields":true},"spec":{"type":"object","x-kubernetes-preserve-unknown-fields":true}},"required":["spec"],"type":"object","x-kubernetes-preserve-unknown-fields":true}},"required":["template"],"type":"object"},"status":{"properties":{"lastGeneration":{"type":"string"},"lastLifecycleAction":{"type":"string"},"lastRestartVersion":{"type":"string"}},"type":"object"}},"type":"object","x-kubernetes-embedded-resource":true,"x-kubernetes-preserve-unknown-fields":true}},"required":["workload"],"type":"object"},"status":{"properties":{"conditions":{"items":{"properties":{"lastTransitionTime":{"format":"date-time","type":"string"},"message":{"type":"string"},"reason":{"type":"string"},"status":{"type":"string"},"type":{"type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"},"latestRevision":{"properties":{"name":{"type":"string"},"revision":{"format":"int64","type":"integer"}},"required":["name","revision"],"type":"object"},"observedGeneration":{"format":"int64","type":"integer"}},"type":"object"}},"type":"object"}} diff --git a/core/src/test/python/wlsdeploy/tool/util/targets/kubernetes_schema_test.py b/core/src/test/python/wlsdeploy/tool/util/targets/crd_schema_test.py similarity index 86% rename from core/src/test/python/wlsdeploy/tool/util/targets/kubernetes_schema_test.py rename to core/src/test/python/wlsdeploy/tool/util/targets/crd_schema_test.py index a26803ef3..26becee8e 100644 --- a/core/src/test/python/wlsdeploy/tool/util/targets/kubernetes_schema_test.py +++ b/core/src/test/python/wlsdeploy/tool/util/targets/crd_schema_test.py @@ -114,7 +114,24 @@ def _write_folder(self, folder, in_array, path, indent): subfolder = sub_folders[property_name] in_array = property_name in object_array_keys child_indent = this_indent + " " - self._write_folder(subfolder, in_array, next_path, child_indent) + + # if this folder has multiple options (oneOf), print each with comments + subfolder_options = [subfolder] + one_of_options = schema_helper.get_one_of_options(subfolder) + if one_of_options: + subfolder_options = one_of_options + + for index, subfolder_option in enumerate(subfolder_options): + if one_of_options: + self._write_line('') + self._write_line(child_indent + "# option " + str(index + 1)) + + # comment out options after the first + subfolder_indent = child_indent + if index > 0: + subfolder_indent = subfolder_indent + "# " + + self._write_folder(subfolder_option, in_array, next_path, subfolder_indent) def _write_line(self, text): self.out_file.write(text + "\n") From d715bf82e8094d54a429aa0e3cb8af748d353c69 Mon Sep 17 00:00:00 2001 From: Richard Killen Date: Fri, 20 Jan 2023 16:01:31 -0600 Subject: [PATCH 05/10] Minimized Verrazzano schemas --- .../deploy/crds/vz-application-v1alpha1.json | 1167 +---------------- .../deploy/crds/vz-configmap-v1alpha1.json | 385 +----- .../deploy/crds/vz-weblogic-v1alpha1.json | 198 +-- 3 files changed, 3 insertions(+), 1747 deletions(-) diff --git a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha1.json b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha1.json index 78bda4f5c..cb2118822 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha1.json +++ b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-application-v1alpha1.json @@ -1,1166 +1 @@ -{ - "openAPIV3Schema" : { - "description" : "An ApplicationConfiguration represents an OAM application.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type" : "string" - }, - "kind" : { - "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type" : "string" - }, - "metadata" : { - "type" : "object" - }, - "spec" : { - "description" : "An ApplicationConfigurationSpec defines the desired state of a ApplicationConfiguration.", - "properties" : { - "components" : { - "description" : "Components of which this ApplicationConfiguration consists. Each component will be used to instantiate a workload.", - "items" : { - "description" : "An ApplicationConfigurationComponent specifies a component of an ApplicationConfiguration. Each component is used to instantiate a workload.", - "properties" : { - "componentName" : { - "description" : "ComponentName specifies a component whose latest revision will be bind with ApplicationConfiguration. When the spec of the referenced component changes, ApplicationConfiguration will automatically migrate all trait affect from the prior revision to the new one. This is mutually exclusive with RevisionName.", - "type" : "string" - }, - "dataInputs" : { - "description" : "DataInputs specify the data input sinks into this component.", - "items" : { - "description" : "DataInput specifies a data input sink to an object. If input is array, it will be appended to the target field paths.", - "properties" : { - "toFieldPaths" : { - "description" : "ToFieldPaths specifies the field paths of an object to fill passed value.", - "items" : { - "type" : "string" - }, - "type" : "array" - }, - "valueFrom" : { - "description" : "ValueFrom specifies the value source.", - "properties" : { - "dataOutputName" : { - "description" : "DataOutputName matches a name of a DataOutput in the same AppConfig.", - "type" : "string" - } - }, - "required" : [ "dataOutputName" ], - "type" : "object" - } - }, - "type" : "object" - }, - "type" : "array" - }, - "dataOutputs" : { - "description" : "DataOutputs specify the data output sources from this component.", - "items" : { - "description" : "DataOutput specifies a data output source from an object.", - "properties" : { - "conditions" : { - "description" : "Conditions specify the conditions that should be satisfied before emitting a data output. Different conditions are AND-ed together. If no conditions is specified, it is by default to check output value not empty.", - "items" : { - "description" : "ConditionRequirement specifies the requirement to match a value.", - "properties" : { - "fieldPath" : { - "description" : "FieldPath specifies got value from workload/trait object", - "type" : "string" - }, - "op" : { - "description" : "ConditionOperator specifies the operator to match a value.", - "type" : "string" - }, - "value" : { - "description" : "Value specifies an expected value This is mutually exclusive with ValueFrom", - "type" : "string" - }, - "valueFrom" : { - "description" : "ValueFrom specifies expected value from AppConfig This is mutually exclusive with Value", - "properties" : { - "fieldPath" : { - "type" : "string" - } - }, - "required" : [ "fieldPath" ], - "type" : "object" - } - }, - "required" : [ "op" ], - "type" : "object" - }, - "type" : "array" - }, - "fieldPath" : { - "description" : "FieldPath refers to the value of an object's field.", - "type" : "string" - }, - "name" : { - "description" : "Name is the unique name of a DataOutput in an ApplicationConfiguration.", - "type" : "string" - } - }, - "type" : "object" - }, - "type" : "array" - }, - "parameterValues" : { - "description" : "ParameterValues specify values for the the specified component's parameters. Any parameter required by the component must be specified.", - "items" : { - "description" : "A ComponentParameterValue specifies a value for a named parameter. The associated component must publish a parameter with this name.", - "properties" : { - "name" : { - "description" : "Name of the component parameter to set.", - "type" : "string" - }, - "value" : { - "anyOf" : [ { - "type" : "integer" - }, { - "type" : "string" - } ], - "description" : "Value to set.", - "x-kubernetes-int-or-string" : true - } - }, - "required" : [ "name", "value" ], - "type" : "object" - }, - "type" : "array" - }, - "revisionName" : { - "description" : "RevisionName of a specific component revision to which to bind ApplicationConfiguration. This is mutually exclusive with componentName.", - "type" : "string" - }, - "scopes" : { - "description" : "Scopes in which the specified component should exist.", - "items" : { - "description" : "A ComponentScope specifies a scope in which a component should exist.", - "properties" : { - "scopeRef" : { - "description" : "A ScopeReference must refer to an OAM scope resource.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - } - }, - "required" : [ "scopeRef" ], - "type" : "object" - }, - "type" : "array" - }, - "traits" : { - "description" : "Traits of the specified component.", - "items" : { - "description" : "A ComponentTrait specifies a trait that should be applied to a component.", - "properties" : { - "dataInputs" : { - "description" : "DataInputs specify the data input sinks into this trait.", - "items" : { - "description" : "DataInput specifies a data input sink to an object. If input is array, it will be appended to the target field paths.", - "properties" : { - "toFieldPaths" : { - "description" : "ToFieldPaths specifies the field paths of an object to fill passed value.", - "items" : { - "type" : "string" - }, - "type" : "array" - }, - "valueFrom" : { - "description" : "ValueFrom specifies the value source.", - "properties" : { - "dataOutputName" : { - "description" : "DataOutputName matches a name of a DataOutput in the same AppConfig.", - "type" : "string" - } - }, - "required" : [ "dataOutputName" ], - "type" : "object" - } - }, - "type" : "object" - }, - "type" : "array" - }, - "dataOutputs" : { - "description" : "DataOutputs specify the data output sources from this trait.", - "items" : { - "description" : "DataOutput specifies a data output source from an object.", - "properties" : { - "conditions" : { - "description" : "Conditions specify the conditions that should be satisfied before emitting a data output. Different conditions are AND-ed together. If no conditions is specified, it is by default to check output value not empty.", - "items" : { - "description" : "ConditionRequirement specifies the requirement to match a value.", - "properties" : { - "fieldPath" : { - "description" : "FieldPath specifies got value from workload/trait object", - "type" : "string" - }, - "op" : { - "description" : "ConditionOperator specifies the operator to match a value.", - "type" : "string" - }, - "value" : { - "description" : "Value specifies an expected value This is mutually exclusive with ValueFrom", - "type" : "string" - }, - "valueFrom" : { - "description" : "ValueFrom specifies expected value from AppConfig This is mutually exclusive with Value", - "properties" : { - "fieldPath" : { - "type" : "string" - } - }, - "required" : [ "fieldPath" ], - "type" : "object" - } - }, - "required" : [ "op" ], - "type" : "object" - }, - "type" : "array" - }, - "fieldPath" : { - "description" : "FieldPath refers to the value of an object's field.", - "type" : "string" - }, - "name" : { - "description" : "Name is the unique name of a DataOutput in an ApplicationConfiguration.", - "type" : "string" - } - }, - "type" : "object" - }, - "type" : "array" - }, - "trait" : { - "description" : "A Trait that will be created for the component", - "oneOf" : [ { - "description" : "IngressTrait specifies the ingress traits API.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type" : "string" - }, - "kind" : { - "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type" : "string" - }, - "metadata" : { - "type" : "object" - }, - "spec" : { - "description" : "IngressTraitSpec specifies the desired state of an ingress trait.", - "properties" : { - "rules" : { - "description" : "A list of ingress rules for an ingress trait.", - "items" : { - "description" : "IngressRule specifies a rule for an ingress trait.", - "properties" : { - "destination" : { - "description" : "The destination host and port for the ingress paths.", - "properties" : { - "host" : { - "description" : "Destination host.", - "type" : "string" - }, - "httpCookie" : { - "description" : "Session affinity cookie.", - "properties" : { - "name" : { - "description" : "The name of the HTTP cookie.", - "type" : "string" - }, - "path" : { - "description" : "The path of the HTTP cookie.", - "type" : "string" - }, - "ttl" : { - "description" : "The lifetime of the HTTP cookie (in seconds).", - "format" : "int64", - "type" : "integer" - } - }, - "type" : "object" - }, - "port" : { - "description" : "Destination port.", - "format" : "int32", - "type" : "integer" - } - }, - "type" : "object" - }, - "hosts" : { - "description" : "One or more hosts exposed by the ingress trait. Wildcard hosts or hosts that are empty are filtered out. If there are no valid hosts provided, then a DNS host name is automatically generated and used.", - "items" : { - "type" : "string" - }, - "type" : "array" - }, - "paths" : { - "description" : "The paths to be exposed for an ingress trait.", - "items" : { - "description" : "IngressPath specifies a specific path to be exposed for an ingress trait.", - "properties" : { - "authorizationPolicy" : { - "description" : "Defines the set of rules for authorizing a request.", - "properties" : { - "rules" : { - "description" : "Rules are used to match requests from request principals to specific paths given an optional list of conditions.", - "items" : { - "description" : "AuthorizationRule matches requests from a list of request principals that access a specific path subject to a list of conditions.", - "properties" : { - "from" : { - "description" : "Specifies the request principals for access to a request. An asterisk (*) will match when the value is not empty, for example, if any request principal is found in the request.", - "properties" : { - "requestPrincipals" : { - "description" : "Specifies the request principals for access to a request.", - "items" : { - "type" : "string" - }, - "type" : "array" - } - }, - "type" : "object" - }, - "when" : { - "description" : "Specifies a list of additional conditions for access to a request.", - "items" : { - "description" : "AuthorizationRuleCondition provides additional required attributes for authorization.", - "properties" : { - "key" : { - "description" : "The name of a request attribute.", - "type" : "string" - }, - "values" : { - "description" : "A list of allowed values for the attribute.", - "items" : { - "type" : "string" - }, - "type" : "array" - } - }, - "type" : "object" - }, - "type" : "array" - } - }, - "type" : "object" - }, - "type" : "array" - } - }, - "type" : "object" - }, - "path" : { - "description" : "If no path is provided, then it defaults to forward slash (`/`).", - "type" : "string" - }, - "pathType" : { - "description" : "Path type values are case-sensitive and formatted as follows:
  • `exact`: exact string match
  • `prefix`: prefix-based match
  • `regex`: regex-based match
Defaults to `prefix` if `path` specified is `/`; otherwise, defaults to `exact`.", - "type" : "string" - } - }, - "type" : "object" - }, - "type" : "array" - } - }, - "type" : "object" - }, - "type" : "array" - }, - "tls" : { - "description" : "The security parameters for an ingress trait. This is required only if specific hosts are given in an [IngressRule](#oam.verrazzano.io/v1alpha1.IngressRule).", - "properties" : { - "secretName" : { - "description" : "The name of a secret containing the certificate securing the transport. The specification of a secret here implies that a certificate was created for specific hosts, as specified in an [IngressRule](#oam.verrazzano.io/v1alpha1.IngressRule).", - "type" : "string" - } - }, - "type" : "object" - }, - "workloadRef" : { - "description" : "The WorkloadReference of the workload to which this trait applies. This value is populated by the OAM runtime when an ApplicationConfiguration resource is processed. When the ApplicationConfiguration is processed, a trait and a workload resource are created from the content of the ApplicationConfiguration. The WorkloadReference is provided in the trait by OAM to ensure that the trait controller can find the workload associated with the component containing the trait within the original ApplicationConfiguration.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - } - }, - "required" : [ "workloadRef" ], - "type" : "object" - }, - "status" : { - "description" : "The observed state of an ingress trait and related resources.", - "properties" : { - "conditions" : { - "description" : "Conditions of the resource.", - "items" : { - "description" : "A Condition that may apply to a resource.", - "properties" : { - "lastTransitionTime" : { - "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", - "format" : "date-time", - "type" : "string" - }, - "message" : { - "description" : "A Message containing details about this condition's last transition from one status to another, if any.", - "type" : "string" - }, - "reason" : { - "description" : "A Reason for this condition's last transition from one status to another.", - "type" : "string" - }, - "status" : { - "description" : "Status of this condition; is it currently True, False, or Unknown?", - "type" : "string" - }, - "type" : { - "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", - "type" : "string" - } - }, - "required" : [ "lastTransitionTime", "reason", "status", "type" ], - "type" : "object" - }, - "type" : "array" - }, - "resources" : { - "description" : "The resources managed by this ingress trait.", - "items" : { - "description" : "A TypedReference refers to an object by Name, Kind, and APIVersion. It is commonly used to reference cluster-scoped objects or objects where the namespace is already known.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - }, - "type" : "array" - } - }, - "type" : "object" - } - }, - "type" : "object" - }, { - "description" : "LoggingTrait specifies the logging traits API.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type" : "string" - }, - "kind" : { - "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type" : "string" - }, - "metadata" : { - "type" : "object" - }, - "spec" : { - "description" : "LoggingTraitSpec specifies the desired state of a logging trait.", - "properties" : { - "imagePullPolicy" : { - "description" : "The optional image pull policy for the Fluentd image provided by the user.", - "type" : "string" - }, - "loggingConfig" : { - "description" : "The configuration provided by the user for the Fluentd configuration that consists of fluentd.conf: `\\n ... and so on ...\\n`.", - "type" : "string" - }, - "loggingImage" : { - "description" : "The name of the custom Fluentd image.", - "type" : "string" - }, - "workloadRef" : { - "description" : "The WorkloadReference of the workload to which this trait applies. This value is populated by the OAM runtime when an ApplicationConfiguration resource is processed. When the ApplicationConfiguration is processed, a trait and a workload resource are created from the content of the ApplicationConfiguration. The WorkloadReference is provided in the trait by OAM to ensure that the trait controller can find the workload associated with the component containing the trait within the original ApplicationConfiguration.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - } - }, - "required" : [ "workloadRef" ], - "type" : "object" - }, - "status" : { - "description" : "The observed state of a logging trait and related resources.", - "properties" : { - "conditions" : { - "description" : "Conditions of the resource.", - "items" : { - "description" : "A Condition that may apply to a resource.", - "properties" : { - "lastTransitionTime" : { - "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", - "format" : "date-time", - "type" : "string" - }, - "message" : { - "description" : "A Message containing details about this condition's last transition from one status to another, if any.", - "type" : "string" - }, - "reason" : { - "description" : "A Reason for this condition's last transition from one status to another.", - "type" : "string" - }, - "status" : { - "description" : "Status of this condition; is it currently True, False, or Unknown?", - "type" : "string" - }, - "type" : { - "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", - "type" : "string" - } - }, - "required" : [ "lastTransitionTime", "reason", "status", "type" ], - "type" : "object" - }, - "type" : "array" - }, - "resources" : { - "description" : "The resources managed by this logging trait.", - "items" : { - "description" : "A TypedReference refers to an object by Name, Kind, and APIVersion. It is commonly used to reference cluster-scoped objects or objects where the namespace is already known.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - }, - "type" : "array" - } - }, - "type" : "object" - } - }, - "type" : "object" - }, { - "description" : "A ManualScalerTrait determines how many replicas a workload should have.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type" : "string" - }, - "kind" : { - "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type" : "string" - }, - "metadata" : { - "type" : "object" - }, - "spec" : { - "description" : "A ManualScalerTraitSpec defines the desired state of a ManualScalerTrait.", - "properties" : { - "replicaCount" : { - "description" : "ReplicaCount of the workload this trait applies to.", - "format" : "int32", - "type" : "integer" - }, - "workloadRef" : { - "description" : "WorkloadReference to the workload this trait applies to.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - } - }, - "required" : [ "replicaCount", "workloadRef" ], - "type" : "object" - }, - "status" : { - "description" : "A ManualScalerTraitStatus represents the observed state of a ManualScalerTrait.", - "properties" : { - "conditions" : { - "description" : "Conditions of the resource.", - "items" : { - "description" : "A Condition that may apply to a resource.", - "properties" : { - "lastTransitionTime" : { - "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", - "format" : "date-time", - "type" : "string" - }, - "message" : { - "description" : "A Message containing details about this condition's last transition from one status to another, if any.", - "type" : "string" - }, - "reason" : { - "description" : "A Reason for this condition's last transition from one status to another.", - "type" : "string" - }, - "status" : { - "description" : "Status of this condition; is it currently True, False, or Unknown?", - "type" : "string" - }, - "type" : { - "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", - "type" : "string" - } - }, - "required" : [ "lastTransitionTime", "reason", "status", "type" ], - "type" : "object" - }, - "type" : "array" - } - }, - "type" : "object" - } - }, - "type" : "object" - }, { - "description" : "MetricsTrait specifies the metrics trait API.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type" : "string" - }, - "kind" : { - "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type" : "string" - }, - "metadata" : { - "type" : "object" - }, - "spec" : { - "description" : "MetricsTraitSpec specifies the desired state of a metrics trait.", - "properties" : { - "enabled" : { - "description" : "Specifies whether metrics collection is enabled. Defaults to `true`.", - "type" : "boolean" - }, - "path" : { - "description" : "The HTTP path for the related metrics endpoint. Defaults to `/metrics`.", - "type" : "string" - }, - "port" : { - "description" : "The HTTP port for the related metrics trait. Defaults to `8080`.", - "type" : "integer" - }, - "ports" : { - "description" : "The HTTP endpoints for the related metrics.", - "items" : { - "description" : "PortSpec defines an HTTP port and path combination.", - "properties" : { - "path" : { - "description" : "The HTTP path for the related metrics endpoint. Defaults to `/metrics`.", - "type" : "string" - }, - "port" : { - "description" : "The HTTP port for the related metrics trait. Defaults to `8080`.", - "type" : "integer" - } - }, - "type" : "object" - }, - "type" : "array" - }, - "scraper" : { - "description" : "The Prometheus deployment used to scrape the related metrics endpoints. By default, the Verrazzano-supplied Prometheus component is used to scrape the endpoint.", - "type" : "string" - }, - "secret" : { - "description" : "The name of an opaque secret (for example, `username` and `password`) within the workload’s namespace for metrics endpoint access.", - "type" : "string" - }, - "workloadRef" : { - "description" : "The WorkloadReference of the workload to which this trait applies. This value is populated by the OAM runtime when an ApplicationConfiguration resource is processed. When the ApplicationConfiguration is processed, a trait and a workload resource are created from the content of the ApplicationConfiguration. The WorkloadReference is provided in the trait by OAM to ensure that the trait controller can find the workload associated with the component containing the trait within the original ApplicationConfiguration.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - } - }, - "required" : [ "workloadRef" ], - "type" : "object" - }, - "status" : { - "description" : "The observed state of a metrics trait and related resources.", - "properties" : { - "conditions" : { - "description" : "Conditions of the resource.", - "items" : { - "description" : "A Condition that may apply to a resource.", - "properties" : { - "lastTransitionTime" : { - "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", - "format" : "date-time", - "type" : "string" - }, - "message" : { - "description" : "A Message containing details about this condition's last transition from one status to another, if any.", - "type" : "string" - }, - "reason" : { - "description" : "A Reason for this condition's last transition from one status to another.", - "type" : "string" - }, - "status" : { - "description" : "Status of this condition; is it currently True, False, or Unknown?", - "type" : "string" - }, - "type" : { - "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", - "type" : "string" - } - }, - "required" : [ "lastTransitionTime", "reason", "status", "type" ], - "type" : "object" - }, - "type" : "array" - }, - "resources" : { - "description" : "Related resources affected by this metrics trait.", - "items" : { - "description" : "QualifiedResourceRelation identifies a specific related resource.", - "properties" : { - "apiversion" : { - "description" : "API version of the related resource.", - "type" : "string" - }, - "kind" : { - "description" : "Kind of the related resource.", - "type" : "string" - }, - "name" : { - "description" : "Name of the related resource.", - "type" : "string" - }, - "namespace" : { - "description" : "Namespace of the related resource.", - "type" : "string" - }, - "role" : { - "description" : "Role of the related resource, for example, `Deployment`.", - "type" : "string" - } - }, - "required" : [ "apiversion", "kind", "name", "namespace", "role" ], - "type" : "object" - }, - "type" : "array" - } - }, - "type" : "object" - } - }, - "type" : "object" - } ], - "type" : "object", - "x-kubernetes-embedded-resource" : true, - "x-kubernetes-preserve-unknown-fields" : true - } - }, - "required" : [ "trait" ], - "type" : "object" - }, - "type" : "array" - } - }, - "type" : "object" - }, - "type" : "array" - } - }, - "required" : [ "components" ], - "type" : "object" - }, - "status" : { - "description" : "An ApplicationConfigurationStatus represents the observed state of a ApplicationConfiguration.", - "properties" : { - "conditions" : { - "description" : "Conditions of the resource.", - "items" : { - "description" : "A Condition that may apply to a resource.", - "properties" : { - "lastTransitionTime" : { - "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", - "format" : "date-time", - "type" : "string" - }, - "message" : { - "description" : "A Message containing details about this condition's last transition from one status to another, if any.", - "type" : "string" - }, - "reason" : { - "description" : "A Reason for this condition's last transition from one status to another.", - "type" : "string" - }, - "status" : { - "description" : "Status of this condition; is it currently True, False, or Unknown?", - "type" : "string" - }, - "type" : { - "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", - "type" : "string" - } - }, - "required" : [ "lastTransitionTime", "reason", "status", "type" ], - "type" : "object" - }, - "type" : "array" - }, - "dependency" : { - "description" : "DependencyStatus represents the observed state of the dependency of an ApplicationConfiguration.", - "properties" : { - "unsatisfied" : { - "items" : { - "description" : "UnstaifiedDependency describes unsatisfied dependency flow between one pair of objects.", - "properties" : { - "from" : { - "description" : "DependencyFromObject represents the object that dependency data comes from.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "fieldPath" : { - "type" : "string" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - }, - "reason" : { - "type" : "string" - }, - "to" : { - "description" : "DependencyToObject represents the object that dependency data goes to.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "fieldPaths" : { - "items" : { - "type" : "string" - }, - "type" : "array" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - } - }, - "required" : [ "from", "reason", "to" ], - "type" : "object" - }, - "type" : "array" - } - }, - "type" : "object" - }, - "historyWorkloads" : { - "description" : "HistoryWorkloads will record history but still working revision workloads.", - "items" : { - "description" : "HistoryWorkload contain the old component revision that are still running", - "properties" : { - "revision" : { - "description" : "Revision of this workload", - "type" : "string" - }, - "workloadRef" : { - "description" : "Reference to running workload.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - } - }, - "type" : "object" - }, - "type" : "array" - }, - "observedGeneration" : { - "description" : "The generation observed by the appConfig controller.", - "format" : "int64", - "type" : "integer" - }, - "status" : { - "description" : "Status is a place holder for a customized controller to fill if it needs a single place to summarize the status of the entire application", - "type" : "string" - }, - "workloads" : { - "description" : "Workloads created by this ApplicationConfiguration.", - "items" : { - "description" : "A WorkloadStatus represents the status of a workload.", - "properties" : { - "componentName" : { - "description" : "ComponentName that produced this workload.", - "type" : "string" - }, - "componentRevisionName" : { - "description" : "ComponentRevisionName of current component", - "type" : "string" - }, - "scopes" : { - "description" : "Scopes associated with this workload.", - "items" : { - "description" : "A WorkloadScope represents a scope associated with a workload and its status", - "properties" : { - "scopeRef" : { - "description" : "Reference to a scope created by an ApplicationConfiguration.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - }, - "status" : { - "description" : "Status is a place holder for a customized controller to fill if it needs a single place to summarize the status of the scope", - "type" : "string" - } - }, - "required" : [ "scopeRef" ], - "type" : "object" - }, - "type" : "array" - }, - "status" : { - "description" : "Status is a place holder for a customized controller to fill if it needs a single place to summarize the entire status of the workload", - "type" : "string" - }, - "traits" : { - "description" : "Traits associated with this workload.", - "items" : { - "description" : "A WorkloadTrait represents a trait associated with a workload and its status", - "properties" : { - "message" : { - "description" : "Message will allow controller to leave some additional information for this trait", - "type" : "string" - }, - "status" : { - "description" : "Status is a place holder for a customized controller to fill if it needs a single place to summarize the status of the trait", - "type" : "string" - }, - "traitRef" : { - "description" : "Reference to a trait created by an ApplicationConfiguration.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - } - }, - "required" : [ "traitRef" ], - "type" : "object" - }, - "type" : "array" - }, - "workloadRef" : { - "description" : "Reference to a workload created by an ApplicationConfiguration.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion of the referenced object.", - "type" : "string" - }, - "kind" : { - "description" : "Kind of the referenced object.", - "type" : "string" - }, - "name" : { - "description" : "Name of the referenced object.", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referenced object.", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name" ], - "type" : "object" - } - }, - "type" : "object" - }, - "type" : "array" - } - }, - "type" : "object" - } - }, - "type" : "object" - } -} +{"openAPIV3Schema":{"properties":{"apiVersion":{"type":"string"},"kind":{"enum":["ApplicationConfiguration"],"type":"string"},"metadata":{"type":"object"},"spec":{"properties":{"components":{"items":{"properties":{"componentName":{"type":"string"},"dataInputs":{"items":{"properties":{"toFieldPaths":{"items":{"type":"string"},"type":"array"},"valueFrom":{"properties":{"dataOutputName":{"type":"string"}},"required":["dataOutputName"],"type":"object"}},"type":"object"},"type":"array"},"dataOutputs":{"items":{"properties":{"conditions":{"items":{"properties":{"fieldPath":{"type":"string"},"op":{"type":"string"},"value":{"type":"string"},"valueFrom":{"properties":{"fieldPath":{"type":"string"}},"required":["fieldPath"],"type":"object"}},"required":["op"],"type":"object"},"type":"array"},"fieldPath":{"type":"string"},"name":{"type":"string"}},"type":"object"},"type":"array"},"parameterValues":{"items":{"properties":{"name":{"type":"string"},"value":{"anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}},"required":["name","value"],"type":"object"},"type":"array"},"revisionName":{"type":"string"},"scopes":{"items":{"properties":{"scopeRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["scopeRef"],"type":"object"},"type":"array"},"traits":{"items":{"properties":{"dataInputs":{"items":{"properties":{"toFieldPaths":{"items":{"type":"string"},"type":"array"},"valueFrom":{"properties":{"dataOutputName":{"type":"string"}},"required":["dataOutputName"],"type":"object"}},"type":"object"},"type":"array"},"dataOutputs":{"items":{"properties":{"conditions":{"items":{"properties":{"fieldPath":{"type":"string"},"op":{"type":"string"},"value":{"type":"string"},"valueFrom":{"properties":{"fieldPath":{"type":"string"}},"required":["fieldPath"],"type":"object"}},"required":["op"],"type":"object"},"type":"array"},"fieldPath":{"type":"string"},"name":{"type":"string"}},"type":"object"},"type":"array"},"trait":{"oneOf":[{"description":"IngressTrait specifies the ingress traits API.","properties":{"apiVersion":{"description":"APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources","type":"string"},"kind":{"description":"Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds","enum":["IngressTrait"],"type":"string"},"metadata":{"type":"object"},"spec":{"description":"IngressTraitSpec specifies the desired state of an ingress trait.","properties":{"rules":{"description":"A list of ingress rules for an ingress trait.","items":{"description":"IngressRule specifies a rule for an ingress trait.","properties":{"destination":{"description":"The destination host and port for the ingress paths.","properties":{"host":{"description":"Destination host.","type":"string"},"httpCookie":{"description":"Session affinity cookie.","properties":{"name":{"description":"The name of the HTTP cookie.","type":"string"},"path":{"description":"The path of the HTTP cookie.","type":"string"},"ttl":{"description":"The lifetime of the HTTP cookie (in seconds).","format":"int64","type":"integer"}},"type":"object"},"port":{"description":"Destination port.","format":"int32","type":"integer"}},"type":"object"},"hosts":{"description":"One or more hosts exposed by the ingress trait. Wildcard hosts or hosts that are empty are filtered out. If there are no valid hosts provided, then a DNS host name is automatically generated and used.","items":{"type":"string"},"type":"array"},"paths":{"description":"The paths to be exposed for an ingress trait.","items":{"description":"IngressPath specifies a specific path to be exposed for an ingress trait.","properties":{"authorizationPolicy":{"description":"Defines the set of rules for authorizing a request.","properties":{"rules":{"description":"Rules are used to match requests from request principals to specific paths given an optional list of conditions.","items":{"description":"AuthorizationRule matches requests from a list of request principals that access a specific path subject to a list of conditions.","properties":{"from":{"description":"Specifies the request principals for access to a request. An asterisk (*) will match when the value is not empty, for example, if any request principal is found in the request.","properties":{"requestPrincipals":{"description":"Specifies the request principals for access to a request.","items":{"type":"string"},"type":"array"}},"type":"object"},"when":{"description":"Specifies a list of additional conditions for access to a request.","items":{"description":"AuthorizationRuleCondition provides additional required attributes for authorization.","properties":{"key":{"description":"The name of a request attribute.","type":"string"},"values":{"description":"A list of allowed values for the attribute.","items":{"type":"string"},"type":"array"}},"type":"object"},"type":"array"}},"type":"object"},"type":"array"}},"type":"object"},"path":{"description":"If no path is provided, then it defaults to forward slash (`/`).","type":"string"},"pathType":{"description":"Path type values are case-sensitive and formatted as follows:
  • `exact`: exact string match
  • `prefix`: prefix-based match
  • `regex`: regex-based match
Defaults to `prefix` if `path` specified is `/`; otherwise, defaults to `exact`.","type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"type":"array"},"tls":{"description":"The security parameters for an ingress trait. This is required only if specific hosts are given in an [IngressRule](#oam.verrazzano.io/v1alpha1.IngressRule).","properties":{"secretName":{"description":"The name of a secret containing the certificate securing the transport. The specification of a secret here implies that a certificate was created for specific hosts, as specified in an [IngressRule](#oam.verrazzano.io/v1alpha1.IngressRule).","type":"string"}},"type":"object"},"workloadRef":{"description":"The WorkloadReference of the workload to which this trait applies. This value is populated by the OAM runtime when an ApplicationConfiguration resource is processed. When the ApplicationConfiguration is processed, a trait and a workload resource are created from the content of the ApplicationConfiguration. The WorkloadReference is provided in the trait by OAM to ensure that the trait controller can find the workload associated with the component containing the trait within the original ApplicationConfiguration.","properties":{"apiVersion":{"description":"APIVersion of the referenced object.","type":"string"},"kind":{"description":"Kind of the referenced object.","type":"string"},"name":{"description":"Name of the referenced object.","type":"string"},"uid":{"description":"UID of the referenced object.","type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["workloadRef"],"type":"object"},"status":{"description":"The observed state of an ingress trait and related resources.","properties":{"conditions":{"description":"Conditions of the resource.","items":{"description":"A Condition that may apply to a resource.","properties":{"lastTransitionTime":{"description":"LastTransitionTime is the last time this condition transitioned from one status to another.","format":"date-time","type":"string"},"message":{"description":"A Message containing details about this condition's last transition from one status to another, if any.","type":"string"},"reason":{"description":"A Reason for this condition's last transition from one status to another.","type":"string"},"status":{"description":"Status of this condition; is it currently True, False, or Unknown?","type":"string"},"type":{"description":"Type of this condition. At most one of each condition type may apply to a resource at any point in time.","type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"},"resources":{"description":"The resources managed by this ingress trait.","items":{"description":"A TypedReference refers to an object by Name, Kind, and APIVersion. It is commonly used to reference cluster-scoped objects or objects where the namespace is already known.","properties":{"apiVersion":{"description":"APIVersion of the referenced object.","type":"string"},"kind":{"description":"Kind of the referenced object.","type":"string"},"name":{"description":"Name of the referenced object.","type":"string"},"uid":{"description":"UID of the referenced object.","type":"string"}},"required":["apiVersion","kind","name"],"type":"object"},"type":"array"}},"type":"object"}},"type":"object"},{"description":"LoggingTrait specifies the logging traits API.","properties":{"apiVersion":{"description":"APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources","type":"string"},"kind":{"description":"Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds","enum":["LoggingTrait"],"type":"string"},"metadata":{"type":"object"},"spec":{"description":"LoggingTraitSpec specifies the desired state of a logging trait.","properties":{"imagePullPolicy":{"description":"The optional image pull policy for the Fluentd image provided by the user.","type":"string"},"loggingConfig":{"description":"The configuration provided by the user for the Fluentd configuration that consists of fluentd.conf: `\\n ... and so on ...\\n`.","type":"string"},"loggingImage":{"description":"The name of the custom Fluentd image.","type":"string"},"workloadRef":{"description":"The WorkloadReference of the workload to which this trait applies. This value is populated by the OAM runtime when an ApplicationConfiguration resource is processed. When the ApplicationConfiguration is processed, a trait and a workload resource are created from the content of the ApplicationConfiguration. The WorkloadReference is provided in the trait by OAM to ensure that the trait controller can find the workload associated with the component containing the trait within the original ApplicationConfiguration.","properties":{"apiVersion":{"description":"APIVersion of the referenced object.","type":"string"},"kind":{"description":"Kind of the referenced object.","type":"string"},"name":{"description":"Name of the referenced object.","type":"string"},"uid":{"description":"UID of the referenced object.","type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["workloadRef"],"type":"object"},"status":{"description":"The observed state of a logging trait and related resources.","properties":{"conditions":{"description":"Conditions of the resource.","items":{"description":"A Condition that may apply to a resource.","properties":{"lastTransitionTime":{"description":"LastTransitionTime is the last time this condition transitioned from one status to another.","format":"date-time","type":"string"},"message":{"description":"A Message containing details about this condition's last transition from one status to another, if any.","type":"string"},"reason":{"description":"A Reason for this condition's last transition from one status to another.","type":"string"},"status":{"description":"Status of this condition; is it currently True, False, or Unknown?","type":"string"},"type":{"description":"Type of this condition. At most one of each condition type may apply to a resource at any point in time.","type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"},"resources":{"description":"The resources managed by this logging trait.","items":{"description":"A TypedReference refers to an object by Name, Kind, and APIVersion. It is commonly used to reference cluster-scoped objects or objects where the namespace is already known.","properties":{"apiVersion":{"description":"APIVersion of the referenced object.","type":"string"},"kind":{"description":"Kind of the referenced object.","type":"string"},"name":{"description":"Name of the referenced object.","type":"string"},"uid":{"description":"UID of the referenced object.","type":"string"}},"required":["apiVersion","kind","name"],"type":"object"},"type":"array"}},"type":"object"}},"type":"object"},{"description":"A ManualScalerTrait determines how many replicas a workload should have.","properties":{"apiVersion":{"description":"APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources","type":"string"},"kind":{"description":"Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds","enum":["ManualScalerTrait"],"type":"string"},"metadata":{"type":"object"},"spec":{"description":"A ManualScalerTraitSpec defines the desired state of a ManualScalerTrait.","properties":{"replicaCount":{"description":"ReplicaCount of the workload this trait applies to.","format":"int32","type":"integer"},"workloadRef":{"description":"WorkloadReference to the workload this trait applies to.","properties":{"apiVersion":{"description":"APIVersion of the referenced object.","type":"string"},"kind":{"description":"Kind of the referenced object.","type":"string"},"name":{"description":"Name of the referenced object.","type":"string"},"uid":{"description":"UID of the referenced object.","type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["replicaCount","workloadRef"],"type":"object"},"status":{"description":"A ManualScalerTraitStatus represents the observed state of a ManualScalerTrait.","properties":{"conditions":{"description":"Conditions of the resource.","items":{"description":"A Condition that may apply to a resource.","properties":{"lastTransitionTime":{"description":"LastTransitionTime is the last time this condition transitioned from one status to another.","format":"date-time","type":"string"},"message":{"description":"A Message containing details about this condition's last transition from one status to another, if any.","type":"string"},"reason":{"description":"A Reason for this condition's last transition from one status to another.","type":"string"},"status":{"description":"Status of this condition; is it currently True, False, or Unknown?","type":"string"},"type":{"description":"Type of this condition. At most one of each condition type may apply to a resource at any point in time.","type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"}},"type":"object"}},"type":"object"},{"description":"MetricsTrait specifies the metrics trait API.","properties":{"apiVersion":{"description":"APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources","type":"string"},"kind":{"description":"Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds","enum":["MetricsTrait"],"type":"string"},"metadata":{"type":"object"},"spec":{"description":"MetricsTraitSpec specifies the desired state of a metrics trait.","properties":{"enabled":{"description":"Specifies whether metrics collection is enabled. Defaults to `true`.","type":"boolean"},"path":{"description":"The HTTP path for the related metrics endpoint. Defaults to `/metrics`.","type":"string"},"port":{"description":"The HTTP port for the related metrics trait. Defaults to `8080`.","type":"integer"},"ports":{"description":"The HTTP endpoints for the related metrics.","items":{"description":"PortSpec defines an HTTP port and path combination.","properties":{"path":{"description":"The HTTP path for the related metrics endpoint. Defaults to `/metrics`.","type":"string"},"port":{"description":"The HTTP port for the related metrics trait. Defaults to `8080`.","type":"integer"}},"type":"object"},"type":"array"},"scraper":{"description":"The Prometheus deployment used to scrape the related metrics endpoints. By default, the Verrazzano-supplied Prometheus component is used to scrape the endpoint.","type":"string"},"secret":{"description":"The name of an opaque secret (for example, `username` and `password`) within the workload’s namespace for metrics endpoint access.","type":"string"},"workloadRef":{"description":"The WorkloadReference of the workload to which this trait applies. This value is populated by the OAM runtime when an ApplicationConfiguration resource is processed. When the ApplicationConfiguration is processed, a trait and a workload resource are created from the content of the ApplicationConfiguration. The WorkloadReference is provided in the trait by OAM to ensure that the trait controller can find the workload associated with the component containing the trait within the original ApplicationConfiguration.","properties":{"apiVersion":{"description":"APIVersion of the referenced object.","type":"string"},"kind":{"description":"Kind of the referenced object.","type":"string"},"name":{"description":"Name of the referenced object.","type":"string"},"uid":{"description":"UID of the referenced object.","type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["workloadRef"],"type":"object"},"status":{"description":"The observed state of a metrics trait and related resources.","properties":{"conditions":{"description":"Conditions of the resource.","items":{"description":"A Condition that may apply to a resource.","properties":{"lastTransitionTime":{"description":"LastTransitionTime is the last time this condition transitioned from one status to another.","format":"date-time","type":"string"},"message":{"description":"A Message containing details about this condition's last transition from one status to another, if any.","type":"string"},"reason":{"description":"A Reason for this condition's last transition from one status to another.","type":"string"},"status":{"description":"Status of this condition; is it currently True, False, or Unknown?","type":"string"},"type":{"description":"Type of this condition. At most one of each condition type may apply to a resource at any point in time.","type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"},"resources":{"description":"Related resources affected by this metrics trait.","items":{"description":"QualifiedResourceRelation identifies a specific related resource.","properties":{"apiversion":{"description":"API version of the related resource.","type":"string"},"kind":{"description":"Kind of the related resource.","type":"string"},"name":{"description":"Name of the related resource.","type":"string"},"namespace":{"description":"Namespace of the related resource.","type":"string"},"role":{"description":"Role of the related resource, for example, `Deployment`.","type":"string"}},"required":["apiversion","kind","name","namespace","role"],"type":"object"},"type":"array"}},"type":"object"}},"type":"object"}],"type":"object","x-kubernetes-embedded-resource":true,"x-kubernetes-preserve-unknown-fields":true}},"required":["trait"],"type":"object"},"type":"array"}},"type":"object"},"type":"array"}},"required":["components"],"type":"object"},"status":{"properties":{"conditions":{"items":{"properties":{"lastTransitionTime":{"format":"date-time","type":"string"},"message":{"type":"string"},"reason":{"type":"string"},"status":{"type":"string"},"type":{"type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"},"dependency":{"properties":{"unsatisfied":{"items":{"properties":{"from":{"properties":{"apiVersion":{"type":"string"},"fieldPath":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"},"reason":{"type":"string"},"to":{"properties":{"apiVersion":{"type":"string"},"fieldPaths":{"items":{"type":"string"},"type":"array"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["from","reason","to"],"type":"object"},"type":"array"}},"type":"object"},"historyWorkloads":{"items":{"properties":{"revision":{"type":"string"},"workloadRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"type":"object"},"type":"array"},"observedGeneration":{"format":"int64","type":"integer"},"status":{"type":"string"},"workloads":{"items":{"properties":{"componentName":{"type":"string"},"componentRevisionName":{"type":"string"},"scopes":{"items":{"properties":{"scopeRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"},"status":{"type":"string"}},"required":["scopeRef"],"type":"object"},"type":"array"},"status":{"type":"string"},"traits":{"items":{"properties":{"message":{"type":"string"},"status":{"type":"string"},"traitRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"required":["traitRef"],"type":"object"},"type":"array"},"workloadRef":{"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name"],"type":"object"}},"type":"object"},"type":"array"}},"type":"object"}},"type":"object"}} diff --git a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha1.json b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha1.json index f1e87528f..c67216fdf 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha1.json +++ b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-configmap-v1alpha1.json @@ -1,384 +1 @@ -{ - "openAPIV3Schema" : { - "description" : "A Component describes how an OAM workload kind may be instantiated.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type" : "string" - }, - "kind" : { - "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type" : "string" - }, - "metadata" : { - "type" : "object" - }, - "spec" : { - "description" : "A ComponentSpec defines the desired state of a Component.", - "properties" : { - "parameters" : { - "description" : "Parameters exposed by this component. ApplicationConfigurations that reference this component may specify values for these parameters, which will in turn be injected into the embedded workload.", - "items" : { - "description" : "A ComponentParameter defines a configurable parameter of a component.", - "properties" : { - "description" : { - "description" : "Description of this parameter.", - "type" : "string" - }, - "fieldPaths" : { - "description" : "FieldPaths specifies an array of fields within this Component's workload that will be overwritten by the value of this parameter. The type of the parameter (e.g. int, string) is inferred from the type of these fields; All fields must be of the same type. Fields are specified as JSON field paths without a leading dot, for example 'spec.replicas'.", - "items" : { - "type" : "string" - }, - "type" : "array" - }, - "name" : { - "description" : "Name of this parameter. OAM ApplicationConfigurations will specify parameter values using this name.", - "type" : "string" - }, - "required" : { - "default" : false, - "description" : "Required specifies whether or not a value for this parameter must be supplied when authoring an ApplicationConfiguration.", - "type" : "boolean" - } - }, - "required" : [ "fieldPaths", "name" ], - "type" : "object" - }, - "type" : "array" - }, - "workload" : { - "description" : "ConfigMap holds configuration data for pods to consume.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", - "type" : "string" - }, - "binaryData" : { - "additionalProperties" : { - "format" : "byte", - "type" : "string" - }, - "description" : "BinaryData contains the binary data. Each key must consist of alphanumeric characters, '-', '_' or '.'. BinaryData can contain byte sequences that are not in the UTF-8 range. The keys stored in BinaryData must not overlap with the ones in the Data field, this is enforced during validation process. Using this field will require 1.10+ apiserver and kubelet.", - "type" : "object" - }, - "data" : { - "additionalProperties" : { - "type" : "string" - }, - "description" : "Data contains the configuration data. Each key must consist of alphanumeric characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use the BinaryData field. The keys stored in Data must not overlap with the keys in the BinaryData field, this is enforced during validation process.", - "type" : "object" - }, - "kind" : { - "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "enum" : [ "ConfigMap" ], - "type" : "string" - }, - "metadata" : { - "description" : "ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create.", - "properties" : { - "annotations" : { - "additionalProperties" : { - "type" : "string" - }, - "description" : "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations", - "type" : "object" - }, - "clusterName" : { - "description" : "The name of the cluster which the object belongs to. This is used to distinguish resources with same name and namespace in different clusters. This field is not set anywhere right now and apiserver is going to ignore it if set in create or update request.", - "type" : "string" - }, - "creationTimestamp" : { - "description" : "Time is a wrapper around time.Time which supports correct marshaling to YAML and JSON. Wrappers are provided for many of the factory methods that the time package offers.", - "format" : "date-time", - "type" : "string" - }, - "deletionGracePeriodSeconds" : { - "description" : "Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only.", - "format" : "int64", - "type" : "integer" - }, - "deletionTimestamp" : { - "description" : "Time is a wrapper around time.Time which supports correct marshaling to YAML and JSON. Wrappers are provided for many of the factory methods that the time package offers.", - "format" : "date-time", - "type" : "string" - }, - "finalizers" : { - "description" : "Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed.", - "items" : { - "type" : "string" - }, - "type" : "array", - "x-kubernetes-patch-strategy" : "merge" - }, - "generateName" : { - "description" : "GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server.\n\nIf this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header).\n\nApplied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#idempotency", - "type" : "string" - }, - "generation" : { - "description" : "A sequence number representing a specific generation of the desired state. Populated by the system. Read-only.", - "format" : "int64", - "type" : "integer" - }, - "initializers" : { - "description" : "Initializers tracks the progress of initialization.", - "properties" : { - "pending" : { - "description" : "Pending is a list of initializers that must execute in order before this object is visible. When the last pending initializer is removed, and no failing result is set, the initializers struct will be set to nil and the object is considered as initialized and visible to all clients.", - "items" : { - "description" : "Initializer is information about an initializer that has not yet completed.", - "properties" : { - "name" : { - "description" : "name of the process that is responsible for initializing this object.", - "type" : "string" - } - }, - "required" : [ "name" ] - }, - "type" : "array", - "x-kubernetes-patch-merge-key" : "name", - "x-kubernetes-patch-strategy" : "merge" - }, - "result" : { - "description" : "Status is a return value for calls that don't return other objects.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", - "type" : "string" - }, - "code" : { - "description" : "Suggested HTTP return code for this status, 0 if not set.", - "format" : "int32", - "type" : "integer" - }, - "details" : { - "description" : "StatusDetails is a set of additional properties that MAY be set by the server to provide additional information about a response. The Reason field of a Status object defines what attributes will be set. Clients must ignore fields that do not match the defined type of each attribute, and should assume that any attribute may be empty, invalid, or under defined.", - "properties" : { - "causes" : { - "description" : "The Causes array includes more details associated with the StatusReason failure. Not all StatusReasons may provide detailed causes.", - "items" : { - "description" : "StatusCause provides more information about an api.Status failure, including cases when multiple errors are encountered.", - "properties" : { - "field" : { - "description" : "The field of the resource that has caused this error, as named by its JSON serialization. May include dot and postfix notation for nested attributes. Arrays are zero-indexed. Fields may appear more than once in an array of causes due to fields having multiple errors. Optional.\n\nExamples:\n \"name\" - the field \"name\" on the current resource\n \"items[0].name\" - the field \"name\" on the first array entry in \"items\"", - "type" : "string" - }, - "message" : { - "description" : "A human-readable description of the cause of the error. This field may be presented as-is to a reader.", - "type" : "string" - }, - "reason" : { - "description" : "A machine-readable description of the cause of the error. If this value is empty there is no information available.", - "type" : "string" - } - } - }, - "type" : "array" - }, - "group" : { - "description" : "The group attribute of the resource associated with the status StatusReason.", - "type" : "string" - }, - "kind" : { - "description" : "The kind attribute of the resource associated with the status StatusReason. On some operations may differ from the requested resource Kind. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "type" : "string" - }, - "name" : { - "description" : "The name attribute of the resource associated with the status StatusReason (when there is a single name which can be described).", - "type" : "string" - }, - "retryAfterSeconds" : { - "description" : "If specified, the time in seconds before the operation should be retried. Some errors may indicate the client must take an alternate action - for those errors this field may indicate how long to wait before taking the alternate action.", - "format" : "int32", - "type" : "integer" - }, - "uid" : { - "description" : "UID of the resource. (when there is a single resource which can be described). More info: http://kubernetes.io/docs/user-guide/identifiers#uids", - "type" : "string" - } - } - }, - "kind" : { - "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "enum" : [ "Status" ], - "type" : "string" - }, - "message" : { - "description" : "A human-readable description of the status of this operation.", - "type" : "string" - }, - "metadata" : { - "description" : "ListMeta describes metadata that synthetic resources must have, including lists and various status objects. A resource may have only one of {ObjectMeta, ListMeta}.", - "properties" : { - "continue" : { - "description" : "continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message.", - "type" : "string" - }, - "resourceVersion" : { - "description" : "String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency", - "type" : "string" - }, - "selfLink" : { - "description" : "selfLink is a URL representing this object. Populated by the system. Read-only.", - "type" : "string" - } - } - }, - "reason" : { - "description" : "A machine-readable description of why this operation is in the \"Failure\" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it.", - "type" : "string" - }, - "status" : { - "description" : "Status of the operation. One of: \"Success\" or \"Failure\". More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status", - "type" : "string" - } - }, - "x-kubernetes-group-version-kind" : [ { - "group" : "", - "kind" : "Status", - "version" : "v1" - } ] - } - }, - "required" : [ "pending" ] - }, - "labels" : { - "additionalProperties" : { - "type" : "string" - }, - "description" : "Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels", - "type" : "object" - }, - "name" : { - "description" : "Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names", - "type" : "string" - }, - "namespace" : { - "description" : "Namespace defines the space within each name must be unique. An empty namespace is equivalent to the \"default\" namespace, but \"default\" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty.\n\nMust be a DNS_LABEL. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/namespaces", - "type" : "string" - }, - "ownerReferences" : { - "description" : "List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller.", - "items" : { - "description" : "OwnerReference contains enough information to let you identify an owning object. An owning object must be in the same namespace as the dependent, or be cluster-scoped, so there is no namespace field.", - "properties" : { - "apiVersion" : { - "description" : "API version of the referent.", - "type" : "string" - }, - "blockOwnerDeletion" : { - "description" : "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. Defaults to false. To set this field, a user needs \"delete\" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned.", - "type" : "boolean" - }, - "controller" : { - "description" : "If true, this reference points to the managing controller.", - "type" : "boolean" - }, - "kind" : { - "description" : "Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", - "type" : "string" - }, - "name" : { - "description" : "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names", - "type" : "string" - }, - "uid" : { - "description" : "UID of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#uids", - "type" : "string" - } - }, - "required" : [ "apiVersion", "kind", "name", "uid" ] - }, - "type" : "array", - "x-kubernetes-patch-merge-key" : "uid", - "x-kubernetes-patch-strategy" : "merge" - }, - "resourceVersion" : { - "description" : "An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources.\n\nPopulated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency", - "type" : "string" - }, - "selfLink" : { - "description" : "SelfLink is a URL representing this object. Populated by the system. Read-only.", - "type" : "string" - }, - "uid" : { - "description" : "UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations.\n\nPopulated by the system. Read-only. More info: http://kubernetes.io/docs/user-guide/identifiers#uids", - "type" : "string" - } - } - } - }, - "type" : "object", - "x-kubernetes-embedded-resource" : true, - "x-kubernetes-group-version-kind" : [ { - "group" : "", - "kind" : "ConfigMap", - "version" : "v1" - } ], - "x-kubernetes-preserve-unknown-fields" : true - } - }, - "required" : [ "workload" ], - "type" : "object" - }, - "status" : { - "description" : "A ComponentStatus represents the observed state of a Component.", - "properties" : { - "conditions" : { - "description" : "Conditions of the resource.", - "items" : { - "description" : "A Condition that may apply to a resource.", - "properties" : { - "lastTransitionTime" : { - "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", - "format" : "date-time", - "type" : "string" - }, - "message" : { - "description" : "A Message containing details about this condition's last transition from one status to another, if any.", - "type" : "string" - }, - "reason" : { - "description" : "A Reason for this condition's last transition from one status to another.", - "type" : "string" - }, - "status" : { - "description" : "Status of this condition; is it currently True, False, or Unknown?", - "type" : "string" - }, - "type" : { - "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", - "type" : "string" - } - }, - "required" : [ "lastTransitionTime", "reason", "status", "type" ], - "type" : "object" - }, - "type" : "array" - }, - "latestRevision" : { - "description" : "LatestRevision of component", - "properties" : { - "name" : { - "type" : "string" - }, - "revision" : { - "format" : "int64", - "type" : "integer" - } - }, - "required" : [ "name", "revision" ], - "type" : "object" - }, - "observedGeneration" : { - "description" : "The generation observed by the component controller.", - "format" : "int64", - "type" : "integer" - } - }, - "type" : "object" - } - }, - "type" : "object" - } -} +{"openAPIV3Schema":{"properties":{"apiVersion":{"type":"string"},"kind":{"enum":["Component"],"type":"string"},"metadata":{"type":"object"},"spec":{"properties":{"parameters":{"items":{"properties":{"description":{"type":"string"},"fieldPaths":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"required":{"default":false,"type":"boolean"}},"required":["fieldPaths","name"],"type":"object"},"type":"array"},"workload":{"properties":{"apiVersion":{"type":"string"},"binaryData":{"additionalProperties":{"format":"byte","type":"string"},"type":"object"},"data":{"additionalProperties":{"type":"string"},"type":"object"},"kind":{"enum":["ConfigMap"],"type":"string"},"metadata":{"properties":{"annotations":{"additionalProperties":{"type":"string"},"type":"object"},"clusterName":{"type":"string"},"creationTimestamp":{"format":"date-time","type":"string"},"deletionGracePeriodSeconds":{"format":"int64","type":"integer"},"deletionTimestamp":{"format":"date-time","type":"string"},"finalizers":{"items":{"type":"string"},"type":"array","x-kubernetes-patch-strategy":"merge"},"generateName":{"type":"string"},"generation":{"format":"int64","type":"integer"},"initializers":{"properties":{"pending":{"items":{"properties":{"name":{"type":"string"}},"required":["name"]},"type":"array","x-kubernetes-patch-merge-key":"name","x-kubernetes-patch-strategy":"merge"},"result":{"properties":{"apiVersion":{"type":"string"},"code":{"format":"int32","type":"integer"},"details":{"properties":{"causes":{"items":{"properties":{"field":{"type":"string"},"message":{"type":"string"},"reason":{"type":"string"}}},"type":"array"},"group":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"retryAfterSeconds":{"format":"int32","type":"integer"},"uid":{"type":"string"}}},"kind":{"enum":["Status"],"type":"string"},"message":{"type":"string"},"metadata":{"properties":{"continue":{"type":"string"},"resourceVersion":{"type":"string"},"selfLink":{"type":"string"}}},"reason":{"type":"string"},"status":{"type":"string"}},"x-kubernetes-group-version-kind":[{"group":"","kind":"Status","version":"v1"}]}},"required":["pending"]},"labels":{"additionalProperties":{"type":"string"},"type":"object"},"name":{"type":"string"},"namespace":{"type":"string"},"ownerReferences":{"items":{"properties":{"apiVersion":{"type":"string"},"blockOwnerDeletion":{"type":"boolean"},"controller":{"type":"boolean"},"kind":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["apiVersion","kind","name","uid"]},"type":"array","x-kubernetes-patch-merge-key":"uid","x-kubernetes-patch-strategy":"merge"},"resourceVersion":{"type":"string"},"selfLink":{"type":"string"},"uid":{"type":"string"}}}},"type":"object","x-kubernetes-embedded-resource":true,"x-kubernetes-group-version-kind":[{"group":"","kind":"ConfigMap","version":"v1"}],"x-kubernetes-preserve-unknown-fields":true}},"required":["workload"],"type":"object"},"status":{"properties":{"conditions":{"items":{"properties":{"lastTransitionTime":{"format":"date-time","type":"string"},"message":{"type":"string"},"reason":{"type":"string"},"status":{"type":"string"},"type":{"type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"},"latestRevision":{"properties":{"name":{"type":"string"},"revision":{"format":"int64","type":"integer"}},"required":["name","revision"],"type":"object"},"observedGeneration":{"format":"int64","type":"integer"}},"type":"object"}},"type":"object"}} diff --git a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha1.json b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha1.json index 13ca2cf04..26f24d024 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha1.json +++ b/core/src/main/resources/oracle/weblogic/deploy/crds/vz-weblogic-v1alpha1.json @@ -1,197 +1 @@ -{ - "openAPIV3Schema" : { - "description" : "A Component describes how an OAM workload kind may be instantiated.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type" : "string" - }, - "kind" : { - "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type" : "string" - }, - "metadata" : { - "type" : "object" - }, - "spec" : { - "description" : "A ComponentSpec defines the desired state of a Component.", - "properties" : { - "parameters" : { - "description" : "Parameters exposed by this component. ApplicationConfigurations that reference this component may specify values for these parameters, which will in turn be injected into the embedded workload.", - "items" : { - "description" : "A ComponentParameter defines a configurable parameter of a component.", - "properties" : { - "description" : { - "description" : "Description of this parameter.", - "type" : "string" - }, - "fieldPaths" : { - "description" : "FieldPaths specifies an array of fields within this Component's workload that will be overwritten by the value of this parameter. The type of the parameter (e.g. int, string) is inferred from the type of these fields; All fields must be of the same type. Fields are specified as JSON field paths without a leading dot, for example 'spec.replicas'.", - "items" : { - "type" : "string" - }, - "type" : "array" - }, - "name" : { - "description" : "Name of this parameter. OAM ApplicationConfigurations will specify parameter values using this name.", - "type" : "string" - }, - "required" : { - "default" : false, - "description" : "Required specifies whether or not a value for this parameter must be supplied when authoring an ApplicationConfiguration.", - "type" : "boolean" - } - }, - "required" : [ "fieldPaths", "name" ], - "type" : "object" - }, - "type" : "array" - }, - "workload" : { - "description" : "VerrazzanoWebLogicWorkload specifies the Verrazzano WebLogic workload API.", - "properties" : { - "apiVersion" : { - "description" : "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type" : "string" - }, - "kind" : { - "description" : "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type" : "string" - }, - "metadata" : { - "type" : "object" - }, - "spec" : { - "description" : "The desired state of a Verrazzano WebLogic workload.", - "properties" : { - "clusters" : { - "items" : { - "properties" : { - "apiVersion" : { - "type" : "string" - }, - "metadata" : { - "type" : "object", - "x-kubernetes-preserve-unknown-fields" : true - }, - "spec" : { - "type" : "object", - "x-kubernetes-preserve-unknown-fields" : true - } - }, - "required" : [ "spec" ], - "type" : "object" - }, - "type" : "array" - }, - "template" : { - "description" : "The metadata and spec for the underlying Domain resource.", - "properties" : { - "apiVersion" : { - "type" : "string" - }, - "metadata" : { - "type" : "object", - "x-kubernetes-preserve-unknown-fields" : true - }, - "spec" : { - "type" : "object", - "x-kubernetes-preserve-unknown-fields" : true - } - }, - "required" : [ "spec" ], - "type" : "object", - "x-kubernetes-preserve-unknown-fields" : true - } - }, - "required" : [ "template" ], - "type" : "object" - }, - "status" : { - "description" : "The observed state of a Verrazzano WebLogic workload.", - "properties" : { - "lastGeneration" : { - "description" : "The last generation of the Verrazzano WebLogic workload that was reconciled.", - "type" : "string" - }, - "lastLifecycleAction" : { - "description" : "The last value of the `verrazzano.io/lifecycle-action`.", - "type" : "string" - }, - "lastRestartVersion" : { - "description" : "The last value of the `verrazzano.io/restart-version` annotation.", - "type" : "string" - } - }, - "type" : "object" - } - }, - "type" : "object", - "x-kubernetes-embedded-resource" : true, - "x-kubernetes-preserve-unknown-fields" : true - } - }, - "required" : [ "workload" ], - "type" : "object" - }, - "status" : { - "description" : "A ComponentStatus represents the observed state of a Component.", - "properties" : { - "conditions" : { - "description" : "Conditions of the resource.", - "items" : { - "description" : "A Condition that may apply to a resource.", - "properties" : { - "lastTransitionTime" : { - "description" : "LastTransitionTime is the last time this condition transitioned from one status to another.", - "format" : "date-time", - "type" : "string" - }, - "message" : { - "description" : "A Message containing details about this condition's last transition from one status to another, if any.", - "type" : "string" - }, - "reason" : { - "description" : "A Reason for this condition's last transition from one status to another.", - "type" : "string" - }, - "status" : { - "description" : "Status of this condition; is it currently True, False, or Unknown?", - "type" : "string" - }, - "type" : { - "description" : "Type of this condition. At most one of each condition type may apply to a resource at any point in time.", - "type" : "string" - } - }, - "required" : [ "lastTransitionTime", "reason", "status", "type" ], - "type" : "object" - }, - "type" : "array" - }, - "latestRevision" : { - "description" : "LatestRevision of component", - "properties" : { - "name" : { - "type" : "string" - }, - "revision" : { - "format" : "int64", - "type" : "integer" - } - }, - "required" : [ "name", "revision" ], - "type" : "object" - }, - "observedGeneration" : { - "description" : "The generation observed by the component controller.", - "format" : "int64", - "type" : "integer" - } - }, - "type" : "object" - } - }, - "type" : "object" - } -} +{"openAPIV3Schema":{"properties":{"apiVersion":{"type":"string"},"kind":{"enum":["Component"],"type":"string"},"metadata":{"type":"object"},"spec":{"properties":{"parameters":{"items":{"properties":{"description":{"type":"string"},"fieldPaths":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"required":{"default":false,"type":"boolean"}},"required":["fieldPaths","name"],"type":"object"},"type":"array"},"workload":{"properties":{"apiVersion":{"type":"string"},"kind":{"enum":["VerrazzanoWebLogicWorkload"],"type":"string"},"metadata":{"type":"object"},"spec":{"properties":{"clusters":{"items":{"properties":{"apiVersion":{"type":"string"},"metadata":{"type":"object","x-kubernetes-preserve-unknown-fields":true},"spec":{"type":"object","x-kubernetes-preserve-unknown-fields":true}},"required":["spec"],"type":"object"},"type":"array"},"template":{"properties":{"apiVersion":{"type":"string"},"metadata":{"type":"object","x-kubernetes-preserve-unknown-fields":true},"spec":{"type":"object","x-kubernetes-preserve-unknown-fields":true}},"required":["spec"],"type":"object","x-kubernetes-preserve-unknown-fields":true}},"required":["template"],"type":"object"},"status":{"properties":{"lastGeneration":{"type":"string"},"lastLifecycleAction":{"type":"string"},"lastRestartVersion":{"type":"string"}},"type":"object"}},"type":"object","x-kubernetes-embedded-resource":true,"x-kubernetes-preserve-unknown-fields":true}},"required":["workload"],"type":"object"},"status":{"properties":{"conditions":{"items":{"properties":{"lastTransitionTime":{"format":"date-time","type":"string"},"message":{"type":"string"},"reason":{"type":"string"},"status":{"type":"string"},"type":{"type":"string"}},"required":["lastTransitionTime","reason","status","type"],"type":"object"},"type":"array"},"latestRevision":{"properties":{"name":{"type":"string"},"revision":{"format":"int64","type":"integer"}},"required":["name","revision"],"type":"object"},"observedGeneration":{"format":"int64","type":"integer"}},"type":"object"}},"type":"object"}} From 7c408d2cfd238f92c5bf424d2a90b811d8dd8a73 Mon Sep 17 00:00:00 2001 From: Richard Killen Date: Mon, 23 Jan 2023 14:32:05 -0600 Subject: [PATCH 06/10] Allow multiple content options for Verrazzano application traits in model help --- .../modelhelp/model_crd_section_printer.py | 89 ++++++++++++++++++- .../tool/modelhelp/model_help_printer.py | 2 +- .../deploy/messages/wlsdeploy_rb.properties | 2 + 3 files changed, 88 insertions(+), 5 deletions(-) diff --git a/core/src/main/python/wlsdeploy/tool/modelhelp/model_crd_section_printer.py b/core/src/main/python/wlsdeploy/tool/modelhelp/model_crd_section_printer.py index 016131b6f..6b725c017 100644 --- a/core/src/main/python/wlsdeploy/tool/modelhelp/model_crd_section_printer.py +++ b/core/src/main/python/wlsdeploy/tool/modelhelp/model_crd_section_printer.py @@ -9,6 +9,7 @@ from wlsdeploy.tool.modelhelp import model_help_utils from wlsdeploy.tool.modelhelp.model_help_utils import ControlOptions import wlsdeploy.util.unicode_helper as str_helper +from wlsdeploy.util import dictionary_utils from wlsdeploy.util.exit_code import ExitCode @@ -127,25 +128,49 @@ def _print_model_folder_sample(self, section_name, model_path_tokens, control_op current_folder = schema for token in model_path_tokens[token_index:]: + lookup_token = token + option_key = None + + # check for a folder with multiple options, such as (verrazzano/.../trait#MetricsTrait) + if '#' in token: + parts = token.split('#', 1) + lookup_token = parts[0] + option_key = parts[1] + properties = _get_properties(current_folder) valid_subfolder_keys = _get_folder_names(properties) - if token not in valid_subfolder_keys: + if lookup_token not in valid_subfolder_keys: ex = exception_helper.create_cla_exception(ExitCode.ARG_VALIDATION_ERROR, - "WLSDPLY-10111", model_path, token, + "WLSDPLY-10111", model_path, lookup_token, ', '.join(valid_subfolder_keys)) self._logger.throwing(ex, class_name=self._class_name, method_name=_method_name) raise ex - current_folder = properties[token] + current_folder = properties[lookup_token] + + # find matching option if folder has multiple options, such as (verrazzano/.../trait#MetricsTrait) + token_suffix = '' + folder_options = schema_helper.get_one_of_options(current_folder) + if folder_options and option_key is not None: + token_suffix = ' # ' + option_key + current_folder = self._find_folder_option(folder_options, option_key, model_path + '/' + lookup_token) - _print_indent(token + ":", indent, in_object_array) + _print_indent(lookup_token + ":" + token_suffix, indent, in_object_array) indent += 1 # apply to the next folder in the path in_object_array = schema_helper.is_object_array(current_folder) model_path = model_path + "/" + token + # finished writing the parent folders + + # if this is a folder with multiple options, list the options and return + folder_options = schema_helper.get_one_of_options(current_folder) + if folder_options: + print_folder_options(folder_options, model_path, indent) + return + # list the attributes and folders, as specified if model_help_utils.show_attributes(control_option): @@ -252,6 +277,33 @@ def _print_attributes_sample(self, schema_folder, indent_level, in_object_array) return in_object_array + def _find_folder_option(self, folder_options, option_key, model_path): + """ + Return the folder option that matches the specified index key. + Try matching "kind" field of each option, then try lookup by numeric index. + Throw an exception if no matching option is found. + :param folder_options: the options to be examined + :param option_key: the key to check against + :param model_path: used for error logging + :return: the matching option + """ + _method_name = '_find_folder_option' + + for folder_option in folder_options: + key = _get_kind_value(folder_option) + if key == option_key: + return folder_option + + if option_key.isdecimal(): + index = int(option_key) + if (index > -1) and (index < len(folder_options)): + return folder_options[index] + + ex = exception_helper.create_cla_exception(ExitCode.ARG_VALIDATION_ERROR, "WLSDPLY-10115", + model_path, '#' + option_key) + self._logger.throwing(ex, class_name=self._class_name, method_name=_method_name) + raise ex + def _get_properties(schema_folder): # in array elements, the properties are under "items" @@ -277,6 +329,35 @@ def _get_folder_names(schema_properties): return folder_names +def print_folder_options(folder_options, model_path, indent_level): + """ + Print messages for a folder that has multiple content options. + :param folder_options: the options to be printed + :param model_path: the model path to be included in the output + :param indent_level: the level to indent by, before printing output + :return: the matching option, or None + """ + _print_indent("# " + exception_helper.get_message('WLSDPLY-10114', len(folder_options)), indent_level) + for index, one_of_option in enumerate(folder_options): + key = _get_kind_value(one_of_option) or index + print("") + _print_indent("# see " + model_path + "#" + str(key), indent_level) + + +def _get_kind_value(folder_option): + """ + Return the "kind" value of the specified folder option. + If the option doesn't have a kind value, return None. + :param folder_option: the folder option to be examined + :return: the value of the "kind" field, or None + """ + properties = schema_helper.get_properties(folder_option) + kind = dictionary_utils.get_dictionary_element(properties, "kind") + enum = dictionary_utils.get_dictionary_element(kind, "enum") + if enum and len(enum): + return enum[0] + + def _print_indent(msg, level=1, first_in_list_object=False): """ Print a message at the specified indent level. diff --git a/core/src/main/python/wlsdeploy/tool/modelhelp/model_help_printer.py b/core/src/main/python/wlsdeploy/tool/modelhelp/model_help_printer.py index 5b2926e76..63c8f7f06 100644 --- a/core/src/main/python/wlsdeploy/tool/modelhelp/model_help_printer.py +++ b/core/src/main/python/wlsdeploy/tool/modelhelp/model_help_printer.py @@ -18,7 +18,7 @@ from wlsdeploy.util.exit_code import ExitCode _class_name = "ModelHelpPrinter" -MODEL_PATH_PATTERN = re.compile(r'(^[a-zA-Z]+:?)?(/[a-zA-Z0-9^/]+)?$') +MODEL_PATH_PATTERN = re.compile(r'(^[a-zA-Z]+:?)?(/[a-zA-Z0-9#^/]+)?$') class ModelHelpPrinter(object): diff --git a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties index 9468362dd..580c6cd87 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties +++ b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties @@ -1247,6 +1247,8 @@ WLSDPLY-10110=Model section {0} has no folder {1} beneath it. Valid folders are: WLSDPLY-10111=Model folder {0} has no folder {1} beneath it. Valid folders are: {2} WLSDPLY-10112={0} encountered an error: {1} WLSDPLY-10113=Model section {0} is not valid for the specified target +WLSDPLY-10114=There are {0} options for this section: +WLSDPLY-10115=Model folder {0} has no option matching {1} ############################################################################### # create messages (12000 - 14999) # From e6fc99704c3593d3f03d691d70e0d1159d46920a Mon Sep 17 00:00:00 2001 From: Richard Killen Date: Wed, 25 Jan 2023 14:48:29 -0600 Subject: [PATCH 07/10] Validate schema folders with multiple content options --- .../tool/validate/crd_sections_validator.py | 78 +++++++++++++++---- .../deploy/messages/wlsdeploy_rb.properties | 3 + .../wlsdeploy/tool/extract/extract_test.py | 43 ++++++++-- core/src/test/resources/extract/model-3.yaml | 56 +++++++++++++ 4 files changed, 155 insertions(+), 25 deletions(-) create mode 100644 core/src/test/resources/extract/model-3.yaml diff --git a/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py b/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py index e24de4e19..0506df010 100644 --- a/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py +++ b/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py @@ -23,6 +23,8 @@ def __init__(self, model_context): self._model_context = model_context self._crd_helper = model_crd_helper.get_helper(model_context, ExceptionType.VALIDATE) self._section_name = self._crd_helper.get_model_section() + self._try_validate = False # suspend severe logging for "try" validations + self._invalid_count = 0 # the count of invalid log messages since last reset def validate_model(self, model_dict): """ @@ -49,9 +51,9 @@ def validate_model(self, model_dict): crd_folder = self._crd_helper.get_crd_folder(key) if not crd_folder: valid_keys = self._crd_helper.get_crd_folder_keys() - self._logger.severe("WLSDPLY-05026", key, len(valid_keys), model_path, - '%s' % ', '.join(valid_keys), - class_name=self._class_name, method_name=_method_name) + self._log_invalid("WLSDPLY-05026", key, len(valid_keys), model_path, + '%s' % ', '.join(valid_keys), + class_name=self._class_name, method_name=_method_name) continue model_content = crd_section[key] @@ -74,10 +76,45 @@ def validate_folder(self, model_folder, schema_folder, schema_path, model_path): self._log_debug(str_helper.to_string(model_path)) if not isinstance(model_folder, dict): - self._logger.severe("WLSDPLY-05038", model_path, class_name=self._class_name, method_name=_method_name) + self._log_invalid("WLSDPLY-05038", model_path, class_name=self._class_name, method_name=_method_name) return - schema_properties = schema_helper.get_properties(schema_folder) + folder_options = schema_helper.get_one_of_options(schema_folder) + if folder_options: + # if folder has multiple content options, try each option until validate is successful + valid_option_found = False + self._try_validate = True + for index, folder_option in enumerate(folder_options): + self._logger.fine("WLSDPLY-05041", index, model_path, + class_name=self._class_name, method_name=_method_name) + self._invalid_count = 0 + schema_properties = schema_helper.get_properties(folder_option) + self.validate_folder_properties(model_folder, schema_properties, schema_path, model_path) + if not self._invalid_count: + self._logger.fine("WLSDPLY-05042", index, model_path, + class_name=self._class_name, method_name=_method_name) + valid_option_found = True + break + self._try_validate = False + if not valid_option_found: + self._log_invalid("WLSDPLY-05043", model_path, len(folder_options), + class_name=self._class_name, method_name=_method_name) + + else: + # if folder has one set of properties, validate against those + schema_properties = schema_helper.get_properties(schema_folder) + self.validate_folder_properties(model_folder, schema_properties, schema_path, model_path) + + def validate_folder_properties(self, model_folder, schema_properties, schema_path, model_path): + """ + Validate the specified model folder against the specified schema properties. + These properties may be directly from the schema folder, or an option in a "one of" list. + :param model_folder: the model folder to validate + :param schema_properties: the schema properties to validate against + :param schema_path: the path of schema elements (no array indices), used for supported check + :param model_path: the path of model elements (including array indices), used for logging + """ + _method_name = 'validate_folder_properties' for key in model_folder: properties = dictionary_utils.get_element(schema_properties, key) @@ -120,9 +157,9 @@ def validate_folder(self, model_folder, schema_folder, schema_path, model_path): self._validate_simple_type(model_value, property_type, key, model_path) else: - self._logger.severe("WLSDPLY-05026", key, len(schema_properties), model_path, - '%s' % ', '.join(schema_properties), class_name=self._class_name, - method_name=_method_name) + self._log_invalid("WLSDPLY-05026", key, len(schema_properties), model_path, + '%s' % ', '.join(schema_properties), class_name=self._class_name, + method_name=_method_name) def _validate_object_array(self, model_value, property_map, schema_path, model_path): """ @@ -135,7 +172,7 @@ def _validate_object_array(self, model_value, property_map, schema_path, model_p _method_name = '_validate_object_array' if not isinstance(model_value, list): - self._logger.severe("WLSDPLY-05040", model_path, class_name=self._class_name, method_name=_method_name) + self._log_invalid("WLSDPLY-05040", model_path, class_name=self._class_name, method_name=_method_name) return index = 0 @@ -147,22 +184,22 @@ def _validate_object_array(self, model_value, property_map, schema_path, model_p def _validate_simple_map(self, model_value, property_name, model_path): _method_name = '_validate_simple_map' if not isinstance(model_value, dict): - self._logger.severe("WLSDPLY-05032", property_name, model_path, str_helper.to_string(type(model_value)), - class_name=self._class_name, method_name=_method_name) + self._log_invalid("WLSDPLY-05032", property_name, model_path, str_helper.to_string(type(model_value)), + class_name=self._class_name, method_name=_method_name) def _validate_simple_array(self, model_value, property_name, model_path): _method_name = '_validate_simple_array' if isinstance(model_value, dict): - self._logger.severe("WLSDPLY-05017", property_name, model_path, "list", - str_helper.to_string(type(model_value)), - class_name=self._class_name, method_name=_method_name) + self._log_invalid("WLSDPLY-05017", property_name, model_path, "list", + str_helper.to_string(type(model_value)), + class_name=self._class_name, method_name=_method_name) def _validate_simple_type(self, model_value, property_type, property_name, model_path): _method_name = '_validate_simple_type' if isinstance(model_value, list) or isinstance(model_value, dict): - self._logger.severe("WLSDPLY-05017", property_name, model_path, property_type, - str_helper.to_string(type(model_value)), - class_name=self._class_name, method_name=_method_name) + self._log_invalid("WLSDPLY-05017", property_name, model_path, property_type, + str_helper.to_string(type(model_value)), + class_name=self._class_name, method_name=_method_name) def _check_folder_path(self, schema_path, model_path): """ @@ -179,3 +216,10 @@ def _check_folder_path(self, schema_path, model_path): def _log_debug(self, message): self._logger.finest(message) + + def _log_invalid(self, message, *args, **kwargs): + log_method = self._logger.severe + if self._try_validate: + log_method = self._logger.fine + log_method(message, *args, **kwargs) + self._invalid_count += 1 diff --git a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties index 580c6cd87..bf651f869 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties +++ b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties @@ -511,6 +511,9 @@ WLSDPLY-05037=Custom folder {0} will not be validated WLSDPLY-05038=Expected a section with subfolders and attributes in model location {0} WLSDPLY-05039=Expected a section with named subfolders in model location {0} WLSDPLY-05040=Expected a list of objects in model location {0} +WLSDPLY-05041=Validating folder option {0} for model location {1} +WLSDPLY-05042=Folder option {0} is valid for model location {1} +WLSDPLY-05043=Model location {0} does not match any of the {1} folder options # wlsdeploy/tool/validate/crd_sections_validator.py WLSDPLY-05090=Model folder {0} is not supported, will be skipped diff --git a/core/src/test/python/wlsdeploy/tool/extract/extract_test.py b/core/src/test/python/wlsdeploy/tool/extract/extract_test.py index 86afd98ed..549c2968e 100644 --- a/core/src/test/python/wlsdeploy/tool/extract/extract_test.py +++ b/core/src/test/python/wlsdeploy/tool/extract/extract_test.py @@ -3,7 +3,6 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. """ import os -import shutil from base_test import BaseTestCase from wlsdeploy.aliases.aliases import Aliases @@ -15,6 +14,7 @@ from wlsdeploy.util.model import Model from wlsdeploy.util.model_context import ModelContext from wlsdeploy.util.model_translator import FileToPython +from wlsdeploy.yaml.yaml_translator import YamlToPython class ExtractTest(BaseTestCase): @@ -51,7 +51,8 @@ def testDefaultModel(self): config['set_cluster_replicas'] = True PythonToJson(config).write_to_json_file(target_path) - resource = self._extract_domain_resource('1') + documents = self._extract_resource_documents('1', 'wko', 'wko-domain.yaml') + resource = documents[0] # clusters from topology should be in the domain resource file cluster_list = self._traverse(resource, 'spec', 'clusters') @@ -72,7 +73,8 @@ def testKubernetesModel(self): Test that fields from the kubernetes section of the model are transferred to the resulting domain resource file """ - resource = self._extract_domain_resource('2') + documents = self._extract_resource_documents('2', 'wko', 'wko-domain.yaml') + resource = documents[0] # clusters from kubernetes section should be in the domain resource file cluster_list = self._traverse(resource, 'spec', 'clusters') @@ -86,7 +88,32 @@ def testKubernetesModel(self): self._match_values("Secret 0", secret_list[0], 'secret-1') self._match_values("Secret 1", secret_list[1], 'secret-2') - def _extract_domain_resource(self, suffix): + def testVerrazzanoModel(self): + """ + Test that fields from the verrazzano section of the model + are transferred to the resulting domain resource file + """ + documents = self._extract_resource_documents('3', 'vz', 'vz-application.yaml') + application_resource = documents[0] + + # a model application component was added to 2 from the template + cluster_list = self._traverse(application_resource, 'spec', 'components') + self._match_values("Component count", len(cluster_list), 3) + self._match_values("Component 2 name", cluster_list[2]['componentName'], 'base-domain-from-model') + + configmap_resource = documents[2] + + # one entry was added to config map + data_map = self._traverse(configmap_resource, 'spec', 'workload', 'data') + self._match_values("Configmap data count", len(data_map), 2) + + # the DB entry was update with a new URL + db_key = 'wdt_jdbc.yaml' + db_host_text = '@modelhost:1521' + self._match_values("Configmap data has key " + db_key, db_key in data_map, True) + self._match_values("Configmap JDBC URL contains " + db_host_text, db_host_text in data_map[db_key], True) + + def _extract_resource_documents(self, suffix, target_name, output_file_name): model_file = os.path.join(self.MODELS_DIR, 'model-' + suffix + '.yaml') translator = FileToPython(model_file, use_ordering=True) model_dict = translator.parse() @@ -96,7 +123,7 @@ def _extract_domain_resource(self, suffix): '-domain_home': '/u01/domain', '-oracle_home': '/oracle', '-output_dir': self.EXTRACT_OUTPUT_DIR, - '-target': 'wko' + '-target': target_name } model_context = ModelContext('ExtractTest', args_map) aliases = Aliases(model_context, WlstModes.OFFLINE, self.wls_version) @@ -104,6 +131,6 @@ def _extract_domain_resource(self, suffix): extractor = DomainResourceExtractor(model, model_context, aliases, self.__logger) extractor.extract() - resource_file = os.path.join(self.EXTRACT_OUTPUT_DIR, 'wko-domain.yaml') - translator = FileToPython(resource_file, use_ordering=True) - return translator.parse() + resource_file = os.path.join(self.EXTRACT_OUTPUT_DIR, output_file_name) + reader = YamlToPython(resource_file, True) + return reader.parse_documents() diff --git a/core/src/test/resources/extract/model-3.yaml b/core/src/test/resources/extract/model-3.yaml new file mode 100644 index 000000000..c6e395bb9 --- /dev/null +++ b/core/src/test/resources/extract/model-3.yaml @@ -0,0 +1,56 @@ +# Copyright (c) 2023, Oracle and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +# Test model for extractDomainResource. +# This will test that fields from the verrazzano section of the model +# are transferred to the resulting domain resource file + +resources: + # template will create a configmap entry for this JDBC resource + JDBCSystemResource: + model-ds: + JdbcResource: + JDBCDriverParams: + URL: 'jdbc:oracle:thin:@dbhost:1521/pdborcl' + +verrazzano: + application: + spec: + components: + - componentName: base-domain-domain # should merge with template component + traits: + - trait: # should merge with template trait + apiVersion: oam.verrazzano.io/v1alpha1 + kind: MetricsTrait + spec: + scraper: verrazzano-system/my-model-scraper + - trait: # should add to template traits + apiVersion: oam.verrazzano.io/v1alpha1 + kind: LoggingTrait + spec: + imagePullPolicy: NEVER + - componentName: base-domain-from-model # should add this component + + weblogic: + spec: + workload: + spec: + template: + spec: + # simple override + domainHome: modelHome + + configmap: + spec: + workload: + data: + # merge with template entry to change DB URL + wdt_jdbc.yaml: | + resources: + JDBCSystemResource: + myDs: + JdbcResource: + JDBCDriverParams: + # This is the URL of the database used by the WebLogic Server application + URL: "jdbc:oracle:thin:@modelhost:1521/pdborcl" + test.yaml: fromModel # should be added From b67fae786953ec89d29b5704c6f146b131e14844 Mon Sep 17 00:00:00 2001 From: Richard Killen Date: Wed, 25 Jan 2023 17:54:15 -0600 Subject: [PATCH 08/10] Implement merging of schema folders with multiple content options --- .../tool/util/targets/crd_file_updater.py | 19 ++++++-- .../tool/util/targets/model_crd_helper.py | 1 + .../tool/validate/crd_sections_validator.py | 48 ++++++++++++------- .../wlsdeploy/tool/extract/extract_test.py | 10 ++-- .../util/targets/crd_file_updater_test.py | 10 ++++ core/src/test/resources/crd/vz-model.yaml | 11 +++++ 6 files changed, 77 insertions(+), 22 deletions(-) diff --git a/core/src/main/python/wlsdeploy/tool/util/targets/crd_file_updater.py b/core/src/main/python/wlsdeploy/tool/util/targets/crd_file_updater.py index 50e84fbb8..f8db838fa 100644 --- a/core/src/main/python/wlsdeploy/tool/util/targets/crd_file_updater.py +++ b/core/src/main/python/wlsdeploy/tool/util/targets/crd_file_updater.py @@ -9,17 +9,18 @@ from oracle.weblogic.deploy.yaml import YamlException from wlsdeploy.aliases import alias_utils -from wlsdeploy.aliases.model_constants import KUBERNETES from wlsdeploy.aliases.model_constants import MODEL_LIST_DELIMITER from wlsdeploy.exception import exception_helper from wlsdeploy.logging.platform_logger import PlatformLogger from wlsdeploy.tool.util.targets import schema_helper +from wlsdeploy.tool.validate.crd_sections_validator import CrdSectionsValidator from wlsdeploy.util import dictionary_utils import wlsdeploy.util.unicode_helper as str_helper +from wlsdeploy.util.model_context import ModelContext from wlsdeploy.yaml.yaml_translator import PythonToYaml from wlsdeploy.yaml.yaml_translator import YamlToPython -__class_name = 'output_file_helper' +__class_name = 'crd_file_updater' __logger = PlatformLogger('wlsdeploy.tool.util') KIND = 'kind' @@ -233,7 +234,19 @@ def _update_dictionary(output_dictionary, model_dictionary, schema_folder, schem output_dictionary[key] = value return - properties = schema_helper.get_properties(schema_folder) + # if this folder has multiple content options, choose the matching one + folder_options = schema_helper.get_one_of_options(schema_folder) + if folder_options: + model_context = ModelContext(__class_name, {}) + validator = CrdSectionsValidator(model_context) + folder_option = validator.find_folder_option(model_dictionary, folder_options, schema_path, schema_path) + if not folder_option: + __logger.warning("WLSDPLY-05043", schema_path, len(folder_options), + class_name=__class_name, method_name=_method_name) + return + properties = schema_helper.get_properties(folder_option) + else: + properties = schema_helper.get_properties(schema_folder) for key, value in model_dictionary.items(): property_folder = properties[key] diff --git a/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py b/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py index 15b13e056..1243d8523 100644 --- a/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py +++ b/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py @@ -104,6 +104,7 @@ def get_product_helper(product_key, product_version, exception_type=ExceptionTyp application_schema = schema_helper.get_schema(VZ_1_APPLICATION_SCHEMA_NAME, exception_type) application_folder = ModelCrdFolder("application", application_schema, False) application_folder.add_object_list_key('spec/components', 'componentName') + application_folder.add_object_list_key('spec/components/traits', 'trait/kind') helper.add_crd_folder(application_folder) weblogic_schema_name = VZ_1_WEBLOGIC_SCHEMA_NAME diff --git a/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py b/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py index 0506df010..59a99e654 100644 --- a/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py +++ b/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py @@ -82,24 +82,10 @@ def validate_folder(self, model_folder, schema_folder, schema_path, model_path): folder_options = schema_helper.get_one_of_options(schema_folder) if folder_options: # if folder has multiple content options, try each option until validate is successful - valid_option_found = False - self._try_validate = True - for index, folder_option in enumerate(folder_options): - self._logger.fine("WLSDPLY-05041", index, model_path, - class_name=self._class_name, method_name=_method_name) - self._invalid_count = 0 - schema_properties = schema_helper.get_properties(folder_option) - self.validate_folder_properties(model_folder, schema_properties, schema_path, model_path) - if not self._invalid_count: - self._logger.fine("WLSDPLY-05042", index, model_path, - class_name=self._class_name, method_name=_method_name) - valid_option_found = True - break - self._try_validate = False - if not valid_option_found: + folder_option = self.find_folder_option(model_folder, folder_options, schema_path, model_path) + if not folder_option: self._log_invalid("WLSDPLY-05043", model_path, len(folder_options), class_name=self._class_name, method_name=_method_name) - else: # if folder has one set of properties, validate against those schema_properties = schema_helper.get_properties(schema_folder) @@ -161,6 +147,36 @@ def validate_folder_properties(self, model_folder, schema_properties, schema_pat '%s' % ', '.join(schema_properties), class_name=self._class_name, method_name=_method_name) + def find_folder_option(self, model_folder, folder_options, schema_path, model_path): + """ + Find a folder option that corresponds to the specified model folder contents. + Try validating with each folder option until successful. + :param model_folder: the model folder to match + :param folder_options: a list of folder options from the schema + :param schema_path: the path of schema elements (no array indices), used for supported check + :param model_path: the path of model elements (including array indices), used for logging + :return: the matching folder option, or None + """ + _method_name = 'find_folder_option' + + # try validating against each option until successful + result = None + self._try_validate = True + for index, folder_option in enumerate(folder_options): + self._logger.fine("WLSDPLY-05041", index, model_path, + class_name=self._class_name, method_name=_method_name) + self._invalid_count = 0 + schema_properties = schema_helper.get_properties(folder_option) + self.validate_folder_properties(model_folder, schema_properties, schema_path, model_path) + if not self._invalid_count: + self._logger.fine("WLSDPLY-05042", index, model_path, + class_name=self._class_name, method_name=_method_name) + result = folder_option + break + + self._try_validate = False + return result + def _validate_object_array(self, model_value, property_map, schema_path, model_path): """ Validate the contents of this object array. diff --git a/core/src/test/python/wlsdeploy/tool/extract/extract_test.py b/core/src/test/python/wlsdeploy/tool/extract/extract_test.py index 549c2968e..942a38029 100644 --- a/core/src/test/python/wlsdeploy/tool/extract/extract_test.py +++ b/core/src/test/python/wlsdeploy/tool/extract/extract_test.py @@ -97,9 +97,13 @@ def testVerrazzanoModel(self): application_resource = documents[0] # a model application component was added to 2 from the template - cluster_list = self._traverse(application_resource, 'spec', 'components') - self._match_values("Component count", len(cluster_list), 3) - self._match_values("Component 2 name", cluster_list[2]['componentName'], 'base-domain-from-model') + component_list = self._traverse(application_resource, 'spec', 'components') + self._match_values("Application component count", len(component_list), 3) + self._match_values("Application component 2 name", component_list[2]['componentName'], + 'base-domain-from-model') + + trait_list = self._traverse(component_list[0], 'traits') + self._match_values("Application trait count", len(trait_list), 3) configmap_resource = documents[2] diff --git a/core/src/test/python/wlsdeploy/tool/util/targets/crd_file_updater_test.py b/core/src/test/python/wlsdeploy/tool/util/targets/crd_file_updater_test.py index 58aba1078..7edddefa8 100644 --- a/core/src/test/python/wlsdeploy/tool/util/targets/crd_file_updater_test.py +++ b/core/src/test/python/wlsdeploy/tool/util/targets/crd_file_updater_test.py @@ -80,12 +80,21 @@ def test_verrazzano_crd_update(self): self._match_values("Document count", len(documents), 3) # application document + application_resource = documents[0] # two existing components, one added, one merged component_list = self._traverse(application_resource, 'spec', 'components') self._match_values("Application component count", len(component_list), 3) + trait_list = self._traverse(component_list[0], 'traits') + self._match_values("Application trait count", len(trait_list), 3) + + scraper_text = '/my-model-scraper' + scraper = self._traverse(trait_list[0], 'trait', 'spec', 'scraper') + self._match_values("Configmap JDBC URL contains " + scraper_text, scraper_text in scraper, True) + # weblogic document + weblogic_resource = documents[1] domain_resource = self._traverse(weblogic_resource, 'spec', 'workload', 'spec', 'template') @@ -104,6 +113,7 @@ def test_verrazzano_crd_update(self): self._match_values("Third cluster replicas", cluster_resource[2]['spec']['replicas'], 1103) # configmap document + configmap_resource = documents[2] data_map = self._traverse(configmap_resource, 'spec', 'workload', 'data') self._match_values("Data count", len(data_map), 2) diff --git a/core/src/test/resources/crd/vz-model.yaml b/core/src/test/resources/crd/vz-model.yaml index 57645e745..7081fcd80 100644 --- a/core/src/test/resources/crd/vz-model.yaml +++ b/core/src/test/resources/crd/vz-model.yaml @@ -6,6 +6,17 @@ verrazzano: spec: components: - componentName: demodomain-domain # should merge with existing component + traits: + - trait: # should merge with template trait + apiVersion: oam.verrazzano.io/v1alpha1 + kind: MetricsTrait + spec: + scraper: verrazzano-system/my-model-scraper + - trait: # should add to template traits + apiVersion: oam.verrazzano.io/v1alpha1 + kind: LoggingTrait + spec: + imagePullPolicy: NEVER - componentName: demodomain-from-model # should add this component weblogic: From ad6a168d334a90ed35aaa87ebb8f91378d31dcfd Mon Sep 17 00:00:00 2001 From: Richard Killen Date: Thu, 26 Jan 2023 09:35:52 -0600 Subject: [PATCH 09/10] Revised comments for review --- .../python/wlsdeploy/tool/util/targets/model_crd_helper.py | 2 +- .../python/wlsdeploy/tool/validate/crd_sections_validator.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py b/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py index 1243d8523..76c6a3cc0 100644 --- a/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py +++ b/core/src/main/python/wlsdeploy/tool/util/targets/model_crd_helper.py @@ -61,7 +61,7 @@ def __init__(self, exception_type): self._crd_folder_map = {} self._model_section = None - # get CRD information for model folders directly under kubernetes, + # get CRD information for model folders directly under the section name def get_crd_folders(self): return self._crd_folders diff --git a/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py b/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py index 59a99e654..a8fea44a9 100644 --- a/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py +++ b/core/src/main/python/wlsdeploy/tool/validate/crd_sections_validator.py @@ -81,7 +81,7 @@ def validate_folder(self, model_folder, schema_folder, schema_path, model_path): folder_options = schema_helper.get_one_of_options(schema_folder) if folder_options: - # if folder has multiple content options, try each option until validate is successful + # if schema folder has multiple content options, find one matching the model folder content folder_option = self.find_folder_option(model_folder, folder_options, schema_path, model_path) if not folder_option: self._log_invalid("WLSDPLY-05043", model_path, len(folder_options), @@ -149,7 +149,7 @@ def validate_folder_properties(self, model_folder, schema_properties, schema_pat def find_folder_option(self, model_folder, folder_options, schema_path, model_path): """ - Find a folder option that corresponds to the specified model folder contents. + Find a schema folder option that corresponds to the specified model folder contents. Try validating with each folder option until successful. :param model_folder: the model folder to match :param folder_options: a list of folder options from the schema From 05451c0741c87c84250ea5109a4d953c482f3d27 Mon Sep 17 00:00:00 2001 From: Richard Killen Date: Thu, 26 Jan 2023 09:48:54 -0600 Subject: [PATCH 10/10] Use unicode_helper for string conversion --- .../tool/modelhelp/model_crd_section_printer.py | 2 +- .../wlsdeploy/tool/util/targets/crd_schema_test.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/main/python/wlsdeploy/tool/modelhelp/model_crd_section_printer.py b/core/src/main/python/wlsdeploy/tool/modelhelp/model_crd_section_printer.py index 6b725c017..1d7691645 100644 --- a/core/src/main/python/wlsdeploy/tool/modelhelp/model_crd_section_printer.py +++ b/core/src/main/python/wlsdeploy/tool/modelhelp/model_crd_section_printer.py @@ -341,7 +341,7 @@ def print_folder_options(folder_options, model_path, indent_level): for index, one_of_option in enumerate(folder_options): key = _get_kind_value(one_of_option) or index print("") - _print_indent("# see " + model_path + "#" + str(key), indent_level) + _print_indent("# see " + model_path + "#" + str_helper.to_string(key), indent_level) def _get_kind_value(folder_option): diff --git a/core/src/test/python/wlsdeploy/tool/util/targets/crd_schema_test.py b/core/src/test/python/wlsdeploy/tool/util/targets/crd_schema_test.py index 26becee8e..d18762598 100644 --- a/core/src/test/python/wlsdeploy/tool/util/targets/crd_schema_test.py +++ b/core/src/test/python/wlsdeploy/tool/util/targets/crd_schema_test.py @@ -7,9 +7,9 @@ from oracle.weblogic.deploy.util import PyOrderedDict -from wlsdeploy.aliases.model_constants import KUBERNETES from wlsdeploy.tool.util.targets import model_crd_helper from wlsdeploy.tool.util.targets import schema_helper +import wlsdeploy.util.unicode_helper as str_helper class CrdSchemaTest(unittest.TestCase): @@ -46,7 +46,7 @@ def _testSchemas(self, product_key, product_version): self.out_file.close() except Exception, e: - self.fail(str(e)) + self.fail(str_helper.to_string(e)) def _write_folder(self, folder, in_array, path, indent): # for an object in an array, the first field is prefixed with a hyphen @@ -96,12 +96,12 @@ def _write_folder(self, folder, in_array, path, indent): enum_values = schema_helper.get_enum_values(property_map) if enum_values: value = "'" + enum_values[0] + "' # " + ', '.join(enum_values) - self._write_line(this_indent + str(property_name) + ": " + value) + self._write_line(this_indent + str_helper.to_string(property_name) + ": " + value) this_indent = plain_indent else: - self.fail('Unknown property type ' + str(property_type) + ' for ' + str(path) + ' ' - + str(property_name)) + self.fail('Unknown property type ' + str_helper.to_string(property_type) + + ' for ' + str_helper.to_string(path) + ' ' + str_helper.to_string(property_name)) # process sub-folders after attributes for clarity for property_name in sub_folders: @@ -124,7 +124,7 @@ def _write_folder(self, folder, in_array, path, indent): for index, subfolder_option in enumerate(subfolder_options): if one_of_options: self._write_line('') - self._write_line(child_indent + "# option " + str(index + 1)) + self._write_line(child_indent + "# option " + str_helper.to_string(index + 1)) # comment out options after the first subfolder_indent = child_indent