diff --git a/bin/crowbar_escm b/bin/crowbar_escm new file mode 100644 index 0000000000..ac0fb596f0 --- /dev/null +++ b/bin/crowbar_escm @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby +# +# Copyright 2017, SUSE LINUX GmbH +# +# 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. +# + +require File.join(File.expand_path(File.dirname(__FILE__)), "barclamp_lib") +@barclamp = "escm" +@timeout = 3600 + +main + diff --git a/chef/cookbooks/escm/README.md b/chef/cookbooks/escm/README.md new file mode 100644 index 0000000000..32c486aeee --- /dev/null +++ b/chef/cookbooks/escm/README.md @@ -0,0 +1 @@ +Chef Cookbook to install and configure ESCM \ No newline at end of file diff --git a/chef/cookbooks/escm/attributes/default.rb b/chef/cookbooks/escm/attributes/default.rb new file mode 100644 index 0000000000..031d4e257f --- /dev/null +++ b/chef/cookbooks/escm/attributes/default.rb @@ -0,0 +1,22 @@ +# +# Copyright 2017, SUSE LINUX GmbH +# +# 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. +# + +default[:escm][:proxy][:no_proxy_default] = "localhost,127.0.0.1" + +default[:escm][:ssl][:certfile] = "/etc/escm/ssl/certs/signing_cert.pem" +default[:escm][:ssl][:keyfile] = "/etc/escm/ssl/private/signing_key.pem" +default[:escm][:ssl][:generate_certs] = false +default[:escm][:ssl][:ca_certs] = "/etc/escm/ssl/certs/ca.pem" diff --git a/chef/cookbooks/escm/files/default/application.yaml b/chef/cookbooks/escm/files/default/application.yaml new file mode 100644 index 0000000000..f3d9e54ad7 --- /dev/null +++ b/chef/cookbooks/escm/files/default/application.yaml @@ -0,0 +1,261 @@ +# heat stack-create --poll -f application.yaml -P logs_volume_id=$logs_volume_id -P data_volume_id=$data_volume_id -P key_name=default -P flavor=d1.tiny escm +heat_template_version: 2015-10-15 + +description: | + # This is how you deploy the whole thing: + # 1) Instantiate volumes.yaml as follows + heat stack-create --poll -f volumes.yaml escm + + # 2) Retrieve outputs from escm: + logs_volume_id=$(heat output-show escm logs_volume_id | sed 's/"//g') + data_volume_id=$(heat output-show escm data_volume_id | sed 's/"//g') + + # 3) Create application stack: + heat stack-create --poll -f application.yaml -P logs_volume_id=$logs_volume_id -P data_volume_id=$data_volume_id -P key_name= escm + + + +parameters: + floating_network: + type: string + default: floating + description: Network to draw Floating IPs from + image: + type: string + default: sles12-sp1 + description: Glance image to use for server + flavor: + type: string + default: escm.medium + description: Nova flavor to use for server + key_name: + type: string + default: escm + description: Keypair name + logs_volume_id: + type: string + description: The Cinder volume for logs + data_volume_id: + type: string + description: The Cinder volume for data + ssh_cert: + default: "" + type: string + description: SSH key to add to servers' /root/.ssh/authorized_keys + wait_condition_timeout: + default: 1800 + type: number + +resources: + + wait_handle: + type: OS::Heat::WaitConditionHandle + + wait_condition: + type: OS::Heat::WaitCondition + depends_on: appserver + properties: + handle: { get_resource: wait_handle } + timeout: { get_param: wait_condition_timeout } + + db_password: + type: OS::Heat::RandomString + + key_secret: + type: OS::Heat::RandomString + + db_core_password: + type: OS::Heat::RandomString + + db_app_password: + type: OS::Heat::RandomString + + ### Network infrastructure ### + + escm_network: + type: OS::Neutron::Net + properties: + name: escm + + escm_subnet: + type: OS::Neutron::Subnet + properties: + cidr: 10.0.0.1/24 + name: escm + network: + get_resource: escm_network + + router: + type: OS::Neutron::Router + properties: + external_gateway_info: + network: + get_param: floating_network + + + router_interface: + type: OS::Neutron::RouterInterface + properties: + router: { get_resource: router } + subnet: { get_resource: escm_subnet } + + allow_inbound: + type: OS::Neutron::SecurityGroup + properties: + description: "Allow inbound SSH and HTTP traffic" + name: escm + rules: + - direction: ingress + remote_ip_prefix: 0.0.0.0/0 + protocol: tcp + ethertype: IPv4 + port_range_min: 22 + port_range_max: 22 + - direction: ingress + remote_ip_prefix: 0.0.0.0/0 + protocol: tcp + ethertype: IPv4 + port_range_min: 8081 + port_range_max: 8081 + - direction: ingress + remote_ip_prefix: 0.0.0.0/0 + protocol: tcp + ethertype: IPv4 + port_range_min: 8443 + port_range_max: 8443 + - direction: ingress + remote_ip_prefix: 0.0.0.0/0 + protocol: tcp + ethertype: IPv4 + port_range_min: 8543 + port_range_max: 8543 + - direction: ingress + remote_ip_prefix: 0.0.0.0/0 + protocol: tcp + ethertype: IPv4 + port_range_min: 8681 + port_range_max: 8681 + - direction: ingress + remote_ip_prefix: 0.0.0.0/0 + protocol: tcp + ethertype: IPv4 + port_range_min: 8881 + port_range_max: 8881 + - direction: egress + protocol: tcp + ethertype: IPv4 + - direction: egress + protocol: tcp + ethertype: IPv6 + - direction: egress + protocol: udp + ethertype: IPv4 + - direction: egress + protocol: udp + ethertype: IPv6 + - direction: egress + protocol: icmp + ethertype: IPv4 + - direction: egress + protocol: icmp + ethertype: IPv6 + + # Parameters that will be available to both user data scripts + user_data_params: + type: OS::Heat::SoftwareConfig + properties: + group: ungrouped + config: + str_replace: + template: {get_file: user-data/heat-config} + params: + $LOGS_VOLUME_DEV: + list_join: + - "" + - - "/dev/disk/by-id/virtio-" + - { get_param: logs_volume_id } + $DATA_VOLUME_DEV: + list_join: + - "" + - - "/dev/disk/by-id/virtio-" + - { get_param: data_volume_id } + $SSH_CERT: { get_param: ssh_cert } + $WAIT_CURL: { get_attr: [ wait_handle, curl_cli ] } + + # User data payload for appserver + userdata_appserver: + type: OS::Heat::MultipartMime + properties: + parts: + - config: {get_resource: user_data_params} + + ### Servers ### + + appserver: + type: OS::Nova::Server + properties: + name: appserver + config_drive: true + flavor: { get_param: flavor } + image: { get_param: image } + key_name: { get_param: key_name } + networks: + - port: { get_resource: port_appserver } + user_data_format: RAW + user_data: { get_resource: userdata_appserver } + + port_appserver: + type: OS::Neutron::Port + properties: + network: + get_resource: escm_network + security_groups: + - get_resource: allow_inbound + + ip_appserver: + type: OS::Neutron::FloatingIP + properties: + port_id: { get_resource: port_appserver } + floating_network: + get_param: floating_network + + logs_volume_attachment: + type: OS::Cinder::VolumeAttachment + properties: + instance_uuid: { get_resource: appserver } + volume_id: { get_param: logs_volume_id } + + data_volume_attachment: + type: OS::Cinder::VolumeAttachment + properties: + instance_uuid: { get_resource: appserver } + volume_id: { get_param: data_volume_id } + +outputs: + # Retrieval after stack creation (presuming stack is named `mystack`): + # heat output-show mystack ip_appserver + ip_appserver: + value: + get_attr: + - ip_appserver + - floating_ip_address + db_password: + value: + get_attr: + - db_password + - value + db_core_password: + value: + get_attr: + - db_core_password + - value + db_app_password: + value: + get_attr: + - db_app_password + - value + key_secret: + value: + get_attr: + - key_secret + - value diff --git a/chef/cookbooks/escm/files/default/user-data/deploy-escmserver b/chef/cookbooks/escm/files/default/user-data/deploy-escmserver new file mode 100644 index 0000000000..d8ea750bc3 --- /dev/null +++ b/chef/cookbooks/escm/files/default/user-data/deploy-escmserver @@ -0,0 +1,181 @@ +#!/bin/sh +# Enable command traces +set -x +# Exit on error +set -e + +# Variables for this script +CONFIG_BASE=/etc/escm +SSL_CONFIG_PATH=${CONFIG_BASE}/ssl +COMPOSE_CONFIG_PATH=${CONFIG_BASE}/docker-compose +DOCKER_PATH=/docker +UPDATE_NECESSARY_CONFIG=true +UPDATE_NECESSARY_CERTS=true + +# Redirect all output to log file +exec &>> ${DOCKER_PATH}/logs/setup-machine-$(date '+%Y-%m-%d').log + +echo "$(date '+%Y-%m-%d %H:%M:%S') starting setup..." + +# Check if update is necessary +if [ -f ${DOCKER_PATH}/var.env.old ]; then + if [ $(diff ${DOCKER_PATH}/var.env.old ${COMPOSE_CONFIG_PATH}/var.env | wc -l) == "0" ]; then + UPDATE_NECESSARY_CONFIG=false + fi +fi + +if [ -f ${DOCKER_PATH}/escm.key.old.sha512sum ] && [ -f ${DOCKER_PATH}/escm.crt.old.sha512sum ]; then + if sha512sum --status --ignore-missing -c ${DOCKER_PATH}/escm.key.old.sha512sum && sha512sum --status --ignore-missing -c ${DOCKER_PATH}/escm.crt.old.sha512sum; then + UPDATE_NECESSARY_CERTS=false + fi +fi + +if [ ${UPDATE_NECESSARY_CONFIG} == "false" ] && [ ${UPDATE_NECESSARY_CERTS} == "false" ]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') configuration not changed - aborting..." + exit 0 +fi + +# Enable automatic exporting of variables +set -a +# Read configuration files +source ${COMPOSE_CONFIG_PATH}/.env +source ${COMPOSE_CONFIG_PATH}/var.env +# Disable automatic exporting of variables +set +a + +# If mandatory variables are unset, abort +if [ -z ${DB_PWD_CORE} ] || [ -z ${DB_PWD_APP} ] || [ -z ${KEY_SECRET} ] || [ -z ${HOST_FQDN} ] || [ -z ${DB_SUPERPWD} ]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') Mandatory variables unset - aborting." + exit 0 +fi + +# If containers are running, stop them +if [ -f ${DOCKER_PATH}/docker-compose-oscm.yml ]; then + if [ $(docker-compose -f ${DOCKER_PATH}/docker-compose-oscm.yml ps -q | wc -l) != "0" ]; then + docker-compose -f ${DOCKER_PATH}/docker-compose-oscm.yml stop + docker-compose -f ${DOCKER_PATH}/docker-compose-oscm.yml rm -f + fi +fi + +# If http proxy is enabled, create Docker config file +if [ ${PROXY_ENABLED} == "true" ]; then + if [ ! -d /etc/systemd/system/docker.service.d ]; then + mkdir -p /etc/systemd/system/docker.service.d + fi + if [ ${PROXY_AUTH} == "true" ]; then + cat < /etc/systemd/system/docker.service.d/http-proxy.conf +[Service] +Environment="HTTP_PROXY=http://${PROXY_USER}:${PROXY_PWD}@${PROXY_HTTP_HOST}:${PROXY_HTTP_PORT}/" "HTTPS_PROXY=http://${PROXY_USER}:${PROXY_PWD}@${PROXY_HTTPS_HOST}:${PROXY_HTTPS_PORT}/" "NO_PROXY=${PROXY_NOPROXY}" +EOF + else + cat < /etc/systemd/system/docker.service.d/http-proxy.conf +[Service] +Environment="HTTP_PROXY=http://${PROXY_HTTP_HOST}:${PROXY_HTTP_PORT}/" "HTTPS_PROXY=http://${PROXY_HTTPS_HOST}:${PROXY_HTTPS_PORT}/" "NO_PROXY=${PROXY_NOPROXY}" +EOF + fi + systemctl daemon-reload + systemctl restart docker +# Otherwise remove Docker config file with proxy config +else + if [ -f /etc/systemd/system/docker.service.d/http-proxy.conf ]; then + rm -f /etc/systemd/system/docker.service.d/http-proxy.conf + systemctl daemon-reload + systemctl restart docker + fi +fi + +# If Docker registry authentication is enabled, create auth info file +if [ ${DOCKER_REGISTRY_AUTH} == "true" ]; then + #Create auth file for Docker registry + REGISTRY_USER_PASS_BASE64=$(printf "${DOCKER_REGISTRY_USER}:${DOCKER_REGISTRY_PWD}" | base64) + mkdir -p /root/.docker + cat < /root/.docker/config.json +{ + "auths": { + "${DOCKER_REGISTRY_HOST}:${DOCKER_REGISTRY_PORT}": { + "auth": "${REGISTRY_USER_PASS_BASE64}" + } + } +} +EOF +# Otherwise remove auth info file +else + if [ -f /root/.docker/config.json ]; then + rm -f /root/.docker/config.json + fi +fi + +# If default Docker registry (Dockerhub) is used, remove insecure registry config +if [ ${DOCKER_REGISTRY_DOCKERHUB} = "true" ]; then + DOCKER_IMAGES_SOURCE="${DOCKER_REGISTRY_ORGANIZATION}/" + if [ -f /etc/docker/daemon.json ]; then + rm -f /etc/docker/daemon.json + systemctl restart docker + fi +# Otherwise, custom registry is used, so create insecure registry config +else + cat < /etc/docker/daemon.json +{ + "insecure-registries" : ["${DOCKER_REGISTRY_HOST}:${DOCKER_REGISTRY_PORT}"] +} +EOF + systemctl restart docker +fi + +# Create rsyslog configuration for Docker log files +if [ ! -f /etc/rsyslog.d/escm.conf ]; then + sed -i '/\/var\/log\/messages$/d' /etc/rsyslog.conf + cat < /etc/rsyslog.d/escm.conf +local0.* /docker/logs/oscm-db/oscm-db.out.log +local1.* /docker/logs/oscm-core/oscm-core.out.log +local2.* /docker/logs/oscm-app/oscm-app.out.log +local3.* /docker/logs/oscm-birt/oscm-birt.out.log +local4.* /docker/logs/oscm-branding/oscm-branding.out.log +local5.* /docker/logs/oscm-help/oscm-help.out.log +*.*;mail.none;news.none;local0.none;local1.none;local2.none;local3.none;local4.none;local5.none;local6.none;local7.none -/var/log/messages +EOF + sed -i '/^local/d' /etc/rsyslog.conf + systemctl restart rsyslog +fi + +# Copy environment and configuration files to Docker directory +if [ -f ${COMPOSE_CONFIG_PATH}/.env ]; then + cp ${COMPOSE_CONFIG_PATH}/.env ${DOCKER_PATH} +fi +if [ -f ${COMPOSE_CONFIG_PATH}/var.env ]; then + cp ${COMPOSE_CONFIG_PATH}/var.env ${DOCKER_PATH} +fi + +# Create Docker directory structure and Docker Compose files +pushd ${DOCKER_PATH} +docker run --name deployer-directories-compose --rm -v ${DOCKER_PATH}:/target ${IMAGE_DEPLOYER} + +# Copy certificate files +# and save the hashes of the current certificate files for update check by the next run +if [ -f ${SSL_CONFIG_PATH}/escm.key ]; then + for dir_privkey in ${DOCKER_PATH}/config/oscm-*; do + cp -f ${SSL_CONFIG_PATH}/escm.key ${dir_privkey}/ssl/privkey + done + sha512sum ${SSL_CONFIG_PATH}/escm.key > ${DOCKER_PATH}/escm.key.old.sha512sum +fi +if [ -f ${SSL_CONFIG_PATH}/escm.crt ]; then + for dir_privkey in ${DOCKER_PATH}/config/oscm-*; do + cp -f ${SSL_CONFIG_PATH}/escm.crt ${dir_privkey}/ssl/cert + done + cp -f ${SSL_CONFIG_PATH}/escm.crt ${DOCKER_PATH}/config/certs + sha512sum ${SSL_CONFIG_PATH}/escm.crt > ${DOCKER_PATH}/escm.crt.old.sha512sum +fi +if [ -f ${SSL_CONFIG_PATH}/escm.chain ]; then + for dir_privkey in ${DOCKER_PATH}/config/oscm-*; do + cp -f ${SSL_CONFIG_PATH}/escm.chain ${dir_privkey}/ssl/chain + sha512sum ${SSL_CONFIG_PATH}/escm.chain > ${DOCKER_PATH}/escm.chain.old.sha512sum + done +fi + +# Initialize the databases and start the application containers +docker run --name deployer-init-start --rm -v ${DOCKER_PATH}:/target -v /var/run/docker.sock:/var/run/docker.sock -e SYSLOG=true -e INITDB=true -e STARTUP=true ${IMAGE_DEPLOYER} + +# Backup the current configuration for update check by the next run +cp ${DOCKER_PATH}/var.env ${DOCKER_PATH}/var.env.old + +echo "$(date '+%Y-%m-%d %H:%M:%S') setup finished." diff --git a/chef/cookbooks/escm/files/default/user-data/heat-config b/chef/cookbooks/escm/files/default/user-data/heat-config new file mode 100644 index 0000000000..5b68a800fe --- /dev/null +++ b/chef/cookbooks/escm/files/default/user-data/heat-config @@ -0,0 +1,71 @@ +#!/bin/sh +# Enable command traces +set -x +# Exit on error +set -e +# Redirect all output to log file +exec &> /var/log/setup-cloud.log + +# Variables for this script +DOCKER_PATH=/docker + +# Create the config directory if it does not exist yet +if [ ! -d /etc/escm/config ]; then + mkdir -p /etc/escm/config +fi + +# Write the SSH public key to root's trusted keys file +CERT_STR="$SSH_CERT" +echo $CERT_STR >> /root/.ssh/authorized_keys + +# Set up Cinder storage +# The Cinder volume ids are truncated to 27 characters when the device +# link in /dev/disk/by-id/ is created. Account for this by truncating the +# device name accordingly. +volume_dev_logs=$(printf '%.43s\n' $LOGS_VOLUME_DEV) +volume_dev_data=$(printf '%.43s\n' $DATA_VOLUME_DEV) + +# Create a file system on the Cinder volumes +if ! file -Ls ${volume_dev_logs} | grep -q "filesystem data" ; then + mkfs.ext4 "${volume_dev_logs}" +fi + +if ! file -Ls ${volume_dev_data} | grep -q "filesystem data" ; then + mkfs.ext4 "${volume_dev_data}" +fi + +# Create fstab entries +if ! grep -qs "${volume_dev_logs}" /etc/fstab; then + echo "${volume_dev_logs} ${DOCKER_PATH}/logs ext4 defaults 1 1" >> /etc/fstab +fi + +if ! grep -qs "${volume_dev_data}" /etc/fstab; then + echo "${volume_dev_data} ${DOCKER_PATH}/data ext4 defaults 1 1" >> /etc/fstab +fi + +# Mount the Cinder volumes if they are not mounted yet +if ! grep -qs "${DOCKER_PATH}/logs" /proc/mounts; then + if [ ! -d ${DOCKER_PATH}/logs ]; then + mkdir -p ${DOCKER_PATH}/logs + fi + mount ${volume_dev_logs} +fi + +if ! grep -qs "${DOCKER_PATH}/data" /proc/mounts; then + if [ ! -d ${DOCKER_PATH}/data ]; then + mkdir -p ${DOCKER_PATH}/data + fi + mount ${volume_dev_data} +fi + +if [ $(grep SwapTotal /proc/meminfo | awk '{ print $2 }') -eq 0 ]; then + dd if=/dev/zero of=${DOCKER_PATH}/data/swapfile bs=1G count=1 + chmod 600 ${DOCKER_PATH}/data/swapfile + mkswap -f ${DOCKER_PATH}/data/swapfile + echo "${DOCKER_PATH}/data/swapfile swap swap defaults 0 0" + swapon ${DOCKER_PATH}/data/swapfile +fi + +# Signal to OpenStack that we're finished and ready +WAIT_CURL_FULL="$WAIT_CURL --data-binary '{\"status\": \"SUCCESS\"}' --noproxy '*'" +eval ${WAIT_CURL_FULL} diff --git a/chef/cookbooks/escm/files/default/volumes.yaml b/chef/cookbooks/escm/files/default/volumes.yaml new file mode 100644 index 0000000000..8ddd8abd92 --- /dev/null +++ b/chef/cookbooks/escm/files/default/volumes.yaml @@ -0,0 +1,47 @@ +# Example invocation: heat stack-create --poll -f volumes.yaml escm +heat_template_version: 2015-10-15 + + +parameters: + logs_size: + type: number + default: 2 + description: Size of the logs volume in gigabytes + data_size: + type: number + default: 2 + description: Size of the data volume in gigabytes + + +resources: + + logs_volume: + type: OS::Cinder::Volume + properties: + name: + list_join: + - "_" + - - { get_param: 'OS::stack_name' } + - logs_volume + size: { get_param: logs_size } + + data_volume: + type: OS::Cinder::Volume + properties: + name: + list_join: + - "_" + - - { get_param: 'OS::stack_name' } + - data_volume + size: { get_param: data_size } + +outputs: + # Retrieval after stack creation (presuming stack is named `escm`): + # heat output-show escm logs_volume_id + logs_volume_id: + value: { get_resource: logs_volume } + + # Retrieval after stack creation (presuming stack is named `escm`): + # heat output-show escm data_volume_id + data_volume_id: + value: { get_resource: data_volume } diff --git a/chef/cookbooks/escm/metadata.rb b/chef/cookbooks/escm/metadata.rb new file mode 100644 index 0000000000..612eb99b33 --- /dev/null +++ b/chef/cookbooks/escm/metadata.rb @@ -0,0 +1,9 @@ +name "escm" +maintainer "EST" +maintainer_email "arkadiusz.kowalczyk@ts.fujistu.com" +license "Apache 2.0" +description "Installs/Configures ESCM" +long_description IO.read(File.join(File.dirname(__FILE__), "README.md")) +version "0.1" + +depends "heat" diff --git a/chef/cookbooks/escm/recipes/role_escm_server.rb b/chef/cookbooks/escm/recipes/role_escm_server.rb new file mode 100644 index 0000000000..f334e59351 --- /dev/null +++ b/chef/cookbooks/escm/recipes/role_escm_server.rb @@ -0,0 +1,3 @@ +if CrowbarRoleRecipe.node_state_valid_for_role?(node, "escm", "escm-server") + include_recipe "#{@cookbook_name}::server" +end diff --git a/chef/cookbooks/escm/recipes/server.rb b/chef/cookbooks/escm/recipes/server.rb new file mode 100644 index 0000000000..cfbd55fd71 --- /dev/null +++ b/chef/cookbooks/escm/recipes/server.rb @@ -0,0 +1,363 @@ +# +# Copyright 2017, SUSE LINUX GmbH +# +# 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. +# + +escm_project = node[:escm][:keystone][:project] +escm_user = node[:escm][:keystone][:user] +escm_password = node[:escm][:keystone][:password] +escm_ssl_certfile = node[:escm][:ssl][:certfile] +escm_ssl_keyfile = node[:escm][:ssl][:keyfile] +escm_ssl_cacerts = node[:escm][:ssl][:ca_certs] +escm_flavor_name = node[:escm][:openstack][:flavor][:name] +escm_flavor_ram = node[:escm][:openstack][:flavor][:ram] +escm_flavor_vcpus = node[:escm][:openstack][:flavor][:vcpus] +escm_flavor_disk = node[:escm][:openstack][:flavor][:disk] +escm_keypair_name = node[:escm][:openstack][:keypair][:name] +escm_keypair_publickey = node[:escm][:openstack][:keypair][:publickey] +escm_keypair_publickeyfile = "/etc/escm/install/openstack_keypair_public.pem" +escm_install_path = "/etc/escm/install" +escm_path = "/etc/escm" +escm_volumestack_name = node[:escm][:openstack][:volume_stack][:stack_name] +escm_instancestack_name = node[:escm][:openstack][:instance_stack][:stack_name] +escm_data_volume_size = node[:escm][:openstack][:volume_stack][:data_volume_size] +escm_logs_volume_size = node[:escm][:openstack][:volume_stack][:logs_volume_size] +escm_image = node[:escm][:openstack][:image] +escm_floating_network = node[:escm][:openstack][:floating_network] +escm_keypair_crowbar_sshkey = "/etc/escm/install/escm_ssh.key" +escm_group = "root" + +keystone_settings = KeystoneHelper.keystone_settings(node, @cookbook_name) + +env = "OS_USERNAME='#{escm_user}' " +env << "OS_PASSWORD='#{escm_password}' " +env << "OS_PROJECT_NAME='#{escm_project}' " +env << "OS_AUTH_URL='#{keystone_settings["internal_auth_url"]}' " +env << "OS_INTERFACE=internal " +env << "OS_IDENTITY_API_VERSION='#{keystone_settings["api_version"]}' " +env << "OS_USER_DOMAIN_NAME='Default' " +env << "OS_PROJECT_DOMAIN_NAME='Default'" + +openstack_cmd = "#{env} openstack" + +openstack_args_keystone = keystone_settings["insecure"] ? "--insecure" : "" + +nova_config = Barclamp::Config.load("openstack", "nova", node[:escm][:nova_instance]) +nova_insecure = CrowbarOpenStackHelper.insecure(nova_config) +openstack_args_nova = nova_insecure || keystone_settings["insecure"] ? "--insecure" : "" + +heat_config = Barclamp::Config.load("openstack", "heat", node[:escm][:heat_instance]) +heat_insecure = CrowbarOpenStackHelper.insecure(heat_config) +openstack_args_heat = heat_insecure || keystone_settings["insecure"] ? "--insecure" : "" + +register_auth_hash = { + user: keystone_settings["admin_user"], + password: keystone_settings["admin_password"], + tenant: keystone_settings["admin_tenant"] +} + +keystone_register "escm wakeup keystone" do + protocol keystone_settings["protocol"] + insecure keystone_settings["insecure"] + host keystone_settings["internal_url_host"] + port keystone_settings["admin_port"] + auth register_auth_hash + action :wakeup +end + +keystone_register "escm create project" do + protocol keystone_settings["protocol"] + insecure keystone_settings["insecure"] + host keystone_settings["internal_url_host"] + port keystone_settings["admin_port"] + auth register_auth_hash + tenant_name escm_project + action :add_tenant +end + +keystone_register "escm register user" do + protocol keystone_settings["protocol"] + insecure keystone_settings["insecure"] + host keystone_settings["internal_url_host"] + port keystone_settings["admin_port"] + auth register_auth_hash + user_name escm_user + user_password escm_password + tenant_name escm_project + action :add_user +end + +keystone_register "escm give user admin role" do + protocol keystone_settings["protocol"] + insecure keystone_settings["insecure"] + host keystone_settings["internal_url_host"] + port keystone_settings["admin_port"] + auth register_auth_hash + user_name escm_user + tenant_name escm_project + role_name "admin" + action :add_access +end + +keystone_register "escm give user member role" do + protocol keystone_settings["protocol"] + insecure keystone_settings["insecure"] + host keystone_settings["internal_url_host"] + port keystone_settings["admin_port"] + auth register_auth_hash + user_name escm_user + tenant_name escm_project + role_name "Member" + action :add_access +end + +keystone_register "escm give user _member_ role" do + protocol keystone_settings["protocol"] + insecure keystone_settings["insecure"] + host keystone_settings["internal_url_host"] + port keystone_settings["admin_port"] + auth register_auth_hash + user_name escm_user + tenant_name escm_project + role_name "_member_" + action :add_access +end + +ruby_block "check_escm_glance_image" do + block do + Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut) + command = "#{openstack_cmd} #{openstack_args_heat} image list -c Name -f value | egrep '^#{escm_image}$'" + command_out = shell_out(command) + if command_out.stdout.strip != escm_image + message = "The image with name '#{escm_image}' is not found in glance! Please check your escm proposal attributes or glance image registry." + raise message + end + end + action :create +end + +execute "create_escm_flavor" do + command "#{openstack_cmd} #{openstack_args_nova} flavor create --ram #{escm_flavor_ram} --disk #{escm_flavor_disk} \ + --vcpus #{escm_flavor_vcpus} --private #{escm_flavor_name}" + not_if "#{openstack_cmd} #{openstack_args_nova} flavor list --all -c Name -f value | egrep -q '^#{escm_flavor_name}$'" +end + +execute "create_escm_flavor_access" do + command "#{openstack_cmd} #{openstack_args_nova} flavor set --project #{escm_project} #{escm_flavor_name}" + ignore_failure true +end + +bash "create_escm_keypair_file" do + code <<-EOH + publickey="#{escm_keypair_publickey}" + mkdir -p $(dirname #{escm_keypair_publickeyfile}) + echo "${publickey}" > "#{escm_keypair_publickeyfile}" +EOH +end + +execute "create_escm_keypair" do + command "#{openstack_cmd} #{openstack_args_nova} keypair create #{escm_keypair_name} --public-key #{escm_keypair_publickeyfile}" + not_if "#{openstack_cmd} #{openstack_args_nova} keypair list -c Name -f value | egrep -q '^#{escm_keypair_name}$'" +end + +directory "#{escm_install_path}" do + owner escm_group + group escm_group + mode 0640 + recursive true +end + +cookbook_file "#{escm_install_path}/volumes.yaml" do + source "volumes.yaml" + owner escm_group + group escm_group + mode 0640 + action :create +end + +cookbook_file "#{escm_install_path}/application.yaml" do + source "application.yaml" + owner escm_group + group escm_group + mode 0640 + action :create +end + +directory "#{escm_install_path}/user-data" do + owner escm_group + group escm_group + mode 0640 + recursive true +end + +cookbook_file "#{escm_install_path}/user-data/heat-config" do + source "user-data/heat-config" + owner escm_group + group escm_group + mode 0640 + action :create +end + +cookbook_file "#{escm_install_path}/user-data/deploy-escmserver" do + source "user-data/deploy-escmserver" + owner escm_group + group escm_group + mode 0640 + action :create +end + +execute "create_escm_volume_stack" do + command "#{openstack_cmd} #{openstack_args_heat} stack create --parameter data_size=#{escm_data_volume_size} --parameter logs_size=#{escm_logs_volume_size} \ + -t #{escm_install_path}/volumes.yaml --wait #{escm_volumestack_name}" + not_if "#{openstack_cmd} #{openstack_args_heat} stack list -c 'Stack Name' -f value | egrep -q '^#{escm_volumestack_name}$'" +end + +ruby_block "get_escm_volume_ids" do + block do + Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut) + command = "#{openstack_cmd} #{openstack_args_heat} stack output show -f shell #{escm_volumestack_name} data_volume_id | grep -Po '(?<=^output_value=\")[^\"]*'" + command_out = shell_out(command) + node[:escm][:openstack][:volume_stack][:data_volume_id] = command_out.stdout.strip + command = "#{openstack_cmd} #{openstack_args_heat} stack output show -f shell #{escm_volumestack_name} logs_volume_id | grep -Po '(?<=^output_value=\")[^\"]*'" + command_out = shell_out(command) + node[:escm][:openstack][:volume_stack][:logs_volume_id] = command_out.stdout.strip + end + action :create +end + +ruby_block "generate_escm_crowbar_ssh_keys" do + block do + Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut) + command = "mkdir -p '$(dirname #{escm_keypair_crowbar_sshkey})'" + command_out = shell_out(command) + command = "[ ! -f #{escm_keypair_crowbar_sshkey} ] && yes y | ssh-keygen -t rsa -f #{escm_keypair_crowbar_sshkey} -N ''" + command_out = shell_out(command) + end + action :create +end + +execute "create_escm_instance_stack" do + command lazy { "#{openstack_cmd} #{openstack_args_heat} stack create --parameter logs_volume_id=#{node[:escm][:openstack][:volume_stack][:logs_volume_id]} \ + --parameter data_volume_id=#{node[:escm][:openstack][:volume_stack][:data_volume_id]} \ + --parameter image=#{escm_image} --parameter flavor=#{escm_flavor_name} \ + --parameter key_name=#{escm_keypair_name} --parameter floating_network=#{escm_floating_network} \ + --parameter-file ssh_cert=#{escm_keypair_crowbar_sshkey}.pub \ + -t #{escm_install_path}/application.yaml --wait #{escm_instancestack_name}" } + not_if "#{openstack_cmd} #{openstack_args_heat} stack list -c 'Stack Name' -f value | egrep -q '^#{escm_instancestack_name}$'" +end + +ruby_block "get_escm_floating_ip" do + block do + Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut) + command = "#{openstack_cmd} #{openstack_args_heat} stack output show -f shell --variable output_value #{escm_instancestack_name} ip_appserver | grep -Po '(?<=^output_value=\")[^\"]*'" + command_out = shell_out(command) + node[:escm][:openstack][:instance_stack][:ip_appserver] = command_out.stdout.strip + end + action :create +end + +if node[:escm][:api][:protocol] == "https" + ssl_setup "setting up ssl for escm" do + generate_certs node[:escm][:ssl][:generate_certs] + certfile node[:escm][:ssl][:certfile] + keyfile node[:escm][:ssl][:keyfile] + group escm_group + fqdn lazy { node[:escm][:ssl][:fqdn].empty? ? node[:escm][:openstack][:instance_stack][:ip_appserver] : node[:escm][:ssl][:fqdn] } + ca_certs node[:escm][:ssl][:ca_certs] + end +end + +ruby_block "get_escm_secrets" do + block do + Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut) + command = "#{openstack_cmd} #{openstack_args_heat} stack output show -f shell --variable output_value #{escm_instancestack_name} db_password | grep -Po '(?<=^output_value=\")[^\"]*'" + command_out = shell_out(command) + node[:escm][:openstack][:instance_stack][:db_password] = command_out.stdout.strip + command = "#{openstack_cmd} #{openstack_args_heat} stack output show -f shell --variable output_value #{escm_instancestack_name} db_core_password | grep -Po '(?<=^output_value=\")[^\"]*'" + command_out = shell_out(command) + node[:escm][:openstack][:instance_stack][:db_core_password] = command_out.stdout.strip + command = "#{openstack_cmd} #{openstack_args_heat} stack output show -f shell --variable output_value #{escm_instancestack_name} db_app_password | grep -Po '(?<=^output_value=\")[^\"]*'" + command_out = shell_out(command) + node[:escm][:openstack][:instance_stack][:db_app_password] = command_out.stdout.strip + command = "#{openstack_cmd} #{openstack_args_heat} stack output show -f shell --variable output_value #{escm_instancestack_name} key_secret | grep -Po '(?<=^output_value=\")[^\"]*'" + command_out = shell_out(command) + node[:escm][:openstack][:instance_stack][:key_secret] = command_out.stdout.strip + end + action :create +end + +var_no_proxy = node[:escm][:proxy][:no_proxy].empty? ? "#{node[:escm][:proxy][:no_proxy_default]},#{node[:escm][:openstack][:instance_stack][:ip_appserver]}" : "#{node[:escm][:proxy][:no_proxy_default]},#{node[:escm][:openstack][:instance_stack][:ip_appserver]},#{node[:escm][:proxy][:no_proxy]}" +var_key_secret = "#{node[:escm][:openstack][:instance_stack][:key_secret]}" +var_host_fqdn = node[:escm][:ssl][:fqdn].empty? ? "#{node[:escm][:openstack][:instance_stack][:ip_appserver]}" : "#{node[:escm][:ssl][:fqdn]}" +var_db_pwd_core = "#{node[:escm][:openstack][:instance_stack][:db_core_password]}" +var_db_pwd_app = "#{node[:escm][:openstack][:instance_stack][:db_app_password]}" +var_db_superpwd = "#{node[:escm][:openstack][:instance_stack][:db_password]}" + +template "#{escm_install_path}/var.env" do + source "var.env.erb" + owner escm_group + group escm_group + mode 0640 + variables( + mail: node[:escm][:mail], + docker: node[:escm][:docker], + proxy: node[:escm][:proxy], + no_proxy: var_no_proxy, + key_secret: var_key_secret, + host_fqdn: var_host_fqdn, + db_pwd_core: var_db_pwd_core, + db_pwd_app: var_db_pwd_app, + db_superpwd: var_db_superpwd + ) +end + +template "#{escm_install_path}/.env" do + source ".env.erb" + owner escm_group + group escm_group + mode 0640 + variables( + docker: node[:escm][:docker] + ) +end + +ruby_block "inject_escm_scripts" do + block do + args = "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i #{escm_keypair_crowbar_sshkey}" + ip_appserver = node[:escm][:openstack][:instance_stack][:ip_appserver] + Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut) + command = "ssh #{args} #{ip_appserver} 'mkdir -p #{escm_path}/docker-compose'" + command_out = shell_out(command) + command = "scp #{args} #{escm_install_path}/var.env #{ip_appserver}:#{escm_path}/docker-compose" + command_out = shell_out(command) + command = "scp #{args} #{escm_install_path}/.env #{ip_appserver}:#{escm_path}/docker-compose" + command_out = shell_out(command) + if node[:escm][:api][:protocol] == "https" + command = "ssh #{args} #{ip_appserver} 'mkdir -p #{escm_path}/ssl'" + command_out = shell_out(command) + command = "scp #{args} #{escm_ssl_certfile} #{ip_appserver}:#{escm_path}/ssl/escm.crt" + command_out = shell_out(command) + command = "scp #{args} #{escm_ssl_keyfile} #{ip_appserver}:#{escm_path}/ssl/escm.key" + command_out = shell_out(command) + command = "scp #{args} #{escm_ssl_cacerts} #{ip_appserver}:#{escm_path}/ssl/escm.chain" + end + command = "scp #{args} #{escm_install_path}/user-data/deploy-escmserver #{ip_appserver}:#{escm_path}/config/" + command_out = shell_out(command) + command = "ssh #{args} #{ip_appserver} 'chmod 755 #{escm_path}/config/deploy-escmserver'" + command_out = shell_out(command) + command = "ssh #{args} #{ip_appserver} '#{escm_path}/config/deploy-escmserver' &" + command_out = shell_out(command) + end + action :create +end diff --git a/chef/cookbooks/escm/templates/default/.env.erb b/chef/cookbooks/escm/templates/default/.env.erb new file mode 100644 index 0000000000..ade4cb718c --- /dev/null +++ b/chef/cookbooks/escm/templates/default/.env.erb @@ -0,0 +1,47 @@ +<% if @docker["dockerhub"] == true %> +IMAGE_DB=<%= @docker["organization"]+"/oscm-db:"+@docker["tag"] %> +<% else %> +IMAGE_DB=<%= @docker["host"]+":"+@docker["port"].to_s+"/"+@docker["organization"]+"/oscm-db:"+@docker["tag"] %> +<% end %> +<% if @docker["dockerhub"] == true %> +IMAGE_CORE=<%= @docker["organization"]+"/oscm-core:"+@docker["tag"] %> +<% else %> +IMAGE_CORE=<%= @docker["host"]+":"+@docker["port"].to_s+"/"+@docker["organization"]+"/oscm-core:"+@docker["tag"] %> +<% end %> +<% if @docker["dockerhub"] == true %> +IMAGE_APP=<%= @docker["organization"]+"/oscm-app:"+@docker["tag"] %> +<% else %> +IMAGE_APP=<%= @docker["host"]+":"+@docker["port"].to_s+"/"+@docker["organization"]+"/oscm-app:"+@docker["tag"] %> +<% end %> +<% if @docker["dockerhub"] == true %> +IMAGE_BIRT=<%= @docker["organization"]+"/oscm-birt:"+@docker["tag"] %> +<% else %> +IMAGE_BIRT=<%= @docker["host"]+":"+@docker["port"].to_s+"/"+@docker["organization"]+"/oscm-birt:"+@docker["tag"] %> +<% end %> +<% if @docker["dockerhub"] == true %> +IMAGE_BRANDING=<%= @docker["organization"]+"/oscm-branding:"+@docker["tag"] %> +<% else %> +IMAGE_BRANDING=<%= @docker["host"]+":"+@docker["port"].to_s+"/"+@docker["organization"]+"/oscm-branding:"+@docker["tag"] %> +<% end %> +<% if @docker["dockerhub"] == true %> +IMAGE_INITDB=<%= @docker["organization"]+"/oscm-initdb:"+@docker["tag"] %> +<% else %> +IMAGE_INITDB=<%= @docker["host"]+":"+@docker["port"].to_s+"/"+@docker["organization"]+"/oscm-initdb:"+@docker["tag"] %> +<% end %> +<% if @docker["dockerhub"] == true %> +IMAGE_PROXY=<%= @docker["organization"]+"/oscm-proxy:"+@docker["tag"] %> +<% else %> +IMAGE_PROXY=<%= @docker["host"]+":"+@docker["port"].to_s+"/"+@docker["organization"]+"/oscm-proxy:"+@docker["tag"] %> +<% end %> +<% if @docker["dockerhub"] == true %> +IMAGE_HELP=<%= @docker["organization"]+"/oscm-help:"+@docker["tag"] %> +<% else %> +IMAGE_HELP=<%= @docker["host"]+":"+@docker["port"].to_s+"/"+@docker["organization"]+"/oscm-help:"+@docker["tag"] %> +<% end %> +<% if @docker["dockerhub"] == true %> +IMAGE_DEPLOYER=<%= @docker["organization"]+"/oscm-deployer:"+@docker["tag"] %> +<% else %> +IMAGE_DEPLOYER=<%= @docker["host"]+":"+@docker["port"].to_s+"/"+@docker["organization"]+"/oscm-deployer:"+@docker["tag"] %> +<% end %> + +DOCKER_PATH=/docker diff --git a/chef/cookbooks/escm/templates/default/var.env.erb b/chef/cookbooks/escm/templates/default/var.env.erb new file mode 100644 index 0000000000..9c6129444f --- /dev/null +++ b/chef/cookbooks/escm/templates/default/var.env.erb @@ -0,0 +1,98 @@ +# Version: v17.5.0 +# Please adjust _all_ of the ${PLACEHOLDERS} in order for the application +# to work correctly. + +##################### +# Database settings # +##################### +# The ports of the PostgreSQL databases +# Please set to 5432 +DB_PORT_CORE=5432 +DB_PORT_JMS=5432 +DB_PORT_APP=5432 +# Database password for the application core database +DB_PWD_CORE=<%= @db_pwd_core %> +# Database password for the Asynchronous Provisioning Platform (APP) database +DB_PWD_APP=<%= @db_pwd_app %> +# Database superuser (postgres) password +DB_SUPERPWD=<%= @db_superpwd %> + +################# +# Mail settings # +################# +# The host name or IP address of your mail server +SMTP_HOST=<%= @mail["host"] %> +# The port of your mail server +SMTP_PORT=<%= @mail["port"] %> +# The sender email address that OSCM should use +SMTP_FROM=<%= @mail["from"] %> +# The user name for your mail server if it requires authentication; if no +# authentication is required, please set none +SMTP_USER=<%= @mail["user"] %> +# The password for your mail server if it requires authentication; if no +# authentication is required, please set none +SMTP_PWD=<%= @mail["password"] %> +# Whether your mail server requires authentication; can be true or false +SMTP_AUTH=<%= @mail["auth"] %> +# Whether to use TLS for mail server communication; can be true or false +SMTP_TLS=<%= @mail["tls"] %> +# The sender email address that the Asynchronous Provisioning Platform (APP) +# should use +APP_ADMIN_MAIL_ADDRESS=<%= @mail["from"] %> + +####################### +# Controller settings # +####################### +# The ID of the controller to be configured +CONTROLLER_ID=ess.openstack +# Organization ID for controller authentication +# Please set to PLATFORM_OPERATOR +CONTROLLER_ORG_ID=PLATFORM_OPERATOR +# Numerical user key of the controller administrator +# Please set to 1000 +CONTROLLER_USER_KEY=1000 +# User name of the controller administrator +# Please set to administrator +CONTROLLER_USER_NAME=administrator +# Password of the controller administrator +# Please set to admin123 +CONTROLLER_USER_PASS=admin123 + +################# +# Misc settings # +################# +# A secret string which will be used as a seed for encryption in the database +# Please do not lose this if you plan to keep your database +KEY_SECRET=<%= @key_secret %> +# The host name or IP address which you will use to access the application +HOST_FQDN=<%= @host_fqdn %> +# URL for the Report Engine +# Replace HOST_FQDN with the same value as above; please leave the other +# placeholders intact +REPORT_ENGINEURL=https://<%= @host_fqdn %>:8681/birt/frameset?__report=${reportname}.rptdesign&SessionId=${sessionid}&__locale=${locale}&WSDLURL=${wsdlurl}&SOAPEndPoint=${soapendpoint}&wsname=Report&wsport=ReportPort +# Debug logs; can be true or false +TOMEE_DEBUG=false + +################ +# SOC settings # +################ +# Proxy +PROXY_ENABLED=<%= @proxy["use_proxy"] %> +PROXY_HTTP_HOST=<%= @proxy["http_host"] %> +PROXY_HTTP_PORT=<%= @proxy["http_port"] %> +PROXY_HTTPS_HOST=<%= @proxy["https_host"] %> +PROXY_HTTPS_PORT=<%= @proxy["https_port"] %> +PROXY_NOPROXY=<%= @no_proxy %> +PROXY_AUTH=<%= @proxy["auth"] %> +PROXY_USER=<%= @proxy["user"] %> +PROXY_PWD=<%= @proxy["password"] %> + +# Docker +DOCKER_REGISTRY_DOCKERHUB=<%= @docker["dockerhub"] %> +DOCKER_REGISTRY_HOST=<%= @docker["host"] %> +DOCKER_REGISTRY_PORT=<%= @docker["port"] %> +DOCKER_REGISTRY_ORGANIZATION=<%= @docker["organization"] %> +DOCKER_REGISTRY_AUTH=<%= @docker["auth"] %> +DOCKER_REGISTRY_USER=<%= @docker["user"] %> +DOCKER_REGISTRY_PWD=<%= @docker["password"] %> +DOCKER_TAG=<%= @docker["tag"] %> diff --git a/chef/data_bags/crowbar/template-escm.json b/chef/data_bags/crowbar/template-escm.json new file mode 100644 index 0000000000..df34035aec --- /dev/null +++ b/chef/data_bags/crowbar/template-escm.json @@ -0,0 +1,103 @@ +{ + "id": "template-escm", + "description": "ESCM", + "attributes": { + "escm": { + "timeout": 300, + "debug": false, + "keystone_instance": "none", + "nova_instance": "none", + "heat_instance": "none", + "keystone": { + "project": "escm", + "user": "escm", + "password": "escm" + }, + "openstack": { + "image": "sles12-sp3", + "flavor": { + "name": "escm.small", + "ram": 8192, + "vcpus": 4, + "disk": 20 + }, + "keypair": { + "name": "escm", + "publickey": "" + }, + "volume_stack": { + "stack_name": "escm-volumes", + "data_volume_size": 2, + "logs_volume_size": 2 + }, + "instance_stack": { + "stack_name": "escm-instances" + }, + "floating_network": "floating" + }, + "mail": { + "auth": true, + "host": "", + "port": 25, + "tls": false, + "user": "", + "password": "", + "from": "" + }, + "docker": { + "dockerhub": true, + "host": "", + "port": 5000, + "auth": false, + "user": "", + "password": "", + "organization": "servicecatalog", + "tag": "v17.5.0" + }, + "proxy": { + "use_proxy": false, + "http_host": "", + "http_port": 80, + "https_host": "", + "https_port": 80, + "no_proxy": "", + "auth": false, + "user": "", + "password": "" + }, + "host_fqdn": "", + "ssl": { + "certfile": "/etc/escm/ssl/certs/signing_cert.pem", + "keyfile": "/etc/escm/ssl/private/signing_key.pem", + "generate_certs": false, + "fqdn": "", + "ca_certs": "/etc/escm/ssl/certs/ca.pem" + }, + "api": { + "protocol": "https" + } + } + }, + "deployment": { + "escm": { + "crowbar-revision": 0, + "crowbar-applied": false, + "schema-revision": 100, + "element_states": { + "escm-server": [ "readying", "ready", "applying" ] + }, + "element_order": [ + [ "escm-server" ] + ], + "elements": {}, + "element_run_list_order": { + "escm-server": 110 + }, + "config": { + "mode": "full", + "transitions": false, + "transition_list": [] + } + } + } +} diff --git a/chef/data_bags/crowbar/template-escm.schema b/chef/data_bags/crowbar/template-escm.schema new file mode 100644 index 0000000000..9323e52d5b --- /dev/null +++ b/chef/data_bags/crowbar/template-escm.schema @@ -0,0 +1,210 @@ +{ + "type": "map", + "required": true, + "mapping": { + "id": { "type": "str", "required": true}, + "description": { "type": "str", "required": true }, + "attributes": { + "type": "map", + "required": true, + "mapping": { + "escm": { + "type": "map", + "required": true, + "mapping": { + "timeout": { "type": "int", "required": true }, + "debug": { "type": "bool", "required": true }, + "keystone_instance": { "type": "str", "required": true }, + "nova_instance": { "type": "str", "required": true }, + "heat_instance": { "type": "str", "required": true }, + "keystone" : { + "type" : "map", + "required" : true, + "mapping": { + "project": { "type": "str", "required": true }, + "user": { "type": "str", "required": true }, + "password": { "type": "str", "required": true } + } + }, + "openstack" : { + "type" : "map", + "required" : true, + "mapping": { + "image": { "type": "str", "required": true }, + "flavor": { + "type" : "map", + "required" : true, + "mapping": { + "name": { "type": "str", "required": true }, + "ram": { "type": "int", "required": true }, + "vcpus": { "type": "int", "required": true }, + "disk": { "type": "int", "required": true } + } + }, + "keypair": { + "type" : "map", + "required" : true, + "mapping": { + "name": { "type": "str", "required": true }, + "publickey": { "type": "str", "required": true } + } + }, + "volume_stack" : { + "type" : "map", + "required" : true, + "mapping": { + "stack_name": { "type": "str", "required": true }, + "data_volume_size": { "type": "int", "required": true }, + "logs_volume_size": { "type": "int", "required": true } + } + }, + "instance_stack" : { + "type" : "map", + "required" : true, + "mapping": { + "stack_name": { "type": "str", "required": true } + } + }, + "floating_network" : { "type": "str", "required": true } + } + }, + "mail" : { + "type" : "map", + "required" : true, + "mapping": { + "auth": { "type": "bool", "required": true }, + "host": { "type": "str", "required": true }, + "port": { "type": "int", "required": true }, + "tls": { "type": "bool", "required": true }, + "user": { "type": "str", "required": true }, + "password": { "type": "str", "required": true }, + "from": { "type": "str", "required": true } + } + }, + "docker" : { + "type" : "map", + "required" : true, + "mapping": { + "dockerhub": { "type": "bool", "required": true }, + "host": { "type": "str", "required": true }, + "port": { "type": "int", "required": true }, + "auth": { "type": "bool", "required": true }, + "user": { "type": "str", "required": true }, + "password": { "type": "str", "required": true }, + "organization": { "type": "str", "required": true }, + "tag": { "type": "str", "required": true } + } + }, + "proxy" : { + "type" : "map", + "required" : true, + "mapping": { + "use_proxy": { "type": "bool", "required": true }, + "http_host": { "type": "str", "required": true }, + "http_port": { "type": "int", "required": true }, + "https_host": { "type": "str", "required": true }, + "https_port": { "type": "int", "required": true }, + "no_proxy": { "type": "str", "required": true }, + "auth": { "type": "bool", "required": true }, + "user": { "type": "str", "required": true }, + "password": { "type": "str", "required": true } + } + }, + "host_fqdn": { "type" : "str", "required" : true }, + "ssl": { + "type": "map", + "required": true, + "mapping": { + "certfile": { "type" : "str", "required" : true }, + "keyfile": { "type" : "str", "required" : true }, + "generate_certs": { "type" : "bool", "required" : true }, + "fqdn": { "type" : "str", "required" : true }, + "ca_certs": { "type" : "str", "required" : true } + } + }, + "api": { + "type": "map", + "required": true, + "mapping": { + "protocol": { "type" : "str", "required" : true } + } + } + } + } + } + }, + + "deployment": { + "type": "map", + "required": true, + "mapping": { + "escm": { + "type": "map", + "required": true, + "mapping": { + "crowbar-revision": { "type": "int", "required": true }, + "crowbar-committing": { "type": "bool" }, + "crowbar-applied": { "type": "bool" }, + "crowbar-status": { "type": "str" }, + "crowbar-failed": { "type": "str" }, + "crowbar-queued": { "type": "bool" }, + "schema-revision": { "type": "int" }, + "element_states": { + "type": "map", + "mapping": { + = : { + "type": "seq", + "required": true, + "sequence": [ { "type": "str" } ] + } + } + }, + "elements": { + "type": "map", + "required": true, + "mapping": { + = : { + "type": "seq", + "required": true, + "sequence": [ { "type": "str" } ] + } + } + }, + "element_order": { + "type": "seq", + "required": true, + "sequence": [ { + "type": "seq", + "sequence": [ { "type": "str" } ] + } ] + }, + "element_run_list_order": { + "type": "map", + "required": false, + "mapping": { + = : { + "type": "int", + "required": true + } + } + }, + "config": { + "type": "map", + "required": true, + "mapping": { + "environment": { "type": "str", "required": true }, + "mode": { "type": "str", "required": true }, + "transitions": { "type": "bool", "required": true }, + "transition_list": { + "type": "seq", + "required": true, + "sequence": [ { "type": "str" } ] + } + } + } + } + } + } + } + } +} diff --git a/chef/roles/escm-server.rb b/chef/roles/escm-server.rb new file mode 100644 index 0000000000..fc9d320930 --- /dev/null +++ b/chef/roles/escm-server.rb @@ -0,0 +1,5 @@ +name "escm-server" +description "ESCM Server Role" +run_list("recipe[escm::role_escm_server]") +default_attributes +override_attributes diff --git a/crowbar_framework/app/controllers/escm_controller.rb b/crowbar_framework/app/controllers/escm_controller.rb new file mode 100644 index 0000000000..e2dabd8a62 --- /dev/null +++ b/crowbar_framework/app/controllers/escm_controller.rb @@ -0,0 +1,25 @@ +# +# Copyright 2017, SUSE LINUX GmbH +# +# 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. +# + +class EscmController < BarclampController + # Controller for ESCM barclamp + + protected + + def initialize_service + @service_object = EscmService.new logger + end +end diff --git a/crowbar_framework/app/helpers/barclamp/escm_helper.rb b/crowbar_framework/app/helpers/barclamp/escm_helper.rb new file mode 100644 index 0000000000..2ae26a9015 --- /dev/null +++ b/crowbar_framework/app/helpers/barclamp/escm_helper.rb @@ -0,0 +1,28 @@ +# +# Copyright 2017, SUSE LINUX GmbH +# +# 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. +# + +module Barclamp + module EscmHelper + def api_protocols_for_escm(selected) + options_for_select( + [ + ["HTTPS", "https"] + ], + selected.to_s + ) + end + end +end diff --git a/crowbar_framework/app/models/escm_service.rb b/crowbar_framework/app/models/escm_service.rb new file mode 100644 index 0000000000..2270950d80 --- /dev/null +++ b/crowbar_framework/app/models/escm_service.rb @@ -0,0 +1,77 @@ +# +# Copyright 2017, SUSE LINUX GmbH +# +# 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. +# + +class EscmService < PacemakerServiceObject + def initialize(thelogger) + @bc_name = "escm" + @logger = thelogger + end + + class << self + # Turn off multi proposal support till it really works and people ask for it. + def self.allow_multiple_proposals? + false + end + + def role_constraints + { + "escm-server" => { + "unique" => false, + "count" => 1, + "admin" => false, + "cluster" => false, + "exclude_platform" => { + "suse" => "< 12.1", + "windows" => "/.*/" + } + }, + } + end + end + + def proposal_dependencies(role) + answer = [] + ["heat"].each do |dep| + answer << { "barclamp" => dep, "inst" => role.default_attributes[@bc_name]["#{dep}_instance"] } + end + answer + end + + def create_proposal + @logger.debug("Escm create_proposal: entering") + base = super + + nodes = NodeObject.all + server_nodes = nodes.select { |n| n.intended_role == "controller" } + server_nodes = [nodes.first] if server_nodes.empty? + + base["deployment"][@bc_name]["elements"] = { + "escm-server" => [server_nodes.first.name] + } unless server_nodes.nil? + + base["attributes"][@bc_name]["keystone_instance"] = find_dep_proposal("keystone") + base["attributes"][@bc_name]["heat_instance"] = find_dep_proposal("heat") + + @logger.debug("Escm create_proposal: exiting") + base + end + + def validate_proposal_after_save(proposal) + validate_one_for_role proposal, "escm-server" + + super + end +end diff --git a/crowbar_framework/app/views/barclamp/escm/_edit_attributes.html.haml b/crowbar_framework/app/views/barclamp/escm/_edit_attributes.html.haml new file mode 100644 index 0000000000..8669c5988c --- /dev/null +++ b/crowbar_framework/app/views/barclamp/escm/_edit_attributes.html.haml @@ -0,0 +1,96 @@ += attributes_for @proposal do + .panel-sub + = header show_raw_deployment?, true + + .panel-body + %fieldset + %legend + = t(".mail_settings") + + = string_field %w(mail host) + = integer_field %w(mail port) + = boolean_field %w(mail tls) + = string_field %w(mail from) + + = boolean_field %w(mail auth), + "data-showit" => "true", + "data-showit-target" => "#mail_container", + "data-showit-direct" => "true" + + #mail_container + = string_field %w(mail user) + = password_field %w(mail password) + + %fieldset + %legend + = t(".docker_settings") + = boolean_field %w(docker dockerhub), + "data-showit" => "false", + "data-showit-target" => "#dockerhub_container", + "data-showit-direct" => "true" + + #dockerhub_container + = string_field %w(docker host) + = integer_field %w(docker port) + = string_field %w(docker organization) + + = boolean_field %w(docker auth), + "data-showit" => "true", + "data-showit-target" => "#dockerauth_container", + "data-showit-direct" => "true" + + #dockerauth_container + = string_field %w(docker user) + = password_field %w(docker password) + + %fieldset + %legend + = t(".proxy_settings") + + = boolean_field %w(proxy use_proxy), + "data-showit" => "true", + "data-showit-target" => "#proxy_container", + "data-showit-direct" => "true" + + #proxy_container + = string_field %w(proxy http_host) + = integer_field %w(proxy http_port) + = string_field %w(proxy https_host) + = integer_field %w(proxy https_port) + %span.help-block + = t('.proxy_hint') + = string_field %w(proxy no_proxy) + = boolean_field %w(proxy auth), + "data-showit" => "true", + "data-showit-target" => "#proxyauth_container", + "data-showit-direct" => "true" + #proxyauth_container + = string_field %w(proxy user) + = password_field %w(proxy password) + + %fieldset + %legend + = t(".openstack_settings") + + %span.help-block + = t('.keypair_hint') + = text_field %w(openstack keypair publickey) + + %fieldset + %legend + = t(".ssl_header") + + = select_field %w(api protocol), + :collection => :api_protocols_for_escm, + "data-sslprefix" => "ssl", + "data-sslcert" => "/etc/escm/ssl/certs/signing_cert.pem", + "data-sslkey" => "/etc/escm/ssl/private/signing_key.pem" + + #ssl_container + %span.help-block + = t('.ssl_hint') + = boolean_field %w(ssl generate_certs) + = string_field %w(ssl fqdn) + = string_field %w(ssl certfile) + = string_field %w(ssl keyfile) + = string_field %w(ssl ca_certs) diff --git a/crowbar_framework/config/locales/escm/en.yml b/crowbar_framework/config/locales/escm/en.yml new file mode 100644 index 0000000000..7a6b1c8248 --- /dev/null +++ b/crowbar_framework/config/locales/escm/en.yml @@ -0,0 +1,68 @@ +# +# Copyright 2017, SUSE LINUX GmbH +# +# 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. +# + +en: + barclamp: + escm: + edit_attributes: + keystone_instance: 'Keystone' + heat_instance: 'Heat' + mail_settings: 'Mail Settings' + mail: + auth: 'Authentication Required' + host: 'Mail Host' + port: 'SMTP Port' + tls: 'Enable TLS' + user: 'User' + password: 'Password' + from: 'ESCM Email Address' + docker_settings: 'Docker Registry' + docker: + dockerhub: 'Use Docker Hub' + organization: 'Organization' + auth: 'Authentication Required' + host: 'Registry Host' + port: 'Registry Port' + user: 'User' + password: 'Password' + proxy_settings: 'Proxy Settings' + proxy: + auth: 'Authentication Required' + use_proxy: 'Use Proxy' + http_host: 'HTTP Host' + http_port: 'HTTP Port' + https_host: 'HTTPS Host' + https_port: 'HTTPS Port' + no_proxy: 'No Proxy' + user: 'User' + password: 'Password' + proxy_hint: 'A comma-separated list of hosts which can bypass the proxy' + openstack_settings: "OpenStack Settings" + openstack: + keypair: + publickey: "Public Key" + keypair_hint: 'SSH public key of the keypair for openstack instance which hosts ESCM. It cannot be updated.' + api: + protocol: 'Protocol' + ssl_header: 'SSL Settings' + ssl: + generate_certs: 'Generate self-signed certificates' + fqdn: 'Host FQDN/IP address (if left empty, the floating IP will be used)' + certfile: 'SSL Certificate File' + keyfile: 'SSL Private Key File' + ca_certs: 'SSL CA Certificates File (optional)' + ssl_hint: 'Delete the SSL key pair on the given locations, in order to generate new one.' + diff --git a/escm.yml b/escm.yml new file mode 100644 index 0000000000..0405479dd6 --- /dev/null +++ b/escm.yml @@ -0,0 +1,33 @@ +# +# Copyright 2017, SUSE LINUX GmbH +# +# 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. +# + +barclamp: + name: 'escm' + display: 'ESCM' + description: 'Enterprise Service Catalog Manager' + version: 1 + member: + - 'openstack' + requires: + - 'heat' + +crowbar: + layout: 1 + order: 135 + run_order: 135 + chef_order: 135 + proposal_schema_version: 1 +