class ICPDBootstrap(object): ArgsSignature = { '--help': 'string', '--region': 'string', '--stack-name': 'string', '--stackid': 'string', '--role': 'string', '--logfile': 'string', '--loglevel': 'string', '--trace': 'string' } def __init__(self): """ Constructor """ object.__init__(self) self.home = os.path.expanduser("~") self.logsHome = os.path.join(self.home, "logs") def makeDir(self, path): if not os.path.exists(path): os.makedirs(path) #endif #enddef def setupBootNode(self, icpdInstallLogFile): methodName = "setupBootNode" # copy .docker contents to bootnode from masternode dockerpath = "/root/.docker" configFile = '/.docker/config.json' remoteHost = "root@" + self.bootstrap.getMasterIPAddresses()[0] scpCmd = "scp -o StrictHostKeyChecking=no " + remoteHost + ":" config_scp = scpCmd + "~" + configFile + " ." TR.info( methodName, "Copy %s file from %s using scp command %s" % (configFile, remoteHost, config_scp)) self.makeDir(dockerpath) os.chdir(dockerpath) call(config_scp, shell=True, stdout=icpdInstallLogFile) #copy certs from masternode to bootnode etcDockerPath = '/etc/docker/' certsPath = etcDockerPath + 'certs.d/' registry = self.bootstrap.ClusterDNSName + ':8500' registryPath = certsPath + registry rootCert = registryPath + '/root-ca.crt' caCert = registryPath + '/ca.crt' ca_scp = scpCmd + caCert + " ." root_scp = scpCmd + rootCert + " ." TR.info(methodName, "Copy %s and %s file from %s" % (rootCert, caCert, remoteHost)) TR.info(methodName, "RootCert scp command: %s" % (root_scp)) TR.info(methodName, "CACert scp command: %s" % (ca_scp)) self.makeDir(registryPath) os.chdir(registryPath) call(ca_scp, shell=True, stdout=icpdInstallLogFile) call(root_scp, shell=True, stdout=icpdInstallLogFile) #endDef def installICPD(self): """ Install ICPD by executing the script Script will copy required pre-requiste and extract the installer and run the deploy scripts It is assumed all the pre-installation configuration steps have been completed. """ methodName = "installICPD" TR.info(methodName, "IBM Cloud Pak for Data installation started.") # We really do not need this when ICP fixes the bootnode docker and certs issue # copy .docker contents to bootnode from masternode logFilePath = os.path.join(self.logsHome, "icpd_install.log") with open(logFilePath, "a+") as icpdInstallLogFile: self.setupBootNode(icpdInstallLogFile) # create /ibm folder and extract icp4d.tar contents to it TR.info(methodName, "Extract icp4d.tar to /ibm") self.makeDir('/ibm') call('tar -xvf /tmp/icp4d.tar -C /ibm/', shell=True, stdout=icpdInstallLogFile) os.chdir('/ibm') # cd to /ibm and give +x to installer file installCMD = self.installMap['installCMD'] TR.info(methodName, "install CMD : %s" % (installCMD)) os.chmod(installCMD, stat.S_IEXEC) # docker login to registry to be on safer side registry = self.bootstrap.ClusterDNSName + ':8500' dockerCMD = 'docker login ' + registry + '/zen -u ' + self.bootstrap.AdminUser + ' -p ' + self.bootstrap.AdminPassword call(dockerCMD, shell=True, stdout=icpdInstallLogFile) #create namepsace namespaceCMD = "sudo kubectl create -f /root/zen.yaml" call(namespaceCMD, shell=True, stdout=icpdInstallLogFile) #create docker secret secretCMD = "sudo kubectl create secret -n zen docker-registry icp4d-anyuid-docker-pull --docker-server=" + registry + " --docker-username=admin --docker-password="******"2.1.0.1"): portValue = '\n31843\nY' #endIf input = '\nA\nzen\nY' + portValue + '\n' + registry + '/zen\n\nY\nN\n' + str( storageclass) + '\nY\nY\nY' TR.info(methodName, "Input for installer : %s" % (input)) runInstaller = 'sudo /ibm/' + installCMD process = Popen(runInstaller, shell=True, stdin=PIPE, stdout=icpdInstallLogFile, stderr=icpdInstallLogFile, close_fds=True) stdoutdata, stderrdata = process.communicate(input) TR.info(methodName, "%s" % (stdoutdata)) manageUser = "******" + self.bootstrap.AdminPassword TR.info(methodName, "Start manageUser") call(manageUser, shell=True, stdout=icpdInstallLogFile) TR.info(methodName, "End manageUser") TR.info(methodName, "Start Activate trial") icpdUrl = "https://" + self.bootstrap.ClusterDNSName + ":31843" activatetrial = "sudo python /root/activate-trial.py " + icpdUrl + " admin " + self.bootstrap.AdminPassword + " /root/trial.lic" call(activatetrial, shell=True, stdout=icpdInstallLogFile) TR.info(methodName, "End Activate trial") TR.info(methodName, "IBM Cloud Pak for Data installation completed.") os.remove("/root/trial.lic") source_file = open("/root/activate-license.sh").read() source_file = source_file.replace('<CLUSTERDNSNAME>', self.bootstrap.ClusterDNSName) updated_file = open("/root/activate-license.sh", 'w') updated_file.write(source_file) updated_file.close() TR.info(methodName, "Create configmap for addons") source_file = open("/root/configmap.yaml").read() source_file = source_file.replace('<CLUSTERDNSNAME>', self.bootstrap.ClusterDNSName) updated_file = open("/root/configmap.yaml", 'w') updated_file.write(source_file) updated_file.close() # run kubectl create configmap.yaml kubectlCMD = "sudo kubectl create -f /root/configmap.yaml" check_call(kubectlCMD, shell=True, stdout=icpdInstallLogFile) TR.info(methodName, "Created configmap for addons") addonList = self.bootstrap.Addons.split(",") if (addonList != ['']): for addon in addonList: TR.info(methodName, "Addon to be installed %s" % addon) installAddon = "sudo python /root/deploy_icpd_addons.py " + addon TR.info( methodName, "Intitate addon %s installation with following command %s" % (addon, installAddon)) retcode = check_call(installAddon, shell=True, stdout=icpdInstallLogFile) TR.info( methodName, "Return code for addon %s installation is %s" % (addon, retcode)) #endFor #endIf TR.info( methodName, "IBM Cloud Pak for Data Addons %s installation completed." % addonList) url = "wget -q -O - http://169.254.169.254/latest/meta-data/instance-id" bootInstanceId = check_output(url, shell=True) self.bootstrap.putSSMParameter( "/%s/bootInstanceId" % self.bootstrap.rootStackName, bootInstanceId, description="Boot InstanceId of %s" % self.bootstrap.rootStackName) TR.info(methodName, "Set flag for stack creation completion") self.bootstrap.putSSMParameter( "/%s/stackStatus" % self.bootstrap.rootStackName, "Created", description=" %s is created successfully." % self.bootstrap.rootStackName) #endFor #endwith #endDef def signalWaitHandle(self, eth, etm, ets): """ Send a status signal to the "install completed" wait condition via the pre-signed URL provided to the stack. If the instance rc is 0, we send a --success true If the instance rc is non-zero we send a --success false More detail on the status is provided in the --reason option of the signal. NOTE: A failure signal (--success false) causes a rollback of the CloudFormation templates. If the deployer does not use --disable-rollback, then the VMs are deleted and doing a post mortem can be more difficult. """ methodName = 'signalWaitHandle' try: if (self.rc == 0): success = 'true' status = 'SUCCESS' else: success = 'false' status = 'FAILURE: Check boot node logs in S3 log bucket or on the boot node EC2 instance in /root/logs bootstrap.log and /opt/icp/%s/cluster/logs install.log.*' % self.bootstrap.ICPVersion #endIf data = "%s: IBM Cloud Pak installation elapsed time: %d:%02d:%02d" % ( status, eth, etm, ets) TR.info( methodName, "Signaling: %s with status: %s, data: %s" % (self.bootstrap.ICPDInstallationCompletedURL, status, data)) # Deployer should use --disable-rollback to avoid deleting the stack on failures and allow a post mortem. check_call([ '/usr/local/bin/cfn-signal', '--success', success, '--id', self.bootStackId, '--reason', status, '--data', data, self.bootstrap.ICPDInstallationCompletedURL ]) except CalledProcessError as e: TR.error( methodName, "ERROR return code: %s, Exception: %s" % (e.returncode, e), e) raise e #endTry #endDef def main(self, argv): methodName = "main" self.rc = 0 self.bootstrap = Bootstrap() try: beginTime = Utilities.currentTimeMillis() cmdLineArgs = Utilities.getInputArgs(self.ArgsSignature, argv[1:]) trace, logFile = self.bootstrap._configureTraceAndLogging( cmdLineArgs) TR.info( methodName, "BOOT0101I BEGIN Bootstrap AWS ICPD Quickstart version 1.0.0.") if (trace): TR.info( methodName, "BOOT0102I Tracing with specification: '%s' to log file: '%s'" % (trace, logFile)) #endIf region = cmdLineArgs.get('region') self.bootstrap.region = region self.bootstrap.role = cmdLineArgs.get('role') self.bootstrap.fqdn = socket.getfqdn() self.bootStackId = cmdLineArgs.get('stackid') self.bootstrap.rootStackName = cmdLineArgs.get('stack-name') self.bootstrap._init(self.bootstrap.rootStackName, self.bootStackId) TR.info(methodName, "Addons to be installed %s" % self.bootstrap.Addons) self.logExporter = LogExporter( region=self.bootstrap.region, bucket=self.bootstrap.ICPDeploymentLogsBucketName, keyPrefix='logs/%s' % self.bootstrap.rootStackName, role=self.bootstrap.role, fqdn=self.bootstrap.fqdn) self.icpHome = "/opt/icp/%s" % self.bootstrap.ICPVersion installMapPath = os.path.join(self.home, "maps", "icpd-install-artifact-map.yaml") self.installMap = self.bootstrap.loadInstallMap( mapPath=installMapPath, version=self.bootstrap.ICPDVersion, region=self.bootstrap.region) icpdS3Path = "{version}/{object}".format( version=self.installMap['version'], object=self.installMap['icpd-base-install-archive']) destPath = "/tmp/icp4d.tar" storageClassCmd = "kubectl get storageclass | nl | grep aws-efs | awk '{print $1}'" TR.info( methodName, "check_output Get StorageClass value from kubectl %s" % (storageClassCmd)) self.storageclassValue = check_output( ['bash', '-c', storageClassCmd]) TR.info( methodName, "check_output StorageclassValue returned : %s" % (self.storageclassValue)) self.bootstrap.getS3Object(self.bootstrap.ICPDArchiveBucketName, icpdS3Path, destPath) self.stackIds = self.bootstrap._getStackIds(self.bootStackId) self.bootstrap._getHosts(self.stackIds) self.installICPD() except ExitException: pass # ExitException is used as a "goto" end of program after emitting help info except Exception, e: TR.error(methodName, "ERROR: %s" % e, e) self.rc = 1 except BaseException, e: TR.error(methodName, "UNEXPECTED ERROR: %s" % e, e) self.rc = 1