From: jh245g Date: Mon, 27 Aug 2018 14:01:58 +0000 (-0400) Subject: Bootstrap Cloudify X-Git-Tag: 3.0.0-ONAP~414^2 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=0191c4fcaed1586770653ce21e9c6d658e8159da;hp=0745a76632ea73d6660d5e470d7782b62860b477;p=oom.git Bootstrap Cloudify Change-Id: Ice60018516175b364ecd024158af14a7b51d7998 Issue-ID: OOM-1350 Signed-off-by: jh245g --- diff --git a/TOSCA/bootstrap.sh b/TOSCA/bootstrap.sh new file mode 100644 index 0000000000..3a415f0fcf --- /dev/null +++ b/TOSCA/bootstrap.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +# ============LICENSE_START========================================== +# =================================================================== +# Copyright (c) 2018 AT&T +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============LICENSE_END============================================ + +# this script will init a community version Cloudify manager +# 1.environment ubuntu 16.04 +# 2. git clone oom project into that ubuntu environment +# 3. provide the Openstack information in /TOSCA/cloudify-environment-setup/input/openstack.yaml +# 4. execute this script with sudo + + +apt-get update +apt-get install build-essential libssl-dev libffi-dev python-dev gcc -y +wget http://repository.cloudifysource.org/cloudify/18.3.23/community-release/cloudify-cli-community-18.3.23.deb +dpkg -i cloudify-cli-community-18.3.23.deb +cfy install cloudify-environment-setup/openstack.yaml -i cloudify-environment-setup/inputs/openstack.yaml --install-plugins --task-retries=30 --task-retry-interval=5 +cfy install cloudify-environment-setup/openstack.yaml -i cloudify-environment-setup/inputs/openstack.yaml --install-plugins --task-retries=30 --task-retry-interval=5 diff --git a/TOSCA/cloudify-environment-setup/imports/manager-configuration.yaml b/TOSCA/cloudify-environment-setup/imports/manager-configuration.yaml new file mode 100644 index 0000000000..5e0de730ec --- /dev/null +++ b/TOSCA/cloudify-environment-setup/imports/manager-configuration.yaml @@ -0,0 +1,77 @@ +# ============LICENSE_START========================================== +# =================================================================== +# Copyright (c) 2018 AT&T +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============LICENSE_END============================================ + +inputs: + + password: + description: > + Your manager password. If you do not provide one will be randomly generated, but it will not be displayed at the end. + + rpm: + description: > + If inputs.bootstrap is false, this is the CLI RPM to install and bootstrap with. + default: http://repository.cloudifysource.org/cloudify/18.3.23/community-release/cloudify-manager-install-community-18.3.23.rpm + + blueprints: + default: + - file: update-blueprint.yaml + name: aws-example-network + url: https://github.com/cloudify-examples/aws-example-network/archive/4.3.zip + - file: simple-blueprint.yaml + name: openstack-example-network + url: https://github.com/cloudify-examples/openstack-example-network/archive/4.3.zip + - file: simple-blueprint.yaml + name: azure-example-network + url: https://github.com/cloudify-examples/azure-example-network/archive/4.3.zip + - file: simple-blueprint.yaml + name: gcp-example-network + url: https://github.com/cloudify-examples/gcp-example-network/archive/4.3.zip + +node_types: + + cloudify.nodes.Manager.EnvironmentSetup: + derived_from: cloudify.nodes.Root + interfaces: + cloudify.interfaces.lifecycle: + create: + implementation: fabric.fabric_plugin.tasks.run_task + inputs: + tasks_file: + default: scripts/manager/tasks.py + task_name: + default: create + task_properties: + default: + private_ip: { get_input: private_ip } + public_ip: { get_input: public_ip } + rpm: { get_input: rpm } + secrets: { get_input: secrets } + blueprints: { get_input: blueprints } + password: { get_input: password } + fabric_env: + default: + host_string: { get_input: public_ip } + user: { get_input: cloudify_image_username } + key_filename: { get_input: cloudify_key_file } + +node_templates: + + ManagerSetup: + type: cloudify.nodes.Manager.EnvironmentSetup + relationships: + - type: cloudify.relationships.depends_on + target: cloudify_host diff --git a/TOSCA/cloudify-environment-setup/inputs/openstack.yaml b/TOSCA/cloudify-environment-setup/inputs/openstack.yaml new file mode 100644 index 0000000000..a5ed88af72 --- /dev/null +++ b/TOSCA/cloudify-environment-setup/inputs/openstack.yaml @@ -0,0 +1,29 @@ +# ============LICENSE_START========================================== +# =================================================================== +# Copyright (c) 2018 AT&T +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============LICENSE_END============================================ + +username: -cut- +keystone_password: -cut- +tenant_name: -cut- +auth_url: https://-cut-:5000/v2.0 +region: RegionOne +external_network_name: GATEWAY_NET +centos_core_image: -cut- +ubuntu_trusty_image: -cut- +small_image_flavor: 2 +large_image_flavor: 4 +password: admin +nameservers: [] \ No newline at end of file diff --git a/TOSCA/cloudify-environment-setup/openstack.yaml b/TOSCA/cloudify-environment-setup/openstack.yaml new file mode 100644 index 0000000000..d794a9e9a1 --- /dev/null +++ b/TOSCA/cloudify-environment-setup/openstack.yaml @@ -0,0 +1,399 @@ +# ============LICENSE_START========================================== +# =================================================================== +# Copyright (c) 2018 AT&T +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============LICENSE_END============================================ + +tosca_definitions_version: cloudify_dsl_1_3 + +imports: + - http://www.getcloudify.org/spec/cloudify/4.3.1/types.yaml + - http://www.getcloudify.org/spec/openstack-plugin/2.7.4/plugin.yaml + - http://www.getcloudify.org/spec/utilities-plugin/1.5.2/plugin.yaml + - http://www.getcloudify.org/spec/fabric-plugin/1.5.1/plugin.yaml + - imports/manager-configuration.yaml + +inputs: + + helm_version: + default: v2.9.1 + + username: + description: OS_USERNAME as specified in Openstack RC file. + + keystone_password: + description: Openstack user password. + + tenant_name: + description: OS_TENANT_NAME as specified in Openstack RC file. + + auth_url: + description: OS_AUTH_URL as specified in Openstack RC file. + + region: + description: OS_REGION_NAME as specified in Openstack RC file. + + external_network_name: + description: Openstack tenant external network name. + + local_ssh_directory: + default: '~/.ssh/' + + manager_key_name: + default: cfy-manager-key-os + + agent_key_name: + default: cfy-agent-key-os + + cloudify_key_file: + default: { concat: [ { get_input: local_ssh_directory }, { get_input: manager_key_name } ] } + + nameservers: + default: [8.8.4.4, 8.8.8.8] + + public_network_subnet_cidr: + default: 192.168.120.0/24 + + public_network_subnet_allocation_pools: + default: + - start: 192.168.120.2 + end: 192.168.120.254 + + private_network_subnet_cidr: + default: 192.168.121.0/24 + + private_network_subnet_allocation_pools: + default: + - start: 192.168.121.2 + end: 192.168.121.254 + + large_image_flavor: + type: string + + small_image_flavor: + type: string + + cloudify_image_username: + default: centos + + centos_core_image: + type: string + + ubuntu_trusty_image: + type: string + + private_ip: + description: > + Resolving the IP for manager setup. + default: { get_attribute: [ cloudify_host, ip ] } + + public_ip: + description: > + Resolving the IP for manager setup. + default: { get_attribute: [ public_network_subnet_port_fip, floating_ip_address ] } + + secrets: + description: > + key, value pairs of secrets used in AWS blueprint examples. + default: + - key: keystone_username + value: { get_input: username } + - key: keystone_password + value: { get_input: keystone_password } + - key: keystone_tenant_name + value: { get_input: tenant_name } + - key: keystone_url + value: { get_input: auth_url } + - key: region + value: { get_input: region } + - key: keystone_region + value: { get_input: region } + - key: external_network_name + value: { get_property: [ external_network, resource_id ] } + - key: router_name + value: { get_attribute: [ public_network_router, external_name ] } + - key: public_network_name + value: { get_attribute: [ public_network, external_name ] } + - key: private_network_name + value: { get_attribute: [ private_network, external_name ] } + - key: public_subnet_name + value: { get_attribute: [ public_network_subnet, external_name ] } + - key: private_subnet_name + value: { get_attribute: [ private_network_subnet, external_name ] } + - key: ubuntu_trusty_image + value: { get_input: ubuntu_trusty_image } + - key: centos_core_image + value: { get_input: centos_core_image } + - key: small_image_flavor + value: { get_input: small_image_flavor } + - key: large_image_flavor + value: { get_input: large_image_flavor } + - key: agent_key_public + value: { get_attribute: [ agent_key, public_key_export ] } + - key: agent_key_private + value: { get_attribute: [ agent_key, private_key_export ] } + +dsl_definitions: + + client_config: &client_config + username: { get_input: username } + password: { get_input: keystone_password } + tenant_name: { get_input: tenant_name } + auth_url: { get_input: auth_url } + region: { get_input: region } + +node_templates: + + manager_key: + type: cloudify.keys.nodes.RSAKey + properties: + resource_config: + public_key_path: { concat: [ { get_input: local_ssh_directory }, { get_input: manager_key_name }, '.pub' ] } + private_key_path: { concat: [ { get_input: local_ssh_directory }, { get_input: manager_key_name } ] } + openssh_format: true + use_secret_store: false + key_name: { get_input: manager_key_name } + interfaces: + cloudify.interfaces.lifecycle: + create: + implementation: keys.cloudify_ssh_key.operations.create + inputs: + store_private_key_material: true + + agent_key: + type: cloudify.keys.nodes.RSAKey + properties: + resource_config: + public_key_path: { concat: [ { get_input: local_ssh_directory }, { get_input: agent_key_name }, '.pub' ] } + private_key_path: { concat: [ { get_input: local_ssh_directory }, { get_input: agent_key_name } ] } + openssh_format: true + use_secret_store: false + key_name: { get_input: agent_key_name } + interfaces: + cloudify.interfaces.lifecycle: + create: + implementation: keys.cloudify_ssh_key.operations.create + inputs: + store_private_key_material: true + + external_network: + type: cloudify.openstack.nodes.Network + properties: + openstack_config: *client_config + use_external_resource: true + resource_id: { get_input: external_network_name } + + public_network_subnet_port_fip: + type: cloudify.openstack.nodes.FloatingIP + properties: + openstack_config: *client_config + floatingip: + floating_network_name: { get_input: external_network_name } + + public_network: + type: cloudify.openstack.nodes.Network + properties: + openstack_config: *client_config + + private_network: + type: cloudify.openstack.nodes.Network + properties: + openstack_config: *client_config + + public_network_router: + type: cloudify.openstack.nodes.Router + properties: + openstack_config: *client_config + relationships: + - type: cloudify.relationships.connected_to + target: external_network + + public_network_subnet: + type: cloudify.openstack.nodes.Subnet + properties: + openstack_config: *client_config + subnet: + ip_version: 4 + cidr: { get_input: public_network_subnet_cidr } + dns_nameservers: { get_input: nameservers } + allocation_pools: { get_input: public_network_subnet_allocation_pools } + relationships: + - type: cloudify.relationships.contained_in + target: public_network + - type: cloudify.openstack.subnet_connected_to_router + target: public_network_router + + private_network_subnet: + type: cloudify.openstack.nodes.Subnet + properties: + openstack_config: *client_config + subnet: + ip_version: 4 + cidr: { get_input: private_network_subnet_cidr } + dns_nameservers: { get_input: nameservers } + allocation_pools: { get_input: private_network_subnet_allocation_pools } + relationships: + - type: cloudify.relationships.contained_in + target: private_network + - type: cloudify.openstack.subnet_connected_to_router + target: public_network_router + + cloudify_security_group: + type: cloudify.openstack.nodes.SecurityGroup + properties: + openstack_config: *client_config + rules: + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: null + port_range_max: null + protocol: icmp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 22 + port_range_max: 22 + protocol: tcp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 80 + port_range_max: 80 + protocol: tcp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 443 + port_range_max: 443 + protocol: tcp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 5671 + port_range_max: 5671 + protocol: tcp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 8086 + port_range_max: 8086 + protocol: tcp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 8101 + port_range_max: 8101 + protocol: tcp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 8300 + port_range_max: 8301 + protocol: tcp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 8500 + port_range_max: 8500 + protocol: tcp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 15432 + port_range_max: 15432 + protocol: tcp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 22000 + port_range_max: 22000 + protocol: tcp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 53229 + port_range_max: 53229 + protocol: tcp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 53333 + port_range_max: 53333 + protocol: tcp + - remote_ip_prefix: 0.0.0.0/0 + port_range_min: 30000 + port_range_max: 40000 + protocol: tcp + + public_network_subnet_port: + type: cloudify.openstack.nodes.Port + properties: + openstack_config: *client_config + relationships: + - type: cloudify.relationships.contained_in + target: public_network + - type: cloudify.relationships.depends_on + target: public_network_subnet + - type: cloudify.openstack.port_connected_to_security_group + target: cloudify_security_group + - type: cloudify.openstack.port_connected_to_floating_ip + target: public_network_subnet_port_fip + + private_network_subnet_port: + type: cloudify.openstack.nodes.Port + properties: + openstack_config: *client_config + relationships: + - type: cloudify.relationships.contained_in + target: private_network + - type: cloudify.relationships.depends_on + target: private_network_subnet + - type: cloudify.openstack.port_connected_to_security_group + target: cloudify_security_group + + cloudify_host_cloud_config: + type: cloudify.nodes.CloudInit.CloudConfig + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + resource_config: + users: + - name: { get_input: cloudify_image_username } + primary-group: wheel + shell: /bin/bash + sudo: ['ALL=(ALL) NOPASSWD:ALL'] + ssh-authorized-keys: + - { get_attribute: [ manager_key, public_key_export ] } + packages: + - wget + runcmd: + - { concat: [ 'usermod -aG wheel ', { get_input: cloudify_image_username } ] } + - yum install -y python-backports-ssl_match_hostname python-setuptools python-backports + - { concat: [ 'wget http://storage.googleapis.com/kubernetes-helm/helm-', { get_input: helm_version }, -linux-amd64.tar.gz ] } + - { concat: [ 'tar -zxvf helm-', { get_input: helm_version }, '-linux-amd64.tar.gz' ] } + - mv linux-amd64/helm /usr/bin/helm + relationships: + - type: cloudify.relationships.depends_on + target: manager_key + - type: cloudify.relationships.depends_on + target: public_network_subnet_port + - type: cloudify.relationships.depends_on + target: private_network_subnet_port + + cloudify_host: + type: cloudify.openstack.nodes.Server + properties: + openstack_config: *client_config + agent_config: + install_method: none + server: + key_name: '' + image: { get_input: centos_core_image } + flavor: { get_input: large_image_flavor } + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + image: { get_input: centos_core_image } + flavor: { get_input: large_image_flavor } + userdata: { get_attribute: [ cloudify_host_cloud_config, cloud_config ] } + nics: + - port-id: { get_attribute: [ public_network_subnet_port, external_id ] } + # - port-id: { get_attribute: [ private_network_subnet_port, external_id ] } + relationships: + # Implicitly dependent on ports. + - type: cloudify.relationships.depends_on + target: cloudify_host_cloud_config + +outputs: + + manager_ip: + value: { get_input: public_ip } diff --git a/TOSCA/cloudify-environment-setup/scripts/manager/tasks.py b/TOSCA/cloudify-environment-setup/scripts/manager/tasks.py new file mode 100644 index 0000000000..e929d55098 --- /dev/null +++ b/TOSCA/cloudify-environment-setup/scripts/manager/tasks.py @@ -0,0 +1,206 @@ +# ============LICENSE_START========================================== +# =================================================================== +# Copyright (c) 2018 AT&T +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============LICENSE_END============================================ + +from tempfile import NamedTemporaryFile +from fabric.api import get, sudo, run +from cloudify import ctx +from cloudify.exceptions import NonRecoverableError, RecoverableError + +CONFIG_PATH = '/etc/cloudify/config.yaml' + + +def install_rpm(_rpm): + try: + sudo("rpm -i {0}".format(_rpm)) + except Exception as e: + raise NonRecoverableError(str(e)) + return True + + +def install_requirements(): + try: + sudo("sudo yum install -y python-backports-ssl_match_hostname " + "python-setuptools python-backports") + except Exception as e: + raise NonRecoverableError(str(e)) + return True + + +def update_config(private, public, _config_path): + SED = "sed -i 's|{0}|{1}|g' {2}" + + old_private_ip = " private_ip: \\x27\\x27" + new_private_ip = " private_ip: \\x27{0}\\x27".format(private) + + try: + sudo(SED.format(old_private_ip, new_private_ip, _config_path)) + except Exception as e: + raise NonRecoverableError(str(e)) + + old_public_ip = " public_ip: \\x27\\x27" + new_public_ip = " public_ip: \\x27{0}\\x27".format(public) + + try: + sudo(SED.format(old_public_ip, new_public_ip, _config_path)) + except Exception as e: + raise NonRecoverableError(str(e)) + + old_networks = " networks: {}" + new_networks = " networks: {{ \\x27default\\x27: \\x27{0}\\x27, \\x27external\\x27: \\x27{1}\\x27 }}".format( + private, public) + + try: + sudo(SED.format(old_networks, new_networks, _config_path)) + sudo("chmod 775 {0}".format(_config_path)) + except Exception as e: + raise NonRecoverableError(str(e)) + return True + + +def cfy_install(password, old=False): + sudo("chmod 777 {0}".format(CONFIG_PATH)) + + install_string = 'cfy_manager install' + + if password: + install_string = \ + install_string + ' ' + '--admin-password {0}'.format( + password) + if old: + install_string = install_string + ' --clean-db' + elif not old: + try: + sudo("sudo yum install -y openssl-1.0.2k") + except Exception as e: + raise NonRecoverableError(str(e)) + + try: + run(install_string) + except Exception as e: + ctx.logger.error(str(e)) + return False + + sudo("chmod 775 {0}".format(CONFIG_PATH)) + + return True + + +def plugins_upload(): + try: + run("cfy plugins bundle-upload") + except Exception as e: + raise NonRecoverableError(str(e)) + + return True + + +def secrets_create(secret_key, secret_value): + try: + run("cfy secrets create {0} -s \"{1}\"".format( + secret_key, secret_value)) + except Exception as e: + raise NonRecoverableError(str(e)) + + return True + + +def blueprints_upload(file, name, url): + try: + run("cfy blueprints upload -n {0} -b {1} {2}".format(file, name, url)) + except Exception as e: + raise NonRecoverableError(str(e)) + + return True + + +def create(private_ip, + public_ip, + rpm, + secrets, + blueprints, + config_path=CONFIG_PATH, + password=None, + **_): + ctx.logger.info("Installing Cloudify Manager components.") + + try: + run("echo Hello") + except Exception as e: + raise RecoverableError(str(e)) + + if not ctx.instance.runtime_properties.get('installed_rpm'): + install_requirements() + ctx.instance.runtime_properties['installed_rpm'] = install_rpm(rpm) + + if not ctx.instance.runtime_properties.get('updated_config'): + ctx.instance.runtime_properties['updated_config'] = \ + update_config(private_ip, public_ip, config_path) + + if 'cfy_installed' not in ctx.instance.runtime_properties: + cfy_install_output = cfy_install(password) + else: + cfy_install_output = cfy_install(password, old=True) + + ctx.instance.runtime_properties['cfy_installed'] = cfy_install_output + if not cfy_install_output: + raise RecoverableError('cfy install failed.') + + if not ctx.instance.runtime_properties.get('plugins_uploaded'): + try: + run( + "cfy plugins upload https://nexus.onap.org/content/sites/raw/org.onap.ccsdk.platform.plugins/plugins/helm-3.0.0-py27-none-linux_x86_64.wgn -y https://nexus.onap.org/content/sites/raw/org.onap.ccsdk.platform.plugins/type_files/helm/1.1.0/helm-type.yaml") + except Exception as e: + raise NonRecoverableError(str(e)) + ctx.instance.runtime_properties['plugins_uploaded'] = plugins_upload() + + more_secrets = [ + {'key': 'cfy_user', 'value': 'admin'}, + {'key': 'kubernetes_master_port', 'value': 'kubernetes_master_port'}, + {'key': 'kubernetes-admin_client_certificate_data', + 'value': 'kubernetes-admin_client_certificate_data'}, + {'key': 'kubernetes_master_ip', 'value': 'kubernetes_master_ip'}, + {'key': 'kubernetes_certificate_authority_data', + 'value': 'kubernetes_certificate_authority_data'}, + {'key': 'kubernetes-admin_client_key_data', + 'value': 'kubernetes-admin_client_key_data'}, + {'key': 'cfy_password', 'value': password or 'cfy_password'}, + {'key': 'cfy_tenant', 'value': 'default_tenant'}, + {'key': 'kubernetes_token', 'value': 'kubernetes_token'} + ] + for ms in more_secrets: + secrets.append(ms) + + for secret in secrets: + secrets_create( + secret.get('key'), + secret.get('value')) + + for blueprint in blueprints: + blueprints_upload( + blueprint.get('file'), + blueprint.get('name'), + blueprint.get('url')) + + ctx.logger.info( + "Initialize your CLI profile: " + "`cfy profiles use " + "{0} -u admin -p {1} -t default_tenant`".format(public_ip, + password or "_")) + if not password: + ctx.logger.info( + "Since you did not provide a password, scroll up though " + "the execution log and search for \"Manager password is\".")