def generate_k8s_script(model_context, token_dictionary, model_dictionary): """ Generate a shell script for creating k8s secrets. :param model_context: used to determine output directory :param token_dictionary: contains every token :param model_dictionary: used to determine domain UID """ target_config = model_context.get_target_configuration() if not target_config.requires_secrets_script(): return # determine the domain name and UID topology = dictionary_utils.get_dictionary_element(model_dictionary, TOPOLOGY) domain_name = dictionary_utils.get_element(topology, NAME) if domain_name is None: domain_name = DEFAULT_WLS_DOMAIN_NAME domain_uid = k8s_helper.get_domain_uid(domain_name) nl = '\n' file_location = model_context.get_kubernetes_output_dir() k8s_file = os.path.join(file_location, "create_k8s_secrets.sh") k8s_script = open(k8s_file, 'w') k8s_script.write('#!/bin/bash' + nl) k8s_script.write(nl) k8s_script.write('set -eu' + nl) k8s_script.write(nl) message = exception_helper.get_message("WLSDPLY-01665", ADMIN_USER_TAG, ADMIN_PASSWORD_TAG) k8s_script.write("# " + message + nl) k8s_script.write('NAMESPACE=default' + nl) k8s_script.write('DOMAIN_UID=' + domain_uid + nl) k8s_script.write(nl) k8s_script.write('function create_k8s_secret {' + nl) k8s_script.write( ' kubectl -n $NAMESPACE delete secret ${DOMAIN_UID}-$1 --ignore-not-found' + nl) k8s_script.write( ' kubectl -n $NAMESPACE create secret generic ${DOMAIN_UID}-$1 --from-literal=password=$2' + nl) k8s_script.write( ' kubectl -n $NAMESPACE label secret ${DOMAIN_UID}-$1 weblogic.domainUID=${DOMAIN_UID}' + nl) k8s_script.write('}' + nl) k8s_script.write(nl) k8s_script.write('function create_paired_k8s_secret {' + nl) k8s_script.write( ' kubectl -n $NAMESPACE delete secret ${DOMAIN_UID}-$1 --ignore-not-found' + nl) k8s_script.write( ' kubectl -n $NAMESPACE create secret generic ${DOMAIN_UID}-$1' + ' --from-literal=username=$2 --from-literal=password=$3' + nl) k8s_script.write( ' kubectl -n $NAMESPACE label secret ${DOMAIN_UID}-$1 weblogic.domainUID=${DOMAIN_UID}' + nl) k8s_script.write('}' + nl) command_string = "create_paired_k8s_secret %s %s %s" \ % (WEBLOGIC_CREDENTIALS_SECRET_NAME, ADMIN_USER_TAG, ADMIN_PASSWORD_TAG) k8s_script.write(nl) message = exception_helper.get_message("WLSDPLY-01664", ADMIN_USER_TAG, ADMIN_PASSWORD_TAG, WEBLOGIC_CREDENTIALS_SECRET_NAME) k8s_script.write("# " + message + nl) k8s_script.write(command_string + nl) for property_name in token_dictionary: # AdminPassword, AdminUser are created separately, # and SecurityConfig.NodeManagerPasswordEncrypted is the short name which filters out if property_name in [ 'AdminPassword', 'AdminUserName', 'SecurityConfig.NodeManagerPasswordEncrypted' ]: continue user_name = find_user_name(property_name, model_dictionary) secret_name = _create_secret_name(property_name) if user_name is None: message = exception_helper.get_message("WLSDPLY-01663", PASSWORD_TAG, secret_name) command_string = "create_k8s_secret %s %s " \ % (secret_name, PASSWORD_TAG) else: message = exception_helper.get_message("WLSDPLY-01664", USER_TAG, PASSWORD_TAG, secret_name) command_string = "create_paired_k8s_secret %s %s %s " \ % (secret_name, user_name, PASSWORD_TAG) k8s_script.write(nl) k8s_script.write("# " + message + nl) k8s_script.write(command_string + nl) k8s_script.close() FileUtils.chmod(k8s_file, 0750)
def _build_template_hash(model, model_context, aliases): """ Create a dictionary of substitution values to apply to the templates. :param model: Model object used to derive values :param model_context: used to determine domain type :param aliases: used to derive folder names :return: the hash dictionary """ template_hash = dict() # domain name and prefix domain_name = dictionary_utils.get_element(model.get_model_topology(), NAME) if domain_name is None: domain_name = DEFAULT_WLS_DOMAIN_NAME template_hash[DOMAIN_NAME] = domain_name # should change spaces to hyphens? template_hash[DOMAIN_PREFIX] = domain_name.lower() # domain UID domain_uid = k8s_helper.get_domain_uid(domain_name) template_hash[DOMAIN_UID] = domain_uid # admin credential admin_secret = domain_uid + target_configuration_helper.WEBLOGIC_CREDENTIALS_SECRET_SUFFIX template_hash[WEBLOGIC_CREDENTIALS_SECRET] = admin_secret # configuration / model template_hash[DOMAIN_TYPE] = model_context.get_domain_type() # clusters clusters = [] cluster_list = dictionary_utils.get_dictionary_element( model.get_model_topology(), CLUSTER) for cluster_name in cluster_list: cluster_hash = dict() cluster_hash[CLUSTER_NAME] = cluster_name cluster_values = dictionary_utils.get_dictionary_element( cluster_list, cluster_name) server_count = k8s_helper.get_server_count(cluster_name, cluster_values, model.get_model()) cluster_hash[REPLICAS] = str(server_count) clusters.append(cluster_hash) template_hash[CLUSTERS] = clusters template_hash[HAS_CLUSTERS] = len(clusters) != 0 # databases databases = [] location = LocationContext().append_location(JDBC_SYSTEM_RESOURCE) name_token = aliases.get_name_token(location) location.append_location(JDBC_RESOURCE, JDBC_DRIVER_PARAMS) system_resources = dictionary_utils.get_dictionary_element( model.get_model_resources(), JDBC_SYSTEM_RESOURCE) for jdbc_name in system_resources: database_hash = dict() database_hash[DATASOURCE_NAME] = jdbc_name named = dictionary_utils.get_dictionary_element( system_resources, jdbc_name) resources = dictionary_utils.get_dictionary_element( named, JDBC_RESOURCE) driver_params = dictionary_utils.get_dictionary_element( resources, JDBC_DRIVER_PARAMS) url = dictionary_utils.get_element(driver_params, URL) if url is None: url = '' database_hash[DS_URL] = url # should change spaces to hyphens? database_hash[DATABASE_PREFIX] = jdbc_name.lower() # get the name that matches secret location.add_name_token(name_token, jdbc_name) secret_name = target_configuration_helper.get_secret_name_for_location( location, domain_uid, aliases) database_hash[DATABASE_CREDENTIALS] = secret_name databases.append(database_hash) template_hash[DATABASES] = databases template_hash[HAS_DATABASES] = len(databases) != 0 return template_hash
def generate_k8s_script(model_context, token_dictionary, model_dictionary, exception_type): """ Generate a shell script for creating k8s secrets. :param model_context: used to determine output directory :param token_dictionary: contains every token :param model_dictionary: used to determine domain UID :param exception_type: type of exception to throw """ # determine the domain name and UID topology = dictionary_utils.get_dictionary_element(model_dictionary, TOPOLOGY) domain_name = dictionary_utils.get_element(topology, NAME) if domain_name is None: domain_name = DEFAULT_WLS_DOMAIN_NAME domain_uid = k8s_helper.get_domain_uid(domain_name) comment = exception_helper.get_message("WLSDPLY-01665") script_hash = {'domainUid': domain_uid, 'topComment': comment} # build a map of secret names (jdbc-generic1) to keys (username, password) secret_map = {} for property_name in token_dictionary: halves = property_name.split(':', 1) value = token_dictionary[property_name] if len(halves) == 2: secret_name = halves[0] # admin credentials are inserted later, at the top of the list if secret_name == WEBLOGIC_CREDENTIALS_SECRET_NAME: continue secret_key = halves[1] if secret_name not in secret_map: secret_map[secret_name] = {} secret_keys = secret_map[secret_name] secret_keys[secret_key] = value # update the hash with secrets and paired secrets secrets = [] paired_secrets = [_build_secret_hash(WEBLOGIC_CREDENTIALS_SECRET_NAME, USER_TAG, PASSWORD_TAG)] secret_names = secret_map.keys() secret_names.sort() for secret_name in secret_names: secret_keys = secret_map[secret_name] user_name = dictionary_utils.get_element(secret_keys, SECRET_USERNAME_KEY) if user_name is None: secrets.append(_build_secret_hash(secret_name, None, PASSWORD_TAG)) else: paired_secrets.append(_build_secret_hash(secret_name, user_name, PASSWORD_TAG)) script_hash['secrets'] = secrets script_hash['pairedSecrets'] = paired_secrets script_hash['longMessage'] = exception_helper.get_message('WLSDPLY-01667', '${LONG_SECRETS_COUNT}') long_messages = [ {'text': exception_helper.get_message('WLSDPLY-01668')}, {'text': exception_helper.get_message('WLSDPLY-01669')}, {'text': exception_helper.get_message('WLSDPLY-01670')} ] script_hash['longMessageDetails'] = long_messages file_location = model_context.get_output_dir() k8s_file = File(file_location, K8S_SCRIPT_NAME) file_template_helper.create_file_from_resource(K8S_SCRIPT_RESOURCE_PATH, script_hash, k8s_file, exception_type) FileUtils.chmod(k8s_file.getPath(), 0750)
def _update_resource_dictionary(self, resource_dict): """ Revise the resource file structure with values from defaults, command line, and elsewhere in model :param resource_dict: the resource file dictionary """ _method_name = '_update_resource_dictionary' # add a metadata section if not present, since we'll at least add name if METADATA not in resource_dict: _add_to_top(resource_dict, METADATA, PyOrderedDict()) metadata_section = resource_dict[METADATA] # add kind if not present if KIND not in resource_dict: _add_to_top(resource_dict, KIND, DEFAULT_KIND) # add API version if not present if API_VERSION not in resource_dict: _add_to_top(resource_dict, API_VERSION, DEFAULT_API_VERSION) # if metadata name not present, use the domain name from the model, or default if K_NAME not in metadata_section: domain_name = dictionary_utils.get_element(self._model.get_model_topology(), NAME) if domain_name is None: domain_name = DEFAULT_WLS_DOMAIN_NAME domain_name = k8s_helper.get_domain_uid(domain_name) metadata_section[K_NAME] = domain_name domain_uid = metadata_section[K_NAME] # add a spec section if not present, since we'll at least add domain home if SPEC not in resource_dict: resource_dict[SPEC] = PyOrderedDict() spec_section = resource_dict[SPEC] # only set domain home if it is not present in spec section if DOMAIN_HOME not in spec_section: spec_section[DOMAIN_HOME] = self._model_context.get_domain_home() # only set image if it is not present in spec section if IMAGE not in spec_section: spec_section[IMAGE] = DEFAULT_IMAGE # imagePullSecrets is required unless imagePullPolicy is Never pull_secrets_required = True if IMAGE_PULL_POLICY in spec_section: policy = str(spec_section[IMAGE_PULL_POLICY]) pull_secrets_required = (policy != NEVER) # if imagePullSecrets required and not present, add a list with one FIX ME value if pull_secrets_required and (IMAGE_PULL_SECRETS not in spec_section): secrets_list = list() secrets_list.append({'name': DEFAULT_IMAGE_PULL_SECRETS}) spec_section[IMAGE_PULL_SECRETS] = secrets_list # if webLogicCredentialsSecret not present, add it using the FIX ME value if WEBLOGIC_CREDENTIALS_SECRET not in spec_section: spec_section[WEBLOGIC_CREDENTIALS_SECRET] = DEFAULT_WEBLOGIC_CREDENTIALS_SECRET # only update clusters if section is not present in spec section if CLUSTERS not in spec_section: topology = self._model.get_model_topology() model_clusters = dictionary_utils.get_dictionary_element(topology, CLUSTER) if len(model_clusters) > 0: cluster_list = list() spec_section[CLUSTERS] = cluster_list for cluster_name, cluster_values in model_clusters.items(): server_count = k8s_helper.get_server_count(cluster_name, cluster_values, self._model.get_model(), self._aliases) cluster_dict = PyOrderedDict() cluster_dict[CLUSTER_NAME] = cluster_name cluster_dict[REPLICAS] = server_count self._logger.info("WLSDPLY-10002", cluster_name, server_count, method_name=_method_name, class_name=self._class_name) cluster_list.append(cluster_dict) # create a configuration section in spec if needed if CONFIGURATION not in spec_section: spec_section[CONFIGURATION] = PyOrderedDict() configuration_section = spec_section[CONFIGURATION] # create a model section in configuration if needed if MODEL not in configuration_section: configuration_section[MODEL] = PyOrderedDict() model_section = configuration_section[MODEL] # set domainType if not specified if DOMAIN_TYPE not in model_section: model_section[DOMAIN_TYPE] = self._model_context.get_domain_type() if SECRETS in configuration_section: # if secrets specified, convert them to a hyphen list secrets = alias_utils.convert_to_model_type("list", configuration_section[SECRETS], MODEL_LIST_DELIMITER) secrets_list = list() secrets_list.extend(secrets) else: # pull the secrets from the model secrets_list = list() _add_secrets(self._model.get_model(), secrets_list, domain_uid) if secrets_list: configuration_section[SECRETS] = secrets_list return
def generate_k8s_script(model_context, token_dictionary, model_dictionary): """ Generate a shell script for creating k8s secrets. :param model_context: used to determine output directory :param token_dictionary: contains every token :param model_dictionary: used to determine domain UID """ # determine the domain name and UID topology = dictionary_utils.get_dictionary_element(model_dictionary, TOPOLOGY) domain_name = dictionary_utils.get_element(topology, NAME) if domain_name is None: domain_name = DEFAULT_WLS_DOMAIN_NAME domain_uid = k8s_helper.get_domain_uid(domain_name) nl = '\n' file_location = model_context.get_kubernetes_output_dir() k8s_file = os.path.join(file_location, "create_k8s_secrets.sh") k8s_script = open(k8s_file, 'w') k8s_script.write('#!/bin/bash' + nl) k8s_script.write(nl) k8s_script.write('set -eu' + nl) k8s_script.write(nl) message = exception_helper.get_message("WLSDPLY-01665", ADMIN_USER_TAG, ADMIN_PASSWORD_TAG) k8s_script.write("# " + message + nl) k8s_script.write('NAMESPACE=default' + nl) k8s_script.write('DOMAIN_UID=' + domain_uid + nl) k8s_script.write(nl) k8s_script.write('function create_k8s_secret {' + nl) k8s_script.write( ' kubectl -n $NAMESPACE delete secret ${DOMAIN_UID}-$1 --ignore-not-found' + nl) k8s_script.write( ' kubectl -n $NAMESPACE create secret generic ${DOMAIN_UID}-$1 --from-literal=password=$2' + nl) k8s_script.write( ' kubectl -n $NAMESPACE label secret ${DOMAIN_UID}-$1 weblogic.domainUID=${DOMAIN_UID}' + nl) k8s_script.write('}' + nl) k8s_script.write(nl) k8s_script.write('function create_paired_k8s_secret {' + nl) k8s_script.write( ' kubectl -n $NAMESPACE delete secret ${DOMAIN_UID}-$1 --ignore-not-found' + nl) k8s_script.write( ' kubectl -n $NAMESPACE create secret generic ${DOMAIN_UID}-$1' + ' --from-literal=username=$2 --from-literal=password=$3' + nl) k8s_script.write( ' kubectl -n $NAMESPACE label secret ${DOMAIN_UID}-$1 weblogic.domainUID=${DOMAIN_UID}' + nl) k8s_script.write('}' + nl) command_string = "create_paired_k8s_secret %s %s %s" \ % (WEBLOGIC_CREDENTIALS_SECRET_NAME, ADMIN_USER_TAG, ADMIN_PASSWORD_TAG) k8s_script.write(nl) message = exception_helper.get_message("WLSDPLY-01664", ADMIN_USER_TAG, ADMIN_PASSWORD_TAG, WEBLOGIC_CREDENTIALS_SECRET_NAME) k8s_script.write("# " + message + nl) k8s_script.write(command_string + nl) # build a map of secret names (jdbc-generic1) to keys (username, password) secret_map = {} for property_name in token_dictionary: halves = property_name.split(':', 1) value = token_dictionary[property_name] if len(halves) == 2: secret_name = halves[0] # admin credentials are hard-coded in the script, to be first in the list if secret_name == WEBLOGIC_CREDENTIALS_SECRET_NAME: continue secret_key = halves[1] if secret_name not in secret_map: secret_map[secret_name] = {} secret_keys = secret_map[secret_name] secret_keys[secret_key] = value secret_names = secret_map.keys() secret_names.sort() for secret_name in secret_names: secret_keys = secret_map[secret_name] user_name = dictionary_utils.get_element(secret_keys, SECRET_USERNAME_KEY) if user_name is None: message = exception_helper.get_message("WLSDPLY-01663", PASSWORD_TAG, secret_name) command_string = "create_k8s_secret %s %s " \ % (secret_name, PASSWORD_TAG) else: message = exception_helper.get_message("WLSDPLY-01664", USER_TAG, PASSWORD_TAG, secret_name) command_string = "create_paired_k8s_secret %s %s %s " \ % (secret_name, user_name, PASSWORD_TAG) k8s_script.write(nl) k8s_script.write("# " + message + nl) k8s_script.write(command_string + nl) k8s_script.close() FileUtils.chmod(k8s_file, 0750)
def _build_template_hash(model, model_context, aliases, credential_injector): """ Create a dictionary of substitution values to apply to the templates. :param model: Model object used to derive values :param model_context: used to determine domain type :param aliases: used to derive folder names :param credential_injector: used to identify secrets :return: the hash dictionary """ template_hash = dict() # actual domain name domain_name = dictionary_utils.get_element(model.get_model_topology(), NAME) if domain_name is None: domain_name = DEFAULT_WLS_DOMAIN_NAME # domain UID, name and prefix must follow DNS-1123 domain_uid = k8s_helper.get_domain_uid(domain_name) template_hash[DOMAIN_UID] = domain_uid template_hash[DOMAIN_NAME] = domain_uid template_hash[DOMAIN_PREFIX] = domain_uid # secrets that should not be included in secrets section declared_secrets = [] # admin credential admin_secret = domain_uid + target_configuration_helper.WEBLOGIC_CREDENTIALS_SECRET_SUFFIX declared_secrets.append(admin_secret) template_hash[WEBLOGIC_CREDENTIALS_SECRET] = admin_secret # configuration / model template_hash[DOMAIN_TYPE] = model_context.get_domain_type() # clusters clusters = [] cluster_list = dictionary_utils.get_dictionary_element( model.get_model_topology(), CLUSTER) for cluster_name in cluster_list: cluster_hash = dict() cluster_hash[CLUSTER_NAME] = cluster_name cluster_values = dictionary_utils.get_dictionary_element( cluster_list, cluster_name) server_count = k8s_helper.get_server_count(cluster_name, cluster_values, model.get_model(), aliases) cluster_hash[REPLICAS] = str(server_count) clusters.append(cluster_hash) template_hash[CLUSTERS] = clusters template_hash[HAS_CLUSTERS] = len(clusters) != 0 # databases databases = [] location = LocationContext().append_location(JDBC_SYSTEM_RESOURCE) name_token = aliases.get_name_token(location) location.append_location(JDBC_RESOURCE, JDBC_DRIVER_PARAMS) system_resources = dictionary_utils.get_dictionary_element( model.get_model_resources(), JDBC_SYSTEM_RESOURCE) for jdbc_name in system_resources: database_hash = dict() database_hash[DATASOURCE_NAME] = jdbc_name named = dictionary_utils.get_dictionary_element( system_resources, jdbc_name) resources = dictionary_utils.get_dictionary_element( named, JDBC_RESOURCE) driver_params = dictionary_utils.get_dictionary_element( resources, JDBC_DRIVER_PARAMS) url = dictionary_utils.get_element(driver_params, URL) if url is None: url = '' database_hash[DS_URL] = url # should change spaces to hyphens? database_hash[DATABASE_PREFIX] = jdbc_name.lower() # get the name that matches secret location.add_name_token(name_token, jdbc_name) secret_name = target_configuration_helper.get_secret_name_for_location( location, domain_uid, aliases) database_hash[DATABASE_CREDENTIALS] = secret_name databases.append(database_hash) template_hash[DATABASES] = databases template_hash[HAS_DATABASES] = len(databases) != 0 # additional secrets - exclude admin additional_secrets = [] # combine user/password properties to get a single list secrets = [] for property_name in credential_injector.get_variable_cache(): halves = property_name.split(':', 1) name = halves[0] if name not in secrets: secrets.append(name) for secret in secrets: secrets_hash = dict() qualified_name = domain_uid + "-" + secret if qualified_name not in declared_secrets: secrets_hash[ADDITIONAL_SECRET_NAME] = qualified_name additional_secrets.append(secrets_hash) template_hash[ADDITIONAL_SECRETS] = additional_secrets template_hash[HAS_ADDITIONAL_SECRETS] = len(additional_secrets) != 0 return template_hash
def _check_uid(self, domain_name, expected_uid): domain_uid = k8s_helper.get_domain_uid(domain_name) self.assertEquals(expected_uid, domain_uid, "Domain UID for " + domain_name + " should be " + expected_uid)