mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	Co-authored-by: John Bampton <jbampton@users.noreply.github.com> Co-authored-by: dahn <daan@onecht.net>
		
			
				
	
	
		
			237 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			237 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/python
 | |
| # -*- coding: utf-8 -*-
 | |
| # Licensed to the Apache Software Foundation (ASF) under one
 | |
| # or more contributor license agreements.  See the NOTICE file
 | |
| # distributed with this work for additional information
 | |
| # regarding copyright ownership.  The ASF licenses this file
 | |
| # to you 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.
 | |
| 
 | |
| import argparse
 | |
| import sys
 | |
| import urllib
 | |
| import uuid
 | |
| import subprocess
 | |
| import os
 | |
| import shutil
 | |
| import gzip
 | |
| import zipfile
 | |
| import bz2
 | |
| 
 | |
| class InstallSysTemplate(object):
 | |
|   parser = None
 | |
|   mountpoint = None
 | |
|   args = None
 | |
|   hypervisor = None
 | |
|   systemvmtemplatepath = None
 | |
|   systemvmtemplateurl = None
 | |
|   managementsecretkey = None
 | |
|   forcecleanup = None
 | |
|   databasehostname = None
 | |
|   databaseusername = None
 | |
|   databaseuserpassword = None
 | |
|   templatesuffix = None
 | |
|   template = None
 | |
|   fileextension = None
 | |
|   templateName = None
 | |
|   destDir = None
 | |
|   fileSize = None
 | |
|   dictionary = None
 | |
| 
 | |
|   def __init__(self):
 | |
|     self.dictionary = dict(xenserver=('XenServer', 'vhd'), kvm=('KVM', 'qcow2'), vmware=('VMware', 'ova'), lxc=('LXC', 'qcow2'), hyperv=('Hyperv', 'vhd'))
 | |
| 
 | |
|   def parseOptions(self):
 | |
|     self.parser = argparse.ArgumentParser(prog="System Template Installer")
 | |
|     self.parser.add_argument("-m", "--mount-point", action="store", dest="mountpoint", help="Secondary Storage Mount Point where to install the template.", required="true")
 | |
|     self.parser.add_argument("-H", "--hypervisor", action="store", dest="hypervisor", help="The Hypervisor name for which template need to be installed", required="true", choices=['kvm','xenserver','vmware','lxc','hyperv'])
 | |
|     group = self.parser.add_mutually_exclusive_group(required=True)
 | |
|     group.add_argument("-f", "--system-vm-template", action="store", dest="systemvmtemplatepath", help="The local system vm template file path")
 | |
|     group.add_argument("-u", "--system-vm-template-url", action="store", dest="systemvmtemplateurl", help="Url to download system vm template")
 | |
|     self.parser.add_argument("-s", "--management-secret-key", action="store", dest="managementsecretkey", help="mgmt server secret key, if you specified any when running cloudstack-setup-database, default is password", default="password")
 | |
|     self.parser.add_argument("-F", "--force-clean-up", action="store_true", dest="forcecleanup", help="clean up system templates of specified hypervisor", default="false")
 | |
|     self.parser.add_argument("-d", "--database-host-name", action="store", dest="databasehostname", help="Database server hostname or ip, e.g localhost", default="localhost", required="true")
 | |
|     self.parser.add_argument("-r", "--database-user-name", action="store", dest="databaseusername", help="Database user name, e.g root", default="root", required="true")
 | |
|     self.parser.add_argument("-p", "--database-user-password", nargs='?', action="store", dest="databaseuserpassword", help="Database password. Followed by nothing if the password is empty", default="", required="true")
 | |
|     self.parser.add_argument("-e", "--template-suffix", action="store", dest="templatesuffix", help="Template suffix, e.g vhd, ova, qcow2",default="vhd")
 | |
|     self.parser.add_argument("-t", "--file-extension", action="store", dest="fileextension", help="The template file extension", default="", required="true", choices=['bz2','gz','zip'])
 | |
| 
 | |
|     self.args = self.parser.parse_args()
 | |
| 
 | |
|   def populateOptions(self):
 | |
|     self.mountpoint = self.args.mountpoint
 | |
|     self.hypervisor = self.args.hypervisor
 | |
|     self.fileextension = self.args.fileextension
 | |
|     if self.args.systemvmtemplatepath:
 | |
|       self.systemvmtemplatepath = self.args.systemvmtemplatepath
 | |
