--- /dev/null
+#! /usr/bin/python
+# Copyright 2019 Nokia
+#
+# 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.
+
+from cmframework.apis import cmerror
+from cmframework.apis import cmactivator
+from cmdatahandlers.api import configmanager
+from cmdatahandlers.api import configerror
+import os
+import subprocess
+import json
+import pwd
+import logging
+
+class installationactivator(cmactivator.CMGlobalActivator):
+ inventory_cli = '/opt/cmframework/scripts/inventory.sh'
+ playbooks_generate_cli = '/usr/local/bin/cmcli ansible-playbooks-generate'
+ playbooks_path = '/opt/openstack-ansible/playbooks/'
+ setup_playbook = 'setup-playbook.yml'
+ presetup_playbook = 'presetup-playbook.yml'
+ bootstrapping_playbook = 'bootstrapping-playbook.yml'
+ provisioning_playbook = 'provisioning-playbook.yml'
+ postconfig_playbook = 'postconfig-playbook.yml'
+ state_file = '/etc/installation_state'
+
+ def __init__(self):
+ self.plugin_client = None
+
+ def get_subscription_info(self):
+ return '.*'
+
+ def activate_set(self, props):
+ self.activate_full()
+
+ def activate_delete(self, props):
+ self.activate_full()
+
+ def activate_full(self, target=None):
+ try:
+ properties = self.get_plugin_client().get_properties('.*')
+ if not properties:
+ return
+ propsjson = {}
+ for name, value in properties.iteritems():
+ try:
+ propsjson[name] = json.loads(value)
+ except Exception as exp:
+ continue
+ configman = configmanager.ConfigManager(propsjson)
+
+ hostsconfig = configman.get_hosts_config_handler()
+ installation_host = hostsconfig.get_installation_host()
+
+ installed = False
+ try:
+ configman.get_cloud_installation_date()
+ installed = True
+ except configerror.ConfigError as exp:
+ pass
+
+ if installed:
+ return
+
+ usersconf = configman.get_users_config_handler()
+ admin = usersconf.get_admin_user()
+
+ #generate high level playbooks
+ if self._run_cmd(self.playbooks_generate_cli, '/etc', 'root', os.environ.copy()):
+ raise cmerror.CMError('Failed to run %s' % self.playbooks_generate_cli)
+
+ caas_data = configman.get_caas_config_handler()
+ phase = self._get_installation_phase()
+ #first we run the setup
+ if not phase:
+ self._set_installation_phase('setup-started')
+ phase = 'setup-started'
+ env = os.environ.copy()
+ if phase == 'setup-started':
+ env['VNF_EMBEDDED_DEPLOYMENT'] = 'false'
+ env['CONFIG_PHASE'] = 'setup'
+ env['BOOTSTRAP_OPTS'] = 'installation_controller=%s' %(installation_host)
+ self._run_setup_playbook(self.presetup_playbook, env)
+ env['BOOTSTRAP_OPTS'] = ''
+ if caas_data.get_vnf_flag():
+ env['VNF_EMBEDDED_DEPLOYMENT'] = 'true'
+ self._run_setup_playbook(self.setup_playbook, env)
+ self._set_installation_phase('setup-ended')
+ phase = 'setup-ended'
+
+ #second we run the aio
+ if phase == 'setup-ended':
+ self._set_installation_phase('bootstrapping-started')
+ phase = 'bootstrapping-started'
+ if phase == 'bootstrapping-started':
+ env['CONFIG_PHASE'] = 'bootstrapping'
+ self._run_playbook(self.bootstrapping_playbook, admin, env)
+ self._set_installation_phase('bootstrapping-ended')
+ phase = 'bootstrapping-ended'
+
+ #3rd we run the provisioning
+ if phase == 'bootstrapping-ended':
+ self._set_installation_phase('provisioning-started')
+ phase = 'provisioning-started'
+ if phase == 'provisioning-started':
+ env['CONFIG_PHASE'] = 'provisioning'
+ self._run_playbook(self.provisioning_playbook, admin, env)
+ self._set_installation_phase('provisioning-ended')
+ phase = 'provisioning-ended'
+
+ #4th we run the postconfig
+ if phase == 'provisioning-ended':
+ self._set_installation_phase('postconfig-started')
+ phase = 'postconfig-started'
+ if phase == 'postconfig-started':
+ env['CONFIG_PHASE'] = 'postconfig'
+ env['CAAS_ONLY_DEPLOYMENT'] = 'false'
+ if caas_data.get_caas_only():
+ env['CAAS_ONLY_DEPLOYMENT'] = 'true'
+ self._run_playbook(self.postconfig_playbook, admin, env)
+ self._set_installation_phase('postconfig-ended')
+ phase = 'postconfig-ended'
+
+ self._set_installation_date()
+
+ self._set_state('success')
+
+ except Exception as exp:
+ self._set_state('failure')
+ raise cmerror.CMError(str(exp))
+
+ def _set_installation_phase(self, phase):
+ self.get_plugin_client().set_property('cloud.installation_phase', json.dumps(phase))
+
+ def _get_installation_phase(self):
+ phase = None
+ try:
+ phase = json.loads(self.get_plugin_client().get_property('cloud.installation_phase'))
+ logging.debug('Current installation phase cloud.installation_phase="%s"'%phase)
+ except Exception as exp:
+ pass
+ return phase
+
+ def _set_installation_date(self):
+ from time import gmtime, strftime
+ # Use ISO 8601 date format
+ times = strftime('%Y-%m-%dT%H:%M:%SZ', gmtime())
+ self.get_plugin_client().set_property('cloud.installation_date', json.dumps(times))
+
+ def _run_playbook(self, playbook, user, env):
+ cmd = '/usr/local/bin/openstack-ansible -b -u ' + user + ' ' + playbook
+ result = self._run_cmd(cmd, self.playbooks_path, user, env)
+ if result != 0:
+ raise cmerror.CMError('Playbook %s failed' % playbook)
+
+ def _run_setup_playbook(self, playbook, env):
+ cmd = '/usr/local/bin/setup-controller.sh ' + playbook
+ result = self._run_cmd(cmd, self.playbooks_path, 'root', env)
+ if result != 0:
+ raise cmerror.CMError('Playbook %s failed' % playbook)
+
+ def _run_cmd(self, cmd, cwd, user, env):
+ args = cmd.split()
+ pw_record = pwd.getpwnam(user)
+ user_name = pw_record.pw_name
+ user_home_dir = pw_record.pw_dir
+ user_uid = pw_record.pw_uid
+ user_gid = pw_record.pw_gid
+ env['HOME'] = user_home_dir
+ env['LOGNAME'] = user_name
+ env['HOME'] = user_home_dir
+ env['PWD'] = cwd
+ env['USER'] = user_name
+ process = subprocess.Popen(args, preexec_fn=self._demote(user_uid, user_gid), cwd=cwd, env=env)
+ result = process.wait()
+ return result
+
+
+ def _demote(self, user_uid, user_gid):
+ def result():
+ os.setgid(user_gid)
+ os.setuid(user_uid)
+ return result
+
+ def _set_state(self, state):
+ with open(self.state_file, 'w') as f:
+ f.write(state)