diff options
Diffstat (limited to 'platform_base_installation')
-rw-r--r-- | platform_base_installation/README.md | 32 | ||||
-rw-r--r-- | platform_base_installation/centos_vm.yaml | 239 | ||||
-rw-r--r-- | platform_base_installation/consul.md | 44 | ||||
-rw-r--r-- | platform_base_installation/consul_cluster.yaml | 377 | ||||
-rw-r--r-- | platform_base_installation/install.md | 38 | ||||
-rwxr-xr-x | platform_base_installation/installer | 350 |
6 files changed, 1080 insertions, 0 deletions
diff --git a/platform_base_installation/README.md b/platform_base_installation/README.md new file mode 100644 index 0000000..3c782f0 --- /dev/null +++ b/platform_base_installation/README.md @@ -0,0 +1,32 @@ +### ONAP Controller Core Components Installation +The ONAP Operations Manager and the next-generation ONAP DCAE system use Cloudify Manager, a third party open source product, +as the core orchestration engine. They use Consul, another third party open source product, as +a key-value store, a service discovery system, and a health monitoring tool. + +This repository contains scripts and artifacts that are used to create +a VM in an OpenStack environment and then install the Cloudify Manager software on it. +Once the Cloudify Manager software is installed, the script uses Cloudify Manager to deploy +a 3-VM cluster running Consul in a high-availability mode. When the deployment completes, the script registers +Cloudify Manager as a service in Consul and puts Consul's address into a configuration file +on the Cloudify Manager VM. + +Eventually we expect that the ECOMP controller will launch the next-generation DCAE controller using a Cloudify blueprint that's executed by the ECOMP controller's Cloudify Manager system. Until that system is ready, the script and artifacts +here can be used to deploy a Cloudify Manager and a Consul cluster for the DCAE controller. + +Documentation in this repo: +- The installation instructions are in the [`install.md` file](./install.md). +- A description of how the installation process sets up Consul is in the [`consul.md` file](./consul.md). + +External documentation links: + +- [Information about Cloudify](http://getcloudify.org) +- [Information about Consul](http://consul.io) + + +#### Limitations +- The installation process does _not_ set up TLS certificates for any of the host VMs and therefore does not configure Cloudify Manager and Consul to use HTTPS. +- The installation process does _not_ set up authentication, authorization, and access control for Cloudify Manager and Consul. +- The installation process sets up one non-root user on each VM. The user is configured for access using the keypair provided at installation time. +- The Cloudify Manager is _not_ set up for highly availability. +- While Consul _is_ set up in a high-availability configuration, clients need to know the addresses of all three Consul VMs. In the event that a client cannot reach one of the VMs, the client must try another address. +- The installation process installs the Web-based user interfaces for both Cloudify Manager and Consul. This may not desirable for production environments.
\ No newline at end of file diff --git a/platform_base_installation/centos_vm.yaml b/platform_base_installation/centos_vm.yaml new file mode 100644 index 0000000..b3a0ce7 --- /dev/null +++ b/platform_base_installation/centos_vm.yaml @@ -0,0 +1,239 @@ +# +# ============LICENSE_START========================================== +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# 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============================================ +# +# ECOMP and OpenECOMP are trademarks +# and service marks of AT&T Intellectual Property. +# + +tosca_definitions_version: cloudify_dsl_1_3 + +imports: + - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml + - http://www.getcloudify.org/spec/openstack-plugin/1.4/plugin.yaml + - http://www.getcloudify.org/spec/fabric-plugin/1.4.1/plugin.yaml + - types/dns_types.yaml + - types/sshkey_types.yaml + +inputs: + centos7image_id: + type: string + ubuntu1604image_id: + type: string + flavor_id: + type: string + security_group: + type: string + public_net: + type: string + private_net: + type: string + openstack: {} + keypair: + type: string + location_prefix: + type: string + location_domain: + type: string + key_filename: + type: string + codesource_url: + type: string + codesource_version: + type: string + cname: + type: string + default: dcae-orcl + datacenter: + type: string + vm_init_clmg_00: + type: string + default: |- + #!/bin/sh + set -x + DATACENTER= + vm_init_clmg_01: + type: string + default: | + CONSULVER=consul_0.8.3 + CONSULNAME=${CONSULVER}_linux_amd64 + MYIP=`curl -Ss http://169.254.169.254/2009-04-04/meta-data/local-ipv4` + MYNAME=`hostname` + echo >>/etc/hosts + echo $MYIP $MYNAME >>/etc/hosts + mkdir -p /opt/consul/config /opt/consul/data /opt/consul/bin + # Download Consul + curl -Ss https://releases.hashicorp.com/consul/${CONSULVER}/${CONSULNAME}.zip > ${CONSULNAME}.zip + unzip -d /opt/consul/bin ${CONSULNAME}.zip + rm ${CONSULNAME}.zip + chmod +x /opt/consul/bin/consul + cat <<EOF > /opt/consul/config/consul.json + { + "bind_addr" : "0.0.0.0", + "client_addr" : "0.0.0.0", + "data_dir" : "/opt/consul/data", + "datacenter": "$DATACENTER", + "rejoin_after_leave": true, + "http_api_response_headers": { + "Access-Control-Allow-Origin" : "*" + }, + "server": false, + "ui": false, + "enable_syslog": true, + "log_level": "info" + } + EOF + cat <<EOF > /lib/systemd/system/consul.service + [Unit] + Description=Consul + Requires=network-online.target + After=network.target + [Service] + Type=simple + ExecStart=/opt/consul/bin/consul agent -config-dir=/opt/consul/config + ExecReload=/bin/kill -HUP \$MAINPID + [Install] + WantedBy=multi-user.target + EOF + systemctl enable consul + systemctl start consul + yum install -y python-psycopg2 + +node_templates: + key_pair: + type: cloudify.openstack.nodes.KeyPair + properties: + private_key_path: { get_input: key_filename } + use_external_resource: True + resource_id: { get_input: keypair } + openstack_config: &open_conf + get_input: openstack + private_net: + type: cloudify.openstack.nodes.Network + properties: + use_external_resource: True + resource_id: { get_input: private_net } + openstack_config: *open_conf + security_group: + type: cloudify.openstack.nodes.SecurityGroup + properties: + use_external_resource: True + resource_id: { get_input: security_group } + openstack_config: *open_conf + fixedip_vm00: + type: cloudify.openstack.nodes.Port + properties: + port: + extra_dhcp_opts: + - opt_name: 'domain-name' + opt_value: { get_input: location_domain } + openstack_config: *open_conf + relationships: + - type: cloudify.relationships.contained_in + target: private_net + floatingip_vm00: + type: cloudify.openstack.nodes.FloatingIP + properties: + openstack_config: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + floating_network_name: { get_input: public_net } + dns_vm00: + type: ccsdk.nodes.dns.arecord + properties: + fqdn: { concat: [ { get_input: location_prefix }, 'orcl00.', { get_input: location_domain } ] } + openstack: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + ip_addresses: + - { get_attribute: [ floatingip_vm00, floating_ip_address ] } + relationships: + - type: cloudify.relationships.depends_on + target: floatingip_vm00 + dns_cm: + type: ccsdk.nodes.dns.arecord + properties: + fqdn: { concat: [ 'cloudify-manager-', { get_input: datacenter}, '.', { get_input: location_domain } ] } + openstack: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + ip_addresses: + - { get_attribute: [ floatingip_vm00, floating_ip_address ] } + relationships: + - type: cloudify.relationships.depends_on + target: floatingip_vm00 + dns_cname: + type: ccsdk.nodes.dns.cnamerecord + properties: + fqdn: { concat: [ { get_input: cname }, '.', { get_input: location_domain } ] } + openstack: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + cname: { get_property: [ dns_vm00, fqdn ] } + relationships: + - type: cloudify.relationships.depends_on + target: dns_vm00 + host_vm00: + type: cloudify.openstack.nodes.Server + properties: + install_agent: false + image: { get_input: centos7image_id } + flavor: { get_input: flavor_id } + management_network_name: { get_input: private_net } + openstack_config: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + name: { concat: [ { get_input: location_prefix }, 'orcl00' ] } + userdata: + concat: + - { get_input: vm_init_clmg_00 } + - { get_input: datacenter } + - |+ + + - { get_input: vm_init_clmg_01 } + relationships: + - type: cloudify.openstack.server_connected_to_port + target: fixedip_vm00 + - type: cloudify.openstack.server_connected_to_security_group + target: security_group + - type: cloudify.openstack.server_connected_to_floating_ip + target: floatingip_vm00 + - type: cloudify.openstack.server_connected_to_keypair + target: key_pair + - type: cloudify.relationships.depends_on + target: dns_vm00 + - type: cloudify.relationships.depends_on + target: dns_cm + +outputs: + public_ip: + value: { get_attribute: [floatingip_vm00, floating_ip_address] } diff --git a/platform_base_installation/consul.md b/platform_base_installation/consul.md new file mode 100644 index 0000000..82f2f61 --- /dev/null +++ b/platform_base_installation/consul.md @@ -0,0 +1,44 @@ +### Consul configuration for ECOMP and DCAE controllers + +#### Version and source +This installation uses Consul 0.8.3. + +Consul is an open source project, and it can be built from source. For this project, however, we are using a binary distribution provided by Hashicorp (the company responsible for Consul development), pulled from https://releases.hashicorp.com/consul/0.8.3/consul_0.8.3_linux_amd64.zip. The zip file contains a single file, the consul +binary executable. + + +#### How the installation works +The installation is driven by a Cloudify blueprint ([`consul_cluster.yaml`](./consul_cluster.yaml)) with a set of inputs describing the OpenStack environment (typically generated by running the `configure-dcae` command as described in +the [installation instructions](./install.md)). + +The blueprint creates three virtual machines, each running Ubuntu 16.04. The blueprint includes an initial shell script that runs when the VM is first booted (the so-called `cloud-init` script). This shell script: +- creates the `/opt/consul/bin`, `/opt/consul/data`, and `/opt/consul/config`, and `/opt/consul/data` directories +- installs the consul binary in `/opt/consul/bin/consul`. +- creates a Consul configuration file and installs it in `/opt/consul/config/consul.json`. +- creates a `systemd` unit file that contains instructions for starting Consul when the system boots and stores it in +`/lib/systemd/system/consul.service`. The Consul software is started in `server` mode. +- enables the Consul service so that `systemd` will start it on boot. +- explicitly starts the Consul service. + +The blueprint launches two VMs in parallel. It does not attempt to launch the third VM until the first two have started and their private IP addresses are known. + +The initialization script for the third VM has one additional step, at the very end. The script issues a `consul join` command targeting the first two machines. This creates the cluster. + +After Cloudify finishes with the installation, the [`installer` script](./installer) waits for the Consul API to become available on the first Consul server, and then attempts to register Cloudify Manager as an [external service](https://www.consul.io/docs/guides/external.html) in Consul. It also puts the address of the first server into the `/opt/env.ini` file on the Cloudify Manager host. (It puts in one address to maintain consistency with the earlier installation process that installed a single Consul server in a Docker container. Certain plugins rely on this entry in `/opt/env.ini`, and they expect a single address. This will eventually change.) + +#### Managing Consul +We don't anticipate a need for hands-on management of Consul. When a Consul VM is rebooted, Consul will start automatically and will rejoin the Consul cluster. + +If there's a need to look more closely at what's going on with a Consul VM, logging in and becoming root provides access to the `systemd` tools. In particular: + +- `systemctl stop consul` will stop the consul service. +- `systemctl start consul` with start the consul service. +- `journalctl -u consul` will show the log for the consul service. +- `journalctl -u consul -f` will "tail" the log for the consul service. + +The crucial files for Consul are located in: +- `/opt/consul/config/config.json` - the Consul configuration file. See the [Consul documentation of configuration options](https://www.consul.io/docs/agent/options.html). +- `lib/systemd/system/consul.service` - the `systemd` unit file for the Consul service. +- `/opt/consul/data` - directory where Consul stores its persistent data. + +Note that the Consul instances communicate with each other over the OpenStack private network--that is, they use private addresses, rather than the floating IP addresses, to contact each other. diff --git a/platform_base_installation/consul_cluster.yaml b/platform_base_installation/consul_cluster.yaml new file mode 100644 index 0000000..f399df3 --- /dev/null +++ b/platform_base_installation/consul_cluster.yaml @@ -0,0 +1,377 @@ +# +# ============LICENSE_START========================================== +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# 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============================================ +# +# ECOMP and OpenECOMP are trademarks +# and service marks of AT&T Intellectual Property. +# + +tosca_definitions_version: cloudify_dsl_1_3 + +imports: + - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml + - http://www.getcloudify.org/spec/openstack-plugin/1.4/plugin.yaml + - "{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/type_files/dnsdesig/dns_types.yaml" + - "{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/type_files/sshkeyshare/sshkey_types.yaml" + +inputs: + centos7image_id: + type: string + ubuntu1604image_id: + type: string + flavor_id: + type: string + security_group: + type: string + public_net: + type: string + private_net: + type: string + openstack: {} + keypair: + type: string + location_prefix: + type: string + location_domain: + type: string + key_filename: + type: string + codesource_url: + type: string + codesource_version: + type: string + datacenter: + type: string + vm_init_cnsl_00: + type: string + default: |- + #!/bin/sh + set -x + DATACENTER= + vm_init_cnsl_01: + type: string + default: | + CONSULVER=consul_0.8.3 + CONSULNAME=${CONSULVER}_linux_amd64 + MYIP=`wget -qO- http://169.254.169.254/2009-04-04/meta-data/local-ipv4` + MYNAME=`hostname` + echo >>/etc/hosts + echo $MYIP $MYNAME >>/etc/hosts + mkdir -p /opt/consul/config /opt/consul/data /opt/consul/bin + + # Download Consul + wget https://releases.hashicorp.com/consul/${CONSULVER}/${CONSULNAME}.zip + unzip -d /opt/consul/bin ${CONSULNAME}.zip + rm ${CONSULNAME}.zip + chmod +x /opt/consul/bin/consul + + # NOTE: Not using port 80 for http to avoid port collision of user facing services + # particularly for more large scale deployments of Consul. + cat <<EOF > /opt/consul/config/consul.json + { + "bind_addr" : "$MYIP", + "client_addr" : "0.0.0.0", + "bootstrap_expect" : 3, + "data_dir" : "/opt/consul/data", + "datacenter": "$DATACENTER", + "http_api_response_headers": { + "Access-Control-Allow-Origin" : "*" + }, + "server": true, + "ui": true, + "enable_syslog": true, + "log_level": "info", + "ports": { + "dns": 53 + } + } + EOF + cat <<EOF > /lib/systemd/system/consul.service + [Unit] + Description=Consul + Requires=network-online.target + After=network.target + [Service] + Type=simple + ExecStart=/opt/consul/bin/consul agent -config-dir=/opt/consul/config + ExecReload=/bin/kill -HUP \$MAINPID + [Install] + WantedBy=multi-user.target + EOF + systemctl enable consul + systemctl start consul +node_templates: + key_pair: + type: cloudify.openstack.nodes.KeyPair + properties: + private_key_path: { get_input: key_filename } + use_external_resource: True + resource_id: { get_input: keypair } + openstack_config: &open_conf + get_input: openstack + private_net: + type: cloudify.openstack.nodes.Network + properties: + use_external_resource: True + resource_id: { get_input: private_net } + openstack_config: *open_conf + security_group: + type: cloudify.openstack.nodes.SecurityGroup + properties: + use_external_resource: True + resource_id: { get_input: security_group } + openstack_config: *open_conf + fixedip_cnsl00: + type: cloudify.openstack.nodes.Port + properties: + port: + extra_dhcp_opts: + - opt_name: 'domain-name' + opt_value: { get_input: location_domain } + openstack_config: *open_conf + relationships: + - type: cloudify.relationships.contained_in + target: private_net + floatingip_cnsl00: + type: cloudify.openstack.nodes.FloatingIP + properties: + openstack_config: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + floating_network_name: { get_input: public_net } + dns_cnsl00: + type: ccsdk.nodes.dns.arecord + properties: + fqdn: { concat: [ { get_input: location_prefix }, 'cnsl00.', { get_input: location_domain } ] } + openstack: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + ip_addresses: + - { get_attribute: [ floatingip_cnsl00, floating_ip_address ] } + relationships: + - type: cloudify.relationships.depends_on + target: floatingip_cnsl00 + host_cnsl00: + type: cloudify.openstack.nodes.Server + properties: + install_agent: false + image: { get_input: ubuntu1604image_id } + flavor: { get_input: flavor_id } + management_network_name: { get_input: private_net } + openstack_config: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + name: { concat: [ { get_input: location_prefix }, 'cnsl00' ] } + userdata: + concat: + - { get_input: vm_init_cnsl_00 } + - { get_input: datacenter } + - |+ + + - { get_input: vm_init_cnsl_01 } + - concat: + - 'until /opt/consul/bin/consul join ' + - { get_attribute: [host_cnsl01, ip] } + - ' ' + - { get_attribute: [host_cnsl02, ip]} + - '; do sleep 15; done' + + relationships: + - type: cloudify.openstack.server_connected_to_port + target: fixedip_cnsl00 + - type: cloudify.openstack.server_connected_to_security_group + target: security_group + - type: cloudify.openstack.server_connected_to_floating_ip + target: floatingip_cnsl00 + - type: cloudify.openstack.server_connected_to_keypair + target: key_pair + - type: cloudify.relationships.depends_on + target: dns_cnsl00 + - type: cloudify.relationships.depends_on + target: host_cnsl01 + - type: cloudify.relationships.depends_on + target: host_cnsl02 + fixedip_cnsl01: + type: cloudify.openstack.nodes.Port + properties: + port: + extra_dhcp_opts: + - opt_name: 'domain-name' + opt_value: { get_input: location_domain } + openstack_config: *open_conf + relationships: + - type: cloudify.relationships.contained_in + target: private_net + floatingip_cnsl01: + type: cloudify.openstack.nodes.FloatingIP + properties: + openstack_config: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + floating_network_name: { get_input: public_net } + dns_cnsl01: + type: ccsdk.nodes.dns.arecord + properties: + fqdn: { concat: [ { get_input: location_prefix }, 'cnsl01.', { get_input: location_domain } ] } + openstack: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + ip_addresses: + - { get_attribute: [ floatingip_cnsl01, floating_ip_address ] } + relationships: + - type: cloudify.relationships.depends_on + target: floatingip_cnsl01 + host_cnsl01: + type: cloudify.openstack.nodes.Server + properties: + install_agent: false + image: { get_input: ubuntu1604image_id } + flavor: { get_input: flavor_id } + management_network_name: { get_input: private_net } + openstack_config: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + name: { concat: [ { get_input: location_prefix }, 'cnsl01' ] } + userdata: + concat: + - { get_input: vm_init_cnsl_00 } + - { get_input: datacenter } + - |+ + + - { get_input: vm_init_cnsl_01 } + relationships: + - type: cloudify.openstack.server_connected_to_port + target: fixedip_cnsl01 + - type: cloudify.openstack.server_connected_to_security_group + target: security_group + - type: cloudify.openstack.server_connected_to_floating_ip + target: floatingip_cnsl01 + - type: cloudify.openstack.server_connected_to_keypair + target: key_pair + - type: cloudify.relationships.depends_on + target: dns_cnsl01 + fixedip_cnsl02: + type: cloudify.openstack.nodes.Port + properties: + port: + extra_dhcp_opts: + - opt_name: 'domain-name' + opt_value: { get_input: location_domain } + openstack_config: *open_conf + relationships: + - type: cloudify.relationships.contained_in + target: private_net + floatingip_cnsl02: + type: cloudify.openstack.nodes.FloatingIP + properties: + openstack_config: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + floating_network_name: { get_input: public_net } + dns_cnsl02: + type: ccsdk.nodes.dns.arecord + properties: + fqdn: { concat: [ { get_input: location_prefix }, 'cnsl02.', { get_input: location_domain } ] } + openstack: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + ip_addresses: + - { get_attribute: [ floatingip_cnsl02, floating_ip_address ] } + relationships: + - type: cloudify.relationships.depends_on + target: floatingip_cnsl02 + dns_cluster: + type: ccsdk.nodes.dns.arecord + properties: + fqdn: { concat: [ 'dcae-cnsl.', { get_input: location_domain } ] } + openstack: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + ip_addresses: + - { get_attribute: [ floatingip_cnsl00, floating_ip_address ] } + - { get_attribute: [ floatingip_cnsl01, floating_ip_address ] } + - { get_attribute: [ floatingip_cnsl02, floating_ip_address ] } + relationships: + - type: cloudify.relationships.depends_on + target: floatingip_cnsl00 + - type: cloudify.relationships.depends_on + target: floatingip_cnsl01 + - type: cloudify.relationships.depends_on + target: floatingip_cnsl02 + host_cnsl02: + type: cloudify.openstack.nodes.Server + properties: + install_agent: false + image: { get_input: ubuntu1604image_id } + flavor: { get_input: flavor_id } + management_network_name: { get_input: private_net } + openstack_config: *open_conf + interfaces: + cloudify.interfaces.lifecycle: + create: + inputs: + args: + name: { concat: [ { get_input: location_prefix }, 'cnsl02' ] } + userdata: + concat: + - { get_input: vm_init_cnsl_00 } + - { get_input: datacenter } + - |+ + + - { get_input: vm_init_cnsl_01 } + relationships: + - type: cloudify.openstack.server_connected_to_port + target: fixedip_cnsl02 + - type: cloudify.openstack.server_connected_to_security_group + target: security_group + - type: cloudify.openstack.server_connected_to_floating_ip + target: floatingip_cnsl02 + - type: cloudify.openstack.server_connected_to_keypair + target: key_pair + - type: cloudify.relationships.depends_on + target: dns_cnsl02 + +outputs: + public_ip: + value: { get_attribute: [floatingip_cnsl00, floating_ip_address] } diff --git a/platform_base_installation/install.md b/platform_base_installation/install.md new file mode 100644 index 0000000..036101e --- /dev/null +++ b/platform_base_installation/install.md @@ -0,0 +1,38 @@ +### Cloudify Manager/Consul Installation + +### Setting up for installation +#### Installation machine +This installation process is a _bootstrap process_, not a conventional software installation. In a conventional installation, the installer spins up a VM and then runs a software installation on it. That is *_not_* how this installation process works. This installation targets an OpenStack tenant that is essentially empty. The installation process will create the VMs that it needs in the OpenStack tenant. The installation process is launched from a machine *_that is not in the OpenStack tenant where the controller is being installed_*. + +The installation machine--which, again, *_must not be in the tenant where the controller is being installed_* must have: + - CentOS 7 operating system. (CentOS 6 can be made to work also.) + - A `bash` interpreter + - `wget`, `curl`, and `unzip` + - A python _development_ environment, including `gcc` and the appropriate Python development package for the distro. + - The python `pip` (version 9.01 or later) and `virtualenv` (version 15.0.2 or later) tools. + - Connectivity to this source code repository. + - Connectivity to the repository holding deployment artifacts. + - Connectivity to the Internet. + - And, obviously, connectivity to the OpenStack tenant where the controller is being installed. + +#### Tenant setup +Certain things need to be set up in the tenant in order to allow the installation to proceed. An `inputs.yaml` containing information about the +tenant must be created for use in the installation step. +TODO: Provide more details here. + +#### Installing Cloudify Manager and Consul +Once the tenant is set up and the `inputs.yaml` file is available, Cloudify Manager and the Consul cluster can be +installed. The `installer` script in this repository automates the installation. + +To run the script: + - Create a new directory on the installation machine + - Enter the new directory + - Place a copy of `installer` in the directory + - `chmod +x installer` + - `./installer --inputs /path/to/inputs/file --ssh-key /path/to/ssh-key --location-id location-id`, where: + - `/path/to/inputs/file` is the path to the file generated with `configure-dcae` + - `/path/to/ssh-key` is the path to a local copy of the private key for the keypair set up with `configure-dcae` + - `location-id` is the location id (e.g., `solutioning-central`) that will be used to identify the location where this deployment is being performed. `location-id` sets the Consul datacenter name; it also is used in the Cloudify Manager environment file to mark the section of the file where information about this location is stored. + + + diff --git a/platform_base_installation/installer b/platform_base_installation/installer new file mode 100755 index 0000000..600849b --- /dev/null +++ b/platform_base_installation/installer @@ -0,0 +1,350 @@ +#!/bin/bash +# +# ============LICENSE_START========================================== +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# 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============================================ +# +# ECOMP and OpenECOMP are trademarks +# and service marks of AT&T Intellectual Property. +# + +# URLs for artifacts needed for installation +DESIGTYPES={{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/type_files/dnsdesig/dns_types.yaml +DESIGPLUG={{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/dnsdesig-1.0.0-py27-none-any.wgn +SSHKEYTYPES={{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/type_files/sshkeyshare/sshkey_types.yaml +SSHKEYPLUG={{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/sshkeyshare-1.0.0-py27-none-any.wgn +CMVMBP={{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/blueprints/centos_vm.yaml +CONSULBP={{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/blueprints/consul_cluster.yaml +# Wagon package for OpenStack plugin +OSPLUGIN={{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/cloudify_openstack_plugin-1.4-py27-none-linux_x86_64-centos-Core.wgn + +# Make sure ssh doesn't prompt for new host or choke on a new host with an IP it's seen before +SSHOPTS="-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" +STARTDIR=$(pwd) + +LOCATION= +SSHUSER=centos +PVTKEY= +INPUTS=inputs.yaml +PUBIP= + +while [ "$#" != 0 ] +do + case "$1" in + '--inputs') + INPUTS="$2" + shift 2 + ;; + '--remote-user') + SSHUSER="$2" + shift 2 + ;; + '--fqdn') + PUBIP="$2" + shift 2 + ;; + '--ssh-key') + PVTKEY="$2" + shift 2 + ;; + '--location-id') + LOCATION="$2" + shift 2 + ;; + *) + LOCATION="" + break; + ;; + esac +done + +if [ "$PVTKEY" = "" -o "$LOCATION" = "" ] +then + echo Usage: "$0" '--ssh-key ssh-private-key-file --location-id location-id [--remote-user remote-user-name] [--fqdn fqdn] [--inputs inputs-file-path]' + exit 1 +fi + + +set -e +set -x + +# Create a virtual environment +virtualenv dcaeinstall +source dcaeinstall/bin/activate + +# Install Cloudify +pip install cloudify==3.4.0 + +# Install the Cloudify OpenStack plugin from a wagon +# (Avoid changes in dependency versions that could cause conflict) +wget -O osplugin.wgn ${OSPLUGIN} +wagon install -s osplugin.wgn + +# Do we need to spin up a VM +if [ -z ${PUBIP} ] +then + # Get the Designate and SSH key plugins and type files + mkdir -p plugins/dnsdesig + mkdir plugins/sshkeyshare + mkdir types + + wget -qO- ${DESIGTYPES} > types/dns_types.yaml + wget -qO- ${SSHKEYTYPES} > types/sshkey_types.yaml + + wget -O dnsdesig.wgn ${DESIGPLUG} + wget -O sshkeyshare.wgn ${SSHKEYPLUG} + + wagon install -s dnsdesig.wgn + wagon install -s sshkeyshare.wgn + + # Get the blueprint for the Centos VM needed for Cloudify Manager + wget -O centos_vm.yaml ${CMVMBP} + + # Fix up the inputs file to get the private key locally + sed -e "s#key_filename:.*#key_filename: $PVTKEY#" < ${INPUTS} > /tmp/local_inputs + # Now install the VM + cfy local init --install-plugins -p centos_vm.yaml -i /tmp/local_inputs -i "datacenter=$LOCATION" + cfy local execute -w install --task-retries=10 + PUBIP=$(cfy local outputs | grep -Po '"public_ip": "\K.*?(?=")') + + # It's probably not completely ready when the installation finish, so wait + sleep 180 +fi + +echo "Installing Cloudify Manager on ${PUBIP}." + +PVTIP=$(ssh $SSHOPTS -i "$PVTKEY" "$SSHUSER"@"$PUBIP" 'echo PVTIP=`curl --silent http://169.254.169.254/2009-04-04/meta-data/local-ipv4`' | grep PVTIP | sed 's/PVTIP=//') +if [ "$PVTIP" = "" ] +then + echo Cannot access specified machine at $PUBIP using supplied credentials + exit 1 +fi + + +# Copy private key onto Cloudify Manager VM +PVTKEYPATH=$(cat ${INPUTS} | grep "key_filename" | cut -d "'" -f2) +PVTKEYNAME=$(basename $PVTKEYPATH) +PVTKEYDIR=$(dirname $PVTKEYPATH) +scp $SSHOPTS -i $PVTKEY $PVTKEY $SSHUSER@$PUBIP:/tmp/$PVTKEYNAME +ssh -t $SSHOPTS -i $PVTKEY $SSHUSER@$PUBIP sudo mkdir -p $PVTKEYDIR +ssh -t $SSHOPTS -i $PVTKEY $SSHUSER@$PUBIP sudo mv /tmp/$PVTKEYNAME $PVTKEYPATH + +ESMAGIC=$(uuidgen -r) +WORKDIR=$HOME/cmtmp +BSDIR=$WORKDIR/cmbootstrap +PVTKEY2=$BSDIR/id_rsa.cfybootstrap +TMPBASE=$WORKDIR/tmp +TMPDIR=$TMPBASE/lib +SRCS=$WORKDIR/srcs.tar +TOOL=$WORKDIR/tool.py +rm -rf $WORKDIR +mkdir -p $BSDIR $TMPDIR/cloudify/wheels $TMPDIR/cloudify/sources $TMPDIR/manager +chmod 700 $WORKDIR +cp "$PVTKEY" $PVTKEY2 +cat >$TOOL <<!EOF +#!/usr/local/bin/python + +import yaml +import sys +bsdir = sys.argv[1] +with open(bsdir + '/simple-manager-blueprint-inputs.yaml', 'r') as f: + inpyaml = yaml.load(f) +with open(bsdir + '/simple-manager-blueprint.yaml', 'r') as f: + bpyaml = yaml.load(f) +for param, value in bpyaml['inputs'].items(): + if value.has_key('default') and not inpyaml.has_key(param): + inpyaml[param] = value['default'] +print inpyaml['manager_resources_package'] +!EOF + +# +# Try to disable attempt to download virtualenv when not needed +# +ssh $SSHOPTS -t -i $PVTKEY2 $SSHUSER@$PUBIP 'sudo bash -xc "echo y; mkdir -p /root/.virtualenv; echo '"'"'[virtualenv]'"'"' >/root/.virtualenv/virtualenv.ini; echo no-download=true >>/root/.virtualenv/virtualenv.ini"' + +# Gather installation artifacts +# from documentation, URL for manager blueprints archive +BSURL=https://github.com/cloudify-cosmo/cloudify-manager-blueprints/archive/3.4.tar.gz +BSFILE=$(basename $BSURL) + +umask 022 +wget -qO- $BSURL >$BSDIR/$BSFILE +cd $BSDIR +tar xzvf $BSFILE +MRPURL=$(python $TOOL $BSDIR/cloudify-manager-blueprints-3.4) +MRPFILE=$(basename $MRPURL) +wget -qO- $MRPURL >$TMPDIR/cloudify/sources/$MRPFILE + +tar cf $SRCS -C $TMPDIR cloudify +rm -rf $TMPBASE +# +# Load required package files onto VM +# +scp $SSHOPTS -i $PVTKEY2 $SRCS $SSHUSER@$PUBIP:/tmp/. +ssh -t $SSHOPTS -i $PVTKEY2 $SSHUSER@$PUBIP 'sudo bash -xc "cd /opt; tar xf /tmp/srcs.tar; chown -R root:root /opt/cloudify /opt/manager; rm -rf /tmp/srcs.tar"' +# +# Install config file -- was done by DCAE controller. What now? +# +ssh $SSHOPTS -t -i $PVTKEY2 $SSHUSER@$PUBIP 'sudo bash -xc '"'"'mkdir -p /opt/dcae; if [ -f /tmp/cfy-config.txt ]; then cp /tmp/cfy-config.txt /opt/dcae/config.txt && chmod 644 /opt/dcae/config.txt; fi'"'" +cd $WORKDIR + +# +# Check for and set up https certificate information +# +rm -f $BSDIR/cloudify-manager-blueprints-3.4/resources/ssl/server.key $BSDIR/cloudify-manager-blueprints-3.4/resources/ssl/server.crt +ssh -t $SSHOPTS -i $PVTKEY2 $SSHUSER@$PUBIP 'sudo bash -xc "openssl pkcs12 -in /opt/app/dcae-certificate/certificate.pkcs12 -passin file:/opt/app/dcae-certificate/.password -nodes -chain"' | awk 'BEGIN{x="/dev/null";}/-----BEGIN CERTIFICATE-----/{x="'$BSDIR'/cloudify-manager-blueprints-3.4/resources/ssl/server.crt";}/-----BEGIN PRIVATE KEY-----/{x="'$BSDIR'/cloudify-manager-blueprints-3.4/resources/ssl/server.key";}{print >x;}/-----END /{x="/dev/null";}' +USESSL=false +if [ -f $BSDIR/cloudify-manager-blueprints-3.4/resources/ssl/server.key -a -f $BSDIR/cloudify-manager-blueprints-3.4/resources/ssl/server.crt ] +then + USESSL=true +fi +# +# Set up configuration for the bootstrap +# +export CLOUDIFY_USERNAME=admin CLOUDIFY_PASSWORD=encc0fba9f6d618a1a51935b42342b17658 +cd $BSDIR/cloudify-manager-blueprints-3.4 +cp simple-manager-blueprint.yaml bootstrap-blueprint.yaml +ed bootstrap-blueprint.yaml <<'!EOF' +/^node_types:/-1a + plugin_resources: + description: > + Holds any archives that should be uploaded to the manager. + default: [] + dsl_resources: + description: > + Holds a set of dsl required resources + default: [] +. +/^ upload_resources:/a + plugin_resources: { get_input: plugin_resources } +. +w +q +!EOF +sed <simple-manager-blueprint-inputs.yaml >bootstrap-inputs.yaml \ + -e "s;.*public_ip: .*;public_ip: '$PUBIP';" \ + -e "s;.*private_ip: .*;private_ip: '$PVTIP';" \ + -e "s;.*ssh_user: .*;ssh_user: '$SSHUSER';" \ + -e "s;.*ssh_key_filename: .*;ssh_key_filename: '$PVTKEY2';" \ + -e "s;.*elasticsearch_java_opts: .*;elasticsearch_java_opts: '-Des.cluster.name=$ESMAGIC';" \ + -e "/ssl_enabled: /s/.*/ssl_enabled: $USESSL/" \ + -e "/security_enabled: /s/.*/security_enabled: $USESSL/" \ + -e "/admin_password: /s/.*/admin_password: '$CLOUDIFY_PASSWORD'/" \ + -e "/admin_username: /s/.*/admin_username: '$CLOUDIFY_USERNAME'/" \ + -e "s;.*manager_resources_package: .*;manager_resources_package: 'http://169.254.169.254/nosuchthing/$MRPFILE';" \ + -e "s;.*ignore_bootstrap_validations: .*;ignore_bootstrap_validations: true;" \ + +# Add plugin resources +cat >>bootstrap-inputs.yaml <<'!EOF' +plugin_resources: + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/dnsdesig-0.1.4-py27-none-any.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/sshkeyshare-0.1.0-py27-none-any.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/cdapcloudify-12.0.0-py27-none-linux_x86_64-centos-Core.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/cdapcloudify-12.1.0-py27-none-any-none-none.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/cdapcloudify-13.0.0-py27-none-any-none-none.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/cdapcloudify-13.1.0-py27-none-any-none-none.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/dockerplugin-1.0.0-py27-none-linux_x86_64-centos-Core.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/dockerplugin-2.0.0-py27-none-linux_x86_64-centos-Core.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/dockerplugin-2.1.0-py27-none-any.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/relationshipplugin-0.3.3-py27-none-linux_x86_64-centos-Core.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/relationshipplugin-1.0.0-py27-none-linux_x86_64-centos-Core.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/brokerdeletioncloudify-0.2.0-py27-none-linux_x86_64-centos-Core.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/reworkdockerplugin-0.6.1-py27-none-linux_x86_64-centos-Core.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/cloudifydmaapplugin-1.0.0-py27-none-any-none-none.wgn' + - '{{ ONAPTEMPLATE_RAWREPOURL_org_onap_ccsdk }}/plugins/cloudifydmaapplugin-1.1.0-py27-none-any-none-none.wgn' +!EOF +# +# And away we go +# +cfy init -r +cfy bootstrap --install-plugins -p bootstrap-blueprint.yaml -i bootstrap-inputs.yaml +rm -f resources/ssl/server.key + +# Install Consul VM via a blueprint +cd $STARTDIR +mkdir consul +cd consul +cfy init -r +cfy use -t ${PUBIP} +echo "Deploying Consul VM" +# Get the blueprint for the Consul VM +wget -O consul.yaml ${CONSULBP} +cfy install -p consul.yaml -d consul -i ${INPUTS} -i "datacenter=$LOCATION" + +# Get the floating IP for one member of the cluster +# Needed for instructing the Consul agent on CM host to join the cluster +CONSULIP=$(cfy deployments outputs -d consul | grep -Po 'Value: \K.*') +echo Consul deployed at $CONSULIP + +# Wait for Consul API to come up +until curl http://$CONSULIP:8500/v1/agent/services +do + echo Waiting for Consul API + sleep 60 +done + +# Wait for a leader to be elected +until [[ "$(curl -Ss http://$CONSULIP:8500/v1/status/leader)" != '""' ]] +do + echo Waiting for leader + sleep 30 +done + +# Instruct the client-mode Consul agent running on the CM to join the cluster +curl http://$PUBIP:8500/v1/agent/join/$CONSULIP + +# Register Cloudify Manager in Consul via the local agent on CM host + +REGREQ=" +{ + \"Name\" : \"cloudify_manager\", + \"ID\" : \"cloudify_manager\", + \"Tags\" : [\"http://${PUBIP}/api/v2.1\"], + \"Address\": \"${PUBIP}\", + \"Port\": 80, + \"Check\" : { + \"Name\" : \"cloudify_manager_health\", + \"Interval\" : \"300s\", + \"HTTP\" : \"http://${PUBIP}/api/v2.1/status\", + \"Status\" : \"passing\", + \"DeregisterCriticalServiceAfter\" : \"30m\" + } +} +" + +curl -X PUT -H 'Content-Type: application/json' --data-binary "$REGREQ" http://$PUBIP:8500/v1/agent/service/register +# Make Consul address available to plugins on Cloudify Manager +# +# FURTHER REVIEW: This is probably no longer necessary. Components should register to the Consul agent on their local VM +# REVIEW: Replace Consul ip with fqdn of Consul that components can resolve. The referred fqdn is the +# Consul fqdn e.g. consul.service.consul which will return a list of Consul nodes. The ability to +# resolve the fqdn must be in place first. +# +# Methods to resolve: +# * Use Consul servers - All VMs spun up for the platform to have all the Consul server ips in the +# resolve.conf seems to be the most transparent approach +# * Use Consul clients that are connected to Consul servers - All VMs spun up for the platform would +# require a Consul agent in client mode which co-located components would use +# * Use Designate - Designate would need to direct requests to Consul for Consul names +ENVINI=$(mktemp) +cat <<!EOF > $ENVINI +[$LOCATION] +CONSUL_HOST=$CONSULIP +CONFIG_BINDING_SERVICE=config_binding_service +!EOF +scp $SSHOPTS -i $PVTKEY $ENVINI $SSHUSER@$PUBIP:/tmp/env.ini +ssh -t $SSHOPTS -i $PVTKEY $SSHUSER@$PUBIP sudo mv /tmp/env.ini /opt/env.ini +rm $ENVINI |