|     if self.args.systemvmtemplateurl:
 | |
|       self.systemvmtemplateurl = self.args.systemvmtemplateurl
 | |
|     if self.args.managementsecretkey:
 | |
|       self.managementsecretkey = self.args.managementsecretkey
 | |
|     if self.args.forcecleanup:
 | |
|       self.forcecleanup = self.args.forcecleanup
 | |
|     if self.args.databasehostname:
 | |
|       self.databasehostname = self.args.databasehostname
 | |
|     if self.args.databaseusername:
 | |
|       self.databaseusername = self.args.databaseusername
 | |
|     if self.args.databaseuserpassword:
 | |
|       self.databaseuserpassword = self.args.databaseuserpassword
 | |
|     else:
 | |
|       self.databaseuserpassword = ""
 | |
|     if self.args.templatesuffix:
 | |
|       self.templatesuffix = self.args.templatesuffix
 | |
|     print 'Password for DB: %s'%self.databaseuserpassword
 | |
| 
 | |
|   def errorAndExit(self, msg):
 | |
|     err = '''\n\nWe apologize for below error:
 | |
| ***************************************************************
 | |
| %s
 | |
| ***************************************************************
 | |
| Please run:
 | |
| 
 | |
|     cloud-install-sys-tmplt -h
 | |
| 
 | |
| for full help
 | |
| ''' % msg
 | |
|     sys.stderr.write(err)
 | |
|     sys.stderr.flush()
 | |
|     sys.exit(1)
 | |
| 
 | |
|   def runCmd(self, cmds):
 | |
|     process = subprocess.Popen(' '.join(cmds), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 | |
|     stdout, stderr = process.communicate()
 | |
|     print(stdout)
 | |
|     if process.returncode != 0:
 | |
|         raise Exception(stderr)
 | |
|     return stdout
 | |
| 
 | |
|   def runMysql(self, query):
 | |
|     try:
 | |
|       print 'Running Query: %s' % query
 | |
|       mysqlCmds = ['mysql', '--user=%s'%self.databaseusername, '--host=%s'%self.databasehostname, '--password=%s'%self.databaseuserpassword, '--skip-column-names', '-U', 'cloud', '-e "%s"'%query]
 | |
|       templateId = self.runCmd(mysqlCmds)
 | |
|       print 'TemplateId is : %s' % templateId
 | |
|     except Exception, e:
 | |
|       err = '''Encountering an error when executing mysql script\n%s''' % str(e)
 | |
|       self.errorAndExit(err)
 | |
|     return templateId
 | |
| 
 | |
|   def fetchTemplateDetails(self):
 | |
|     mysqlQuery = "select max(id) from cloud.vm_template where type = 'SYSTEM' and hypervisor_type = '%s' and removed is null"
 | |
|     ht = None
 | |
|     hypervisorInfo = self.dictionary[self.hypervisor]
 | |
|     ht = hypervisorInfo[0]
 | |
|     self.templatesuffix = hypervisorInfo[1]
 | |
| 
 | |
|     self.template = int(self.runMysql(mysqlQuery%ht))
 | |
| 
 | |
|   def downloadTemplate(self):
 | |
|     self.systemvmtemplatepath = self.templateName + "." + self.fileextension
 | |
|     print 'Downloading template from %s To %s' % (self.systemvmtemplateurl, self.systemvmtemplatepath)
 | |
|     try:
 | |
|       templateFileDownloadUrl = urllib.urlretrieve(self.systemvmtemplateurl, self.systemvmtemplatepath, reporthook=self.report)
 | |
|     except Exception:
 | |
|       self.errorAndExit("Failed to download template file from %s" % self.systemvmtemplateurl)
 | |
| 
 | |
|   def report(tmp, blocknr, blocksize, size):
 | |
|     current = blocknr*blocksize
 | |
|     sys.stdout.write("\rDownloading completed: {0:.2f}%".format(100.0*current/size))
 | |
| 
 | |
|   def installTemplate(self):
 | |
|     destDir = self.mountpoint + os.sep + "template" + os.sep + "tmpl" + os.sep + "1" + os.sep + str(self.template)
 | |
|     self.destDir = destDir
 | |
|     print 'The desination Directory is : %s' % destDir
 | |
|     try:
 | |
|       if self.forcecleanup:
 | |
|         if os.path.exists(destDir):
 | |
|           shutil.rmtree(destDir)
 | |
|       if not os.path.exists(destDir):
 | |
|         os.makedirs(destDir)
 | |
|     except Exception, e:
 | |
|       self.errorAndExit('Failed to create directories on the mounted path.. %s' % str (e))
 | |
|     print 'Installing Template to : %s' % destDir
 | |
|     tmpFile = self.templateName + "." + "tmp"
 | |
|     self.uncompressFile(tmpFile)
 | |
|     print 'Moving the decompressed file to destination directory %s... which could take a long time, please wait' % destDir
 | |
|     shutil.move(tmpFile, destDir + os.sep + self.templateName)
 | |
| 
 | |
|   def uncompressFile(self, fileName):
 | |
|     print 'Uncompressing the file %s... which could take a long time, please wait' % self.systemvmtemplatepath
 | |
|     if self.fileextension == 'gz':
 | |
|       compressedFile = gzip.GzipFile(self.systemvmtemplatepath, 'rb')
 | |
|       decompressedData = compressedFile.read()
 | |
|       compressedFile.close()
 | |
|       decompressedFile = file(fileName, 'wb')
 | |
|       decompressedFile.write(decompressedData)
 | |
|       decompressedFile.close()
 | |
|     elif self.fileextension == 'bz2':
 | |
|       compressedFile = bz2.BZ2File(self.systemvmtemplatepath)
 | |
|       decompressedData = compressedFile.read()
 | |
|       compressedFile.close()
 | |
|       decompressedFile = file(fileName, 'wb')
 | |
|       decompressedFile.write(decompressedData)
 | |
|       decompressedFile.close()
 | |
|       print ''
 | |
|     elif self.fileextension == 'zip':
 | |
|       zippedFile = zipfile.ZipFile(self.systemvmtemplatepath, 'r')
 | |
|       zippedFiles = zippedFile.namelist()
 | |
|       compressedFile = zippedFiles[0]
 | |
|       decompressedData = zippedFile.read(compressedFile)
 | |
|       decompressedFile = file(fileName, 'wb')
 | |
|       decompressedFile.write(decompressedData)
 | |
|       decompressedFile.close()
 | |
|       zippedFile.close()
 | |
|       print ''
 | |
|     else:
 | |
|       self.errorAndExit('Not supported file type %s to decompress' % self.fileextension)
 | |
|     self.fileSize = os.path.getsize(fileName)
 | |
| 
 | |
|   def writeProperties(self):
 | |
|     propertiesFile = file(self.destDir + os.sep + 'template.properties', 'wb')
 | |
|     propertiesFile.write('filename=%s\n'%self.templateName)
 | |
|     propertiesFile.write('description=SystemVM Template\n')
 | |
|     propertiesFile.write('checksum=\n')
 | |
|     propertiesFile.write('hvm=false\n')
 | |
|     propertiesFile.write('size=%s\n'%str(self.fileSize))
 | |
|     propertiesFile.write('%s=true\n'%self.templatesuffix)
 | |
|     propertiesFile.write('id=%s\n'%str(self.template))
 | |
|     propertiesFile.write('public=true\n')
 | |
|     propertiesFile.write('%s.filename=%s\n'%(self.templatesuffix, self.templateName))
 | |
|     propertiesFile.write('uniquename=routing-%s\n'%str(self.template))
 | |
|     propertiesFile.write('%s.virtualsize=%s\n'%(self.templatesuffix, str(self.fileSize)))
 | |
|     propertiesFile.write('virtualsize=%s\n'%str(self.fileSize))
 | |
|     propertiesFile.write('%s.size=%s'%(self.templatesuffix, str(self.fileSize)))
 | |
| 
 | |
|     propertiesFile.close()
 | |
| 
 | |
|   def run(self):
 | |
|     try:
 | |
|       self.parseOptions()
 | |
|       self.populateOptions()
 | |
|       self.fetchTemplateDetails()
 | |
|       randomUUID = uuid.uuid1()
 | |
|       self.templateName = str(randomUUID) + "." + self.templatesuffix
 | |
|       if self.args.systemvmtemplateurl:
 | |
|         self.downloadTemplate()
 | |
|       self.installTemplate()
 | |
|       self.writeProperties()
 | |
|     finally:
 | |
|       print ''
 | |
|     print ''
 | |
|     print "CloudStack has successfully installed system template"
 | |
|     print ''
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|    o = InstallSysTemplate()
 | |
|    o.run()
 |