class PCCEC2Connection(EC2Connection): logger = IaasLogger() useProxy = False def connect(self, host=None, port=None, base_url = None): # prefer the attribute base_url if its set or sent connection = None secure = self.secure if getattr(self, 'base_url', None) and base_url == None: (host, port, secure, self.request_path) = self._tuple_from_url(self.base_url) elif base_url != None: (host, port, secure, self.request_path) = self._tuple_from_url(base_url) else: host = host or self.host port = port or self.port kwargs = {'host': host, 'port': int(port)} if not self.useProxy: #self.logger.debug("**************** OFF PROXY !") connection = self.conn_classes[secure](**kwargs) elif proxy_port is None or proxy_port == "": #self.logger.debug("**************** NON PROXY !") connection = self.conn_classes[secure](**kwargs) else: #self.logger.debug("**************** ON PROXY !") connection = self.conn_classes[secure](proxy_host, proxy_port) if proxy_user is not None and proxy_user != "": headers = {"Proxy-Authorization":"Basic " + base64.b64encode(proxy_user + ":" + proxy_pass)} kwargs["headers"] = headers connection.set_tunnel(**kwargs) self.connection = connection
class PropertiesReader(dict): logger = IaasLogger() prop = re.compile(r"([\w. ]+)\s*=\s*(.*)") src = os.environ.get('PCC_CONFIG_HOME', "") + "/config.properties" def __init__(self): self.loadConfig() def loadFileData(self): data = "" try: file = open(self.src, 'r') for line in file: if not line.startswith("#"): data = data + line file.close() except IOError: pass return data def loadConfig(self): for (key, val) in self.prop.findall(self.loadFileData()): self[key.strip()] = val.rstrip()
class CloudStackOtherController(object): logger = IaasLogger() client = None conn = None platforminfo = None def __init__(self, platforminfo, cs2iaasclient, conn): self.client = cs2iaasclient self.conn = conn self.platforminfo = platforminfo def describeSnapshot(self, snapshotId): snapshot = self.client.describeSnapshot(snapshotId) return snapshot def describeSnapshots(self): snapshots = self.client.describeSnapshots() return snapshots def createSnapshot(self, volumeNo): tableCSVOL = self.conn.getTable("CLOUDSTACK_VOLUME") csVolumes = self.conn.selectOne(tableCSVOL.select(tableCSVOL.c.VOLUME_NO==volumeNo)) volumeId = csVolumes['VOLUME_ID'] snapshot = self.client.createSnapshot(volumeId) tableCSSNP = self.conn.getTable("CLOUDSTACK_SNAPSHOT") sql = tableCSSNP.insert({"SNAPSHOT_NO":None, "SNAPSHOT_ID":snapshot["id"], "FARM_NO":csVolumes["FARM_NO"], "PLATFORM_NO":csVolumes["PLATFORM_NO"], "CREATE_DATE":snapshot["created"], "VOLUMEID":volumeId, }) self.conn.execute(sql) return snapshot["id"] def deleteSnapshot(self, snapshotNo): tableCSSNP = self.conn.getTable("CLOUDSTACK_SNAPSHOT") csSnap = self.conn.selectOne(tableCSSNP.select(tableCSSNP.c.SNAPSHOT_NO==snapshotNo)) self.client.deleteSnapshot(csSnap["SNAPSHOT_ID"]) def getPasswordData(self, instanceNo): tableCSINS = self.conn.getTable("CLOUDSTACK_INSTANCE") csInstance = self.conn.selectOne(tableCSINS.select(tableCSINS.c.INSTANCE_NO==instanceNo)) passwd = self.client.getPasswordData(csInstance["INSTANCE_ID"]) #改行コードを抜く為改行コードでスプリット passwdArray = passwd.splitlines() rtPassword = "" for passline in passwdArray: rtPassword = rtPassword + passline return rtPassword
def iaasSelect(user, platformNo, isLb = False): logger = IaasLogger() conn = MysqlConnector(user) '''プラットフォームを判断しユーザー情報を取得する ''' platforminfo = getPlatformProperty(platformNo) platformType = platforminfo["platformType"] platformName = platforminfo["platformName"] logger.info(u" Platform::No[%s]::種別[%s]::名称[%s]" % (str(platformNo), platformType, platformName)) #ユーザー取得 userTable = conn.getTable("USER") userinfo = conn.selectOne(userTable.select(userTable.c.USER_NO==user)) iaasController = None if platformType == "aws": if platformName == "eucalyptus": return #EC2 およびユーカリ #AWS_CERTIFICATE 取得 certificateTable = conn.getTable("AWS_CERTIFICATE") certificate = conn.selectOne(certificateTable.select(and_(certificateTable.c.USER_NO==user, certificateTable.c.PLATFORM_NO==platformNo))) accessInfo = {"ACCESS_ID": str(certificate["AWS_ACCESS_ID"]), "SECRET_KEY": str(certificate["AWS_SECRET_KEY"]), "USER": user, "USER_NAME": userinfo["USERNAME"]} iaasController = EC2Controller(conn, accessInfo, platforminfo, isLb) elif platformType == "vmware": #vmware pass elif platformType == "nifty": #nifty pass elif platformType == "cloudstack": #CloudStack certificateTable = conn.getTable("CLOUDSTACK_CERTIFICATE") certificate = conn.selectOne(certificateTable.select(and_(certificateTable.c.ACCOUNT==user, certificateTable.c.PLATFORM_NO==platformNo))) accessInfo = {"ACCESS_ID": str(certificate["CLOUDSTACK_ACCESS_ID"]), "SECRET_KEY": str(certificate["CLOUDSTACK_SECRET_KEY"]), "USER": user, "USER_NAME": userinfo["USERNAME"]} iaasController = CloudStackController(conn, accessInfo, platforminfo) else: raise IaasException("PlatformError", platformNo) return iaasController
class OpenStackOtherController(object): logger = IaasLogger() client = None conn = None platforminfo = None def __init__(self, platforminfo, openstackiaasclient, conn): self.client = openstackiaasclient self.conn = conn self.platforminfo = platforminfo
class AzureIaasClient: logger = IaasLogger() platformNo = None username = None sms = None def __init__(self, platforminfo, username, subscription, certificate, conn): self.platformNo = platforminfo["platformNo"] self.username = username # XXX: proxyのコード # 証明書ファイルを作成 # XXX: テンポラリファイルの削除をどうするか要検討 fd = tempfile.NamedTemporaryFile(prefix='pccazurecert', delete=False) fd.writelines(certificate) fd.close() # 接続用オブジェクトの生成 self.certPath = fd.name self.subscription = subscription self.sms = ServiceManagementService(subscription, self.certPath) self.conn = conn def waitAsyncOperationFinished(self, asyncOperation, flg=None): requestId = asyncOperation.request_id while True: # XXX: socket.error: [Errno 104] Connection reset by peer が発生したことがあるので、対処必要 try: operation = self.sms.get_operation_status(requestId) self.logger.debug(' Asynchronous Request ID: %s, Status: %s' % \ (operation.id, operation.status)) if operation.status == 'InProgress': if flg == 'del': time.sleep(5) else: time.sleep(10) continue elif operation.status == 'Succeeded': break else: self.logger.error('%s' % (operation.error.code)) self.logger.error('%s' % (operation.error.message)) break except: self.logger.error(traceback.format_exc()) return return operation.status def generateOSHardDiskConfig(self, mediaLink, imageName): return OSVirtualHardDisk(imageName, mediaLink) def generateLinuxConfig(self, hostName, userName, userPassword, customData): disableSshPasswordAuthentication = False return LinuxConfigurationSet(hostName, userName, userPassword, \ disableSshPasswordAuthentication, custom_data=base64.b64encode(customData)) def generateWindowsConfig(self, hostName, userName, userPassword, customData): resetPasswordOnFirstLogon = False enableAutomaticUpdates = False timeZone = 'Tokyo Standard Time' windowsConfig = WindowsConfigurationSet(hostName, userName, userPassword, \ resetPasswordOnFirstLogon, enableAutomaticUpdates, timeZone, custom_data=base64.b64encode(customData)) windowsConfig.domain_join = None return windowsConfig def generateNetworkConfig(self, subnetID): network = ConfigurationSet() network.configuration_set_type = 'NetworkConfiguration' network.subnet_names.append(subnetID) return network def getOsImage(self, imageName): # XXX: なぜか、WindowsAzureConflictErrorが発生することがある osImages = self.sms.list_os_images() for osImage in osImages: # XXX: カテゴリが"User"の場合、ストレージアカウントの考慮も必要 if osImage.name == imageName: return osImage # 名前の一致するイメージが存在しない return None def identifyImageOsType(self, imageName): osImage = self.getOsImage(imageName) if osImage is None: # 名前の一致するイメージが存在しない return None return osImage.os def _getStorageAccountKey(self, storageAccount): # ストレージアカウントのキーを取得 res = self.sms.get_storage_account_keys(storageAccount) return res.storage_service_keys.primary def _getBlobFromMediaLink(self, blobService, mediaLink): # コンテナ一覧を取得 containerList = blobService.list_containers() for container in containerList: # コンテナに含まれるBlob一覧を取得 blobList = blobService.list_blobs(container.name) for blob in blobList: # URIから、先頭のhttp*://を取り除いた文字列を比較 if blob.url.split('://')[1] == mediaLink.split('://')[1]: return (container, blob) else: return (None, None) def _deleteBlob(self, storageAccount, mediaLink): primary = self._getStorageAccountKey(storageAccount) # BlobServiceオブジェクトを作成 blobService = BlobService(storageAccount, primary) (container, blob) = self._getBlobFromMediaLink(blobService, mediaLink) rs = blobService.delete_blob(container_name=container.name, blob_name=blob.name) try: updatedBlob = blobService.get_blob_properties( container_name=container.name, blob_name=blob.name) except WindowsAzureMissingResourceError as e: return True return False def _leaseBlob(self, storageAccount, mediaLink): primary = self._getStorageAccountKey(storageAccount) # BlobServiceオブジェクトを作成 blobService = BlobService(storageAccount, primary) (container, blob) = self._getBlobFromMediaLink(blobService, mediaLink) prop = blob.properties # Lease StatusがlockedだったらBlobのリース解放を試みる if prop.lease_status == 'locked': # unlockedの時に実行すると、 azure.WindowsAzureConflictError res = blobService.lease_blob(container_name=container.name, blob_name=blob.name, x_ms_lease_action='break') # (成功すると?){}が返ってくる updatedBlob = blobService.get_blob_properties( container_name=container.name, blob_name=blob.name) def _existDisk(self, osHardDiskName): diskList = self.sms.list_disks() for disk in diskList: if disk.name == osHardDiskName: return True else: return False def _deleteDisk(self, osHardDiskName): self.logger.debug("Blob of OS Disk deleting...(%s)" % osHardDiskName) try: # 指定されたデータまたはオペレーティング システム ディスクをイメージ リポジトリから削除 # ディスクに関連付けられた BLOB も削除 asyncOperation = self.sms.delete_disk(osHardDiskName, True) except WindowsAzureMissingResourceError as e: # クラウドサービス/デプロイメントが存在しない(_ERROR_NOT_FOUND) self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000916", [osHardDiskName]) except WindowsAzureError as e: # XXX: Blobがロックされている場合を想定しているが、他にもこのエラーにかかる可能性あり self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000916", [osHardDiskName]) except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000916", [osHardDiskName]) else: operationStatus = self.waitAsyncOperationFinished(asyncOperation, flg='del') if operationStatus != 'Succeeded': raise IaasException("EPROCESS-000916", [osHardDiskName]) self.logger.debug("Blob of OS Disk deleted.(%s)" % osHardDiskName) return operationStatus def getOsHardDisk(self, cloudService, roleName): deploymentName = cloudService # OS Virtual Hard Diskの情報は、get_deployment_by_slotでは取得できない。get_roleを使用する。 try: systemProperty = self.sms.get_role(cloudService, deploymentName, roleName) except WindowsAzureMissingResourceError as e: # クラウドサービス/デプロイメントが存在しない(_ERROR_NOT_FOUND) return None else: return systemProperty.os_virtual_hard_disk.disk_name def getMediaLink(self, cloudService, roleName): deploymentName = cloudService # OS Virtual Hard Diskの情報は、get_deployment_by_slotでは取得できない。get_roleを使用する。 try: systemProperty = self.sms.get_role(cloudService, deploymentName, roleName) except WindowsAzureMissingResourceError as e: # クラウドサービス/デプロイメントが存在しない(_ERROR_NOT_FOUND) return None else: return systemProperty.os_virtual_hard_disk.media_link def getDiskNameAttachedTo(self, cloudService, roleName, lun): deploymentName = cloudService try: systemProperty = self.sms.get_data_disk(cloudService, deploymentName, roleName, lun) except WindowsAzureMissingResourceError as e: # クラウドサービス/デプロイメントが存在しない(_ERROR_NOT_FOUND) return None else: return systemProperty.disk_name def createAddDataDisk(self, cloudService, roleName, mediaLink, size, lun): deploymentName = cloudService # TODO: アタッチコンフリクト問題に暫定的に対応 for i in range(0, 6): try: asyncOperation = self.sms.add_data_disk(service_name = cloudService, \ deployment_name = deploymentName, role_name = roleName, \ lun = lun, host_caching = 'ReadOnly', media_link = mediaLink, \ disk_label = None, disk_name = None, logical_disk_size_in_gb = size, \ #disk_label = '%sL' % (diskName), disk_name = '%sN' % (diskName), logical_disk_size_in_gb = size, \ source_media_link = None) except WindowsAzureMissingResourceError as e: # クラウドサービス/デプロイメントが存在しない(_ERROR_NOT_FOUND) self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000915", [roleName]) except WindowsAzureConflictError as e: # TODO: アタッチコンフリクト問題に暫定的に対応 if i == 5: # 既に存在する self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000915", [roleName]) else: time.sleep(30) continue except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000915", [roleName]) else: operationStatus = self.waitAsyncOperationFinished( asyncOperation) if operationStatus != 'Succeeded': raise IaasException("EPROCESS-000915", [roleName]) return operationStatus def addDataDisk(self, cloudService, roleName, diskName, lun): deploymentName = cloudService # TODO: アタッチコンフリクト問題に暫定的に対応 for i in range(0, 6): try: asyncOperation = self.sms.add_data_disk(service_name = cloudService, \ deployment_name = deploymentName, role_name = roleName, \ lun = lun, host_caching = 'ReadOnly', media_link = None, \ disk_label = None, disk_name = diskName, logical_disk_size_in_gb = None, \ #disk_label = '%sL' % (diskName), disk_name = '%sN' % (diskName), logical_disk_size_in_gb = size, \ source_media_link = None) except WindowsAzureMissingResourceError as e: # クラウドサービス/デプロイメントが存在しない(_ERROR_NOT_FOUND) self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000910", [roleName, diskName]) except WindowsAzureConflictError as e: # TODO: アタッチコンフリクト問題に暫定的に対応 if i == 5: # 既に存在する self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000910", [roleName, diskName]) else: time.sleep(30) continue except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000910", [roleName, diskName]) else: operationStatus = self.waitAsyncOperationFinished( asyncOperation) if operationStatus != 'Succeeded': raise IaasException("EPROCESS-000910", [roleName, diskName]) return operationStatus def deleteDataDisk(self, cloudService, roleName, diskName, lun): deploymentName = cloudService # TODO: デタッチコンフリクト問題に暫定的に対応 for i in range(0, 6): try: asyncOperation = self.sms.delete_data_disk(service_name = cloudService, \ deployment_name = deploymentName, role_name = roleName, \ lun = lun) except WindowsAzureMissingResourceError as e: # クラウドサービス/デプロイメントが存在しない(_ERROR_NOT_FOUND) self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000911", [roleName, diskName]) except WindowsAzureConflictError as e: # TODO: アタッチコンフリクト問題に暫定的に対応 if i == 5: # 既に存在する self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000911", [roleName, diskName]) else: time.sleep(30) continue except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000911", [roleName, diskName]) else: operationStatus = self.waitAsyncOperationFinished( asyncOperation) if operationStatus != 'Succeeded': raise IaasException("EPROCESS-000911", [roleName, diskName]) return operationStatus def getVirtualMachineType(self, cloudService, roleName): try: systemProperty = self.sms.get_deployment_by_slot( cloudService, 'production') except WindowsAzureMissingResourceError as e: # クラウドサービス/デプロイメントが存在しない(_ERROR_NOT_FOUND) return None else: for role in systemProperty.role_instance_list: if role.role_name == roleName: # インスタンスが見つかったらインスタンスサイズを返す return role.instance_size # インスタンスが見つからない場合はNoneを返す return None def getVirtualMachineIpAddress(self, cloudService, roleName): try: systemProperty = self.sms.get_deployment_by_slot( cloudService, 'production') except WindowsAzureMissingResourceError as e: # クラウドサービス/デプロイメントが存在しない(_ERROR_NOT_FOUND) return None else: for role in systemProperty.role_instance_list: if role.role_name == roleName: # インスタンスが見つかったらステータスを返す return role.ip_address # インスタンスが見つからない場合はNoneを返す return None def updateVirtualMachineType(self, cloudService, roleName, roleSize, networkConfig, \ availabilitySet): deploymentName = cloudService try: asyncOperation = self.sms.update_role( \ service_name=cloudService, deployment_name=deploymentName, \ role_name=roleName, role_size=roleSize, network_config=networkConfig, \ availability_set_name=availabilitySet) except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) return None else: operationStatus = self.waitAsyncOperationFinished(asyncOperation) # 異常系テストコード #operationStatus = 'Failed' if operationStatus != 'Succeeded': raise IaasException("EPROCESS-000913", [roleName]) return roleSize def getVirtualMachineStatus(self, cloudService, roleName): # ステータスの取得に失敗した場合はNoneを返す。 try: systemProperty = self.sms.get_deployment_by_slot( cloudService, 'production') except WindowsAzureMissingResourceError as e: # クラウドサービス/デプロイメントが存在しない(_ERROR_NOT_FOUND) return None # XXX: socket.error: [Errno 104] Connection reset by peer が発生したことがあるので、対処必要 else: for role in systemProperty.role_instance_list: if role.role_name == roleName: # インスタンスが見つかったらステータスを返す return role.instance_status # インスタンスが見つからない場合はNoneを返す return None def waitVirtualMachineStatus(self, cloudService, roleName, expectedStatus): # XXX: タイムアウト実装必要 while True: status = self.getVirtualMachineStatus(cloudService, roleName) self.logger.debug(' Virtual machine: %s, Status: %s' % (roleName, status)) if status == expectedStatus: return status elif status == 'ProvisioningFailed': # 失敗 return status elif status is None: return status else: time.sleep(10) continue def waitVirtualMachineStatusStoppedVM(self, cloudService, roleName): return self.waitVirtualMachineStatus(cloudService, roleName, 'StoppedVM') def waitVirtualMachineStatusReadyRole(self, cloudService, roleName): return self.waitVirtualMachineStatus(cloudService, roleName, 'ReadyRole') def listVirtualMachines(self, cloudService): try: systemProperty = self.sms.get_deployment_by_slot( cloudService, 'production') except WindowsAzureMissingResourceError as e: # クラウドサービス/デプロイメントが存在しない(_ERROR_NOT_FOUND) return None else: return systemProperty.role_instance_list def getCloudServiceStatus(self, cloudService): try: systemProperty = self.sms.get_hosted_service_properties( cloudService) except WindowsAzureMissingResourceError as e: # クラウドサービスが存在しない(_ERROR_NOT_FOUND) return None else: # クラウドサービスが存在する場合はstatusを返す return systemProperty.hosted_service_properties.status def waitCloudServiceStatusCreated(self, cloudService): while True: status = self.getCloudServiceStatus(cloudService) if status == 'Creating': time.sleep(10) continue elif status is None: return None else: return status def createCloudService(self, cloudService, affinityGroup=None): cloudServiceLabel = cloudService cloudServiceDesc = cloudService try: # クラウドサービス作成 res = self.sms.create_hosted_service(service_name=cloudService, \ label=cloudServiceLabel, description=cloudServiceDesc, \ affinity_group=affinityGroup) if res is not None: # エラー(その他) self.logger.error(traceback.format_exc()) raise except WindowsAzureConflictError as e: # 既に存在する self.logger.error(traceback.format_exc()) except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) raise return self.waitCloudServiceStatusCreated(cloudService) def getStorageAccountStatus(self, storageAccount): try: systemProperty = self.sms.get_storage_account_properties( storageAccount) except WindowsAzureMissingResourceError as e: # ストレージアカウントが存在しない(_ERROR_NOT_FOUND) return None else: # ストレージアカウントが存在する場合はstatusを返す return systemProperty.storage_service_properties.status def createStorageAccount(self, storageAccount, affinityGroup=None): storageAccountLabel = storageAccount storageAccountDesc = storageAccount try: # ストレージアカウント作成 asyncOperation = self.sms.create_storage_account(service_name=storageAccount, \ description=storageAccountDesc, label=storageAccountLabel, \ affinity_group=affinityGroup) except WindowsAzureConflictError as e: # 既に存在する self.logger.error(traceback.format_exc()) except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) raise else: operationStatus = self.waitAsyncOperationFinished(asyncOperation) # 異常系テストコード #operationStatus = 'Failed' if operationStatus != 'Succeeded': raise IaasException("EPROCESS-000917", [storageAccount]) return self.getStorageAccountStatus(storageAccount) def getProductionDeploymentStatus(self, cloudService): try: systemProperty = self.sms.get_deployment_by_slot( cloudService, 'production') except WindowsAzureMissingResourceError as e: # クラウドサービス/デプロイメントが存在しない(_ERROR_NOT_FOUND) return None else: return systemProperty.status def createVirtualMachineDeployment(self, cloudService, instanceName, osConfig, osHardDisk, \ instanceType, networkConfig, networkName, availabilitySet): deploymentName = cloudService deploymentLabel = deploymentName try: asyncOperation = self.sms.create_virtual_machine_deployment( \ service_name=cloudService, deployment_name=deploymentName, \ deployment_slot='production', label=deploymentLabel, \ role_name=instanceName, system_config=osConfig, \ os_virtual_hard_disk=osHardDisk, role_size=instanceType, \ network_config=networkConfig, availability_set_name=availabilitySet, \ virtual_network_name=networkName) except WindowsAzureConflictError as e: # 既に存在する self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000903", [instanceName]) except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000903", [instanceName]) else: operationStatus = self.waitAsyncOperationFinished(asyncOperation) # 異常系テストコード #operationStatus = 'Failed' if operationStatus != 'Succeeded': raise IaasException("EPROCESS-000903", [instanceName]) return self.waitVirtualMachineStatusReadyRole(cloudService, instanceName) #return self.getVirtualMachineStatus(cloudService, instanceName) def addRole(self, cloudService, instanceName, osConfig, osHardDisk, \ instanceType, networkConfig, networkName, availabilitySet): # XXX: ネットワーク名が既存デプロイメントのネットワークと一致することを確認すべきか。 deploymentName = cloudService try: asyncOperation = self.sms.add_role( \ service_name=cloudService, deployment_name=deploymentName, \ role_name=instanceName, system_config=osConfig, \ os_virtual_hard_disk=osHardDisk, role_size=instanceType, \ network_config=networkConfig, availability_set_name=availabilitySet) except WindowsAzureConflictError as e: # 既に存在する self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000905", [instanceName]) except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000905", [instanceName]) else: operationStatus = self.waitAsyncOperationFinished(asyncOperation) # 異常系テストコード #operationStatus = 'Failed' if operationStatus != 'Succeeded': raise IaasException("EPROCESS-000905", [instanceName]) return self.waitVirtualMachineStatusReadyRole(cloudService, instanceName) #return self.getVirtualMachineStatus(cloudService, instanceName) def startVirtualMachine(self, cloudService, roleName): # XXX: クラウドサービス名=デプロイメント名を前提 deploymentName = cloudService try: asyncOperation = self.sms.start_role( \ service_name=cloudService, deployment_name=deploymentName, \ role_name=roleName) #except WindowsAzureConflictError as e: # # 既に存在する # self.logger.error(traceback.format_exc()) except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000905", [roleName]) else: operationStatus = self.waitAsyncOperationFinished(asyncOperation) # 異常系テストコード #operationStatus = 'Failed' if operationStatus != 'Succeeded': raise IaasException("EPROCESS-000905", [roleName]) return self.waitVirtualMachineStatusReadyRole(cloudService, roleName) def stopVirtualMachine(self, cloudService, roleName): # XXX: クラウドサービス名=デプロイメント名を前提 deploymentName = cloudService try: asyncOperation = self.sms.shutdown_role( \ service_name=cloudService, deployment_name=deploymentName, \ role_name=roleName) #except WindowsAzureConflictError as e: # # 既に存在する # self.logger.error(traceback.format_exc()) except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) raise IaasException("EPROCESS-000907", [roleName]) else: # XXX: 非同期操作が Failed したことがあった。Failしたあと、VMの状態がStoppedVMになるまで待つのは不適切。 # XXX: 非同期操作は Failed になったのに、最終的にVMは停止したことがあった。ただし、しばらくの間、VMのstatusはReadyRoleだった。 operationStatus = self.waitAsyncOperationFinished(asyncOperation) # 異常系テストコード #operationStatus = 'Failed' if operationStatus != 'Succeeded': raise IaasException("EPROCESS-000907", [roleName]) return self.waitVirtualMachineStatusStoppedVM(cloudService, roleName) def _deleteDeployment(self, cloudService, roleName, \ instanceNo, farmNo, instanceInfoInstanceName): deploymentName = cloudService try: # 仮想マシン、オペレーティング システム ディスク、 # 接続されたデータ ディスク、およびディスクの元の BLOB もストレージから削除 asyncOperation = self.sms.delete_deployment( \ service_name=cloudService, deployment_name=deploymentName) # 異常系テストコード #raise Exception except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) self.conn.error(farmNo, None, None, instanceNo, \ instanceInfoInstanceName, "AzureInstanceDeleteFail",["AZURE", roleName, '']) raise IaasException("EPROCESS-000904", [roleName]) else: operationStatus = self.waitAsyncOperationFinished(asyncOperation, flg='del') return operationStatus def _deleteRole(self, cloudService, roleName, \ instanceNo, farmNo, instanceInfoInstanceName): deploymentName = cloudService try: # 仮想マシン、オペレーティング システム ディスク、 # 接続されたデータ ディスク、およびディスクの元の BLOB もストレージから削除 asyncOperation = self.sms.delete_role( \ service_name=cloudService, deployment_name=deploymentName, \ role_name=roleName) # 異常系テストコード #raise Exception except Exception: # 予期せぬ例外 self.logger.error(traceback.format_exc()) self.conn.error(farmNo, None, None, instanceNo, \ instanceInfoInstanceName, "AzureInstanceDeleteFail",["AZURE", roleName, '']) raise IaasException("EPROCESS-000904", [roleName]) else: operationStatus = self.waitAsyncOperationFinished(asyncOperation, flg='del') return operationStatus def deleteVirtualMachine(self, cloudService, instanceName, storageAccount, \ instanceNo, farmNo, instanceInfoInstanceName): mediaLink = self.getMediaLink(cloudService, instanceName) self.logger.debug( ' Virtual Machine(role or deployment) %s is going to be deleted' % (instanceName)) self.logger.debug(' Media Link: %s' % (mediaLink)) roleList = self.listVirtualMachines(cloudService) if roleList is None: return None if len(roleList) == 1: # 最後のVMなので、Delete Deploymentを使う必要あり status = self._deleteDeployment(cloudService, instanceName, \ instanceNo, farmNo, instanceInfoInstanceName) else: status = self._deleteRole(cloudService, instanceName, \ instanceNo, farmNo, instanceInfoInstanceName) # 異常系テストコード #status = 'Failed' if status != 'Succeeded': self.logger.debug(' Async job did not succeed. Status: %s' % (status)) self.conn.error(farmNo, None, None, instanceNo, \ instanceInfoInstanceName, "AzureInstanceDeleteFail",["AZURE", instanceName, status]) raise IaasException("EPROCESS-000904", [instanceName]) return status def createVirtualMachine(self, cloudService, instanceName, osConfig, osHardDisk, \ instanceType, networkConfig, networkName, availabilitySet): deploymentStatus = self.getProductionDeploymentStatus(cloudService) if deploymentStatus is None: return self.createVirtualMachineDeployment( cloudService, instanceName, osConfig, osHardDisk, instanceType, networkConfig, networkName, availabilitySet) else: # XXX: Running以外の時の扱いを決める必要あり return self.addRole(cloudService, instanceName, osConfig, osHardDisk, instanceType, networkConfig, networkName, availabilitySet) def deleteDataVolume(self, storageAccount, mediaLink): self._leaseBlob(storageAccount, mediaLink) time.sleep(120) #XXX: 下記エラーへの対処 #WindowsAzureError: Unknown error (Bad Request) #<Error xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Code>BadRequest</Code><Message>A disk with name cloud-pccdev10-azure-dev10-user01_AZURE-J02-0-201311181315360171 is currently in use by virtual machine azure-dev10-user01_AZURE-J02 running within hosted service cloud-pccdev10, deployment cloud-pccdev10.</Message></Error> self._deleteBlob(storageAccount, mediaLink) return def deleteOSandDataDisk(self, osHardDiskName, storageAccount, mediaLink): accessKeys = self.sms.get_storage_account_keys(storageAccount) accessKey = accessKeys.storage_service_keys.primary if (osHardDiskName == None): parameter = self.subscription + ' ' + self.certPath + ' ' + storageAccount + ' ' + accessKey + ' ' + mediaLink + ' ' else: parameter = self.subscription + ' ' + self.certPath + ' ' + storageAccount + ' ' + accessKey + ' ' + mediaLink + ' ' + osHardDiskName dir = os.path.dirname(__file__) self.logger.info( 'called deleteOSandDataDisk process. python %s/azuredeleteOSandDataDisk.py %s &' % (dir, parameter)) os.system('python %s/azuredeleteOSandDataDisk.py %s &' % (dir, parameter)) return def listVirtualNetworkSites(self): try: networks = self.sms.list_virtual_network_sites() except WindowsAzureMissingResourceError as e: # ネットワーク情報が存在しない(_ERROR_NOT_FOUND) return None else: return networks
class CloudStackInstanceController(object): client = None conn = None logger = IaasLogger() platforminfo = None def __init__(self, platforminfo, ec2iaasclient, conn): self.client = ec2iaasclient self.conn = conn self.platforminfo = platforminfo def startInstance(self, instanceNo): #AWS_INSTANCE 取得 tableCSINS = self.conn.getTable("CLOUDSTACK_INSTANCE") csInstance = self.conn.selectOne(tableCSINS.select(tableCSINS.c.INSTANCE_NO==instanceNo)) #PCC_INSTANCE 取得 tableINS = self.conn.getTable("INSTANCE") pccInstance = self.conn.selectOne(tableINS.select(tableINS.c.INSTANCE_NO==instanceNo)) #イメージの取得 再考の余地あり image = getImage(pccInstance["IMAGE_NO"]) # if isEmpty(csInstance["INSTANCE_ID"]): #インスタンスの作成 self.run(instanceNo, csInstance, pccInstance, image) #winodowsなら if (startsWithIgnoreCase(image["os"], "windows")): #INSTANCE_ID取得の為、CLOUDSTACK_INSTANCE 再取得 csInstance = self.conn.selectOne(tableCSINS.select(tableCSINS.c.INSTANCE_NO==instanceNo)) self.client.getPasswordData(csInstance["INSTANCE_ID"]) else: # インスタンスが停止中でない場合はスキップ if (csInstance["STATE"] != "Stopped"): return; # インスタンスの起動 self.start(instanceNo, csInstance, pccInstance) def stopInstance(self, instanceNo): #AWS_INSTANCE 取得 tableCSINS = self.conn.getTable("CLOUDSTACK_INSTANCE") csInstance = self.conn.selectOne(tableCSINS.select(tableCSINS.c.INSTANCE_NO==instanceNo)) #PCC_INSTANCE 取得 tableINS = self.conn.getTable("INSTANCE") pccInstance = self.conn.selectOne(tableINS.select(tableINS.c.INSTANCE_NO==instanceNo)) # インスタンスIDがない場合は確認する if (isEmpty(csInstance["INSTANCE_ID"])): #起動ミス対策 nodes = self.client.describeInstances(name = pccInstance["INSTANCE_NAME"]) if not nodes or len(nodes) == 0: #インスタンスが存在しない場合 return; if len(nodes) >= 1: #FQDNを比較する for node in nodes: if pccInstance["FQDN"] == node.extra["displayname"]: #起動をミスったインスタンスを発見した場合 #ID情報を更新 csInstance["INSTANCE_ID"] = node.id sql = tableCSINS.update(tableCSINS.c.INSTANCE_NO ==csInstance["INSTANCE_NO"], values=csInstance) self.conn.execute(sql) # インスタンスの停止 self.stop(instanceNo, csInstance, pccInstance) #################################################################################### #---------------------ローカル------------------------------------------------------ #################################################################################### def run(self, instanceNo, csInstance, pccInstance, image): #serviceoffering名称をIDへ変換 serviceofferings = self.client.describeServiceOfferings() #デフォルトは最初にHitするID serviceofferingid = serviceofferings[0]["id"] for serviceoffering in serviceofferings: if csInstance["INSTANCE_TYPE"] == serviceoffering["name"]: serviceofferingid = serviceoffering["id"] availabilityZone = None if (isNotEmpty(csInstance["ZONEID"])): availabilityZone = csInstance["ZONEID"] #任意設定はここから 必要な分増やす extra_args = {} if (isNotEmpty(csInstance["NETWORKID"])): extra_args["network_id"] = csInstance["NETWORKID"] #SecurityGroup securityGroups = [] if (isNotEmpty(csInstance["SECURITYGROUP"])): securityGroups.append(csInstance["SECURITYGROUP"].split(",")) extra_args["securitygroupnames"] = securityGroups if (isNotEmpty(csInstance["KEY_NAME"])): extra_args["keypair"] = csInstance["KEY_NAME"] #UserDataを作成 userData = self.createUserData(instanceNo, pccInstance, csInstance) userData = self.makeUserData(userData) extra_args["userdata"] = userData self.logger.info("userData:"+userData) #イベントログ出力 self.conn.debug(pccInstance["FARM_NO"], None, None, instanceNo, pccInstance["INSTANCE_NAME"], "CloudStackInstanceCreate",["CLOUDSTACK"]) #インスタンスの作成 node = self.client.runInstances(pccInstance["INSTANCE_NAME"], pccInstance["FQDN"], serviceofferingid, image["templateId"], availabilityZone, **extra_args) if node["state"] != "Running": # インスタンス作成失敗時 raise IaasException("EPROCESS-000716", [node["id"], node["state"]]) # ログ出力 self.logger.info(None, "IPROCESS-100603", [node["id"],]) # イベントログ出力 self.conn.debug(pccInstance["FARM_NO"], None, None, instanceNo, pccInstance["INSTANCE_NAME"], "CloudStackInstanceCreateFinish",["CLOUDSTACK", node["id"]]) # データベース更新 table = self.conn.getTable("CLOUDSTACK_INSTANCE") updateDict = self.conn.selectOne(table.select(table.c.INSTANCE_NO==instanceNo)) updateDict["INSTANCE_ID"] = node["id"] updateDict["ZONEID"] = node["zoneid"] updateDict["STATE"] = node["state"] updateDict["DISPLAYNAME"] = node["displayname"] updateDict["IPADDRESS"] = node["nic"][0]["ipaddress"] sql = table.update(table.c.INSTANCE_NO ==updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) def start(self, instanceNo, csInstance, pccInstance): instanceId = csInstance["INSTANCE_ID"] # イベントログ出力 self.conn.debug(pccInstance["FARM_NO"], None, None, instanceNo, pccInstance["INSTANCE_NAME"], "CloudStackInstanceStart",["CLOUDSTACK", instanceId]) #serviceoffering名称をIDへ変換 serviceofferings = self.client.describeServiceOfferings() #デフォルトは最初にHitするID serviceofferingid = serviceofferings[0]["id"] for serviceoffering in serviceofferings: if csInstance["INSTANCE_TYPE"] == serviceoffering["name"]: serviceofferingid = serviceoffering["id"] #serviceofferingの変更有無を確認 node = self.client.describeInstance(instanceId) if node.extra["serviceofferingid"] != serviceofferingid: # serviceofferingの変更 node = self.client.changeInstance(instanceId, serviceofferingid); # インスタンスの起動 node = self.client.startInstance(instanceId); if node["state"] != "Running": # インスタンス作成失敗時 raise IaasException("EPROCESS-000716", [instanceId, node["state"]]) # ログ出力 self.logger.info(None, "IPROCESS-100601", [instanceId,]) # イベントログ出力 self.conn.debug(pccInstance["FARM_NO"], None, None, instanceNo, pccInstance["INSTANCE_NAME"], "CloudStackInstanceStartFinish",["CLOUDSTACK", instanceId]) # データベース更新 table = self.conn.getTable("CLOUDSTACK_INSTANCE") updateDict = self.conn.selectOne(table.select(table.c.INSTANCE_NO==instanceNo)) updateDict["ZONEID"] = node["zoneid"] updateDict["STATE"] = node["state"] updateDict["DISPLAYNAME"] = node["displayname"] updateDict["IPADDRESS"] = node["nic"][0]["ipaddress"] sql = table.update(table.c.INSTANCE_NO ==updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) def stop(self, instanceNo, csInstance, pccInstance): instanceId = csInstance["INSTANCE_ID"] # イベントログ出力 self.conn.debug(pccInstance["FARM_NO"], None, None, instanceNo, pccInstance["INSTANCE_NAME"], "CloudStackInstanceStop",["CLOUDSTACK", instanceId]) # インスタンスの停止 node = self.client.stopInstance(instanceId); if node["state"] != "Stopped": # インスタンス作成失敗時 raise IaasException("EPROCESS-000718", [instanceId, node["state"]]) # ログ出力 self.logger.info(None, "IPROCESS-100602", [instanceId,]) # イベントログ出力 self.conn.debug(pccInstance["FARM_NO"], None, None, instanceNo, pccInstance["INSTANCE_NAME"], "CloudStackInstanceStopFinish",["CLOUDSTACK", instanceId]) # データベース更新 table = self.conn.getTable("CLOUDSTACK_INSTANCE") updateDict = self.conn.selectOne(table.select(table.c.INSTANCE_NO==instanceNo)) updateDict["ZONEID"] = node["zoneid"] updateDict["STATE"] = node["state"] updateDict["DISPLAYNAME"] = node["displayname"] updateDict["IPADDRESS"] = node["nic"][0]["ipaddress"] sql = table.update(table.c.INSTANCE_NO ==updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) def terminate(self, instanceId): #CLOUDSTACK_INSTANCE 取得 tableCSINS = self.conn.getTable("CLOUDSTACK_INSTANCE") csInstance = self.conn.selectOne(tableCSINS.select(tableCSINS.c.INSTANCE_ID==instanceId)) if isEmpty(instanceId): #IDが指定されていない場合はそのまま返す return # インスタンスの停止 node = self.client.terminateInstance(instanceId) # ログ出力 self.logger.info(None, "IPROCESS-100604", [instanceId,]) # データベース更新 csInstance["ZONEID"] = None csInstance["STATE"] = node["state"] csInstance["DISPLAYNAME"] = None csInstance["IPADDRESS"] = None sql = tableCSINS.update(tableCSINS.c.INSTANCE_NO ==csInstance["INSTANCE_NO"], values=csInstance) self.conn.execute(sql) def createUserData(self, instanceNo, pccInstance, csInstance): table = self.conn.getTable("FARM") fram = self.conn.selectOne(table.select(table.c.FARM_NO==pccInstance["FARM_NO"])) #UserDataを作成 userData = {} #DB情報 userData.update({"instanceName": pccInstance["INSTANCE_NAME"]}) userData.update({"farmName": fram["FARM_NAME"]}) # FQDN userData.update({"hostname": pccInstance["FQDN"]}) #初期スクリプト情報 userData.update({"scriptserver": getScriptProperty("script.server")}) #DNS情報 userData.update(self.createDnsUserData(instanceNo)) # Puppet情報 userData.update(self.createPuppetUserData()) # VPN情報 internal = self.platforminfo["internal"] if (internal == 0): userData.update(self.createVpnUserData(pccInstance)) return userData; def createDnsUserData(self,instanceNo): # UserDataを作成 userData = {} # Primary DNSサーバ userData.update({"dns": getDnsProperty("dns.server")}) # Secondry DNSサーバ dns2 = getDnsProperty("dns.server2") if (isNotEmpty(dns2)): userData.update({"dns2": dns2}) # DNSドメイン userData.update({"dnsdomain": getDnsProperty("dns.domain")}) return userData; def createPuppetUserData(self): # UserDataを作成 userData = {} # PuppetMaster情報 userData.update({"puppetmaster": getPuppetProperty("puppet.masterHost")}) return userData; def createVpnUserData(self, pccInstance): # UserDataを作成 userData = {} #VPN情報のユーザとパスワードをセットする userData.update({"vpnuser": pccInstance["FQDN"]}) userData.update({"vpnuserpass": pccInstance["INSTANCE_CODE"]}) # VPNサーバ情報 userData.update({"vpnserver": getVpnProperty("vpn.server")}) userData.update({"vpnport": getVpnProperty("vpn.port")}) # userData.update({"vpnuser": getVpnProperty("vpn.user")}) # userData.update({"vpnuserpass": getVpnProperty("vpn.userpass")}) # ZIPパスワード userData.update({"vpnzippass": getVpnProperty("vpn.zippass")}) # クライアント証明書ダウンロードURL userData.update({"vpnclienturl": getVpnProperty("vpn.clienturl")}) return userData; def makeUserData(self, map): if not map or len(map) == 0: return None userdata = '' for key in map.keys(): value = map[key] if isNotEmpty(value): if userdata != '': userdata = userdata + ';' userdata = userdata + key + "=" + value return userdata
class ec2OtherController(object): logger = IaasLogger() client = None conn = None platforminfo = None def __init__(self, platforminfo, ec2iaasclient, conn): self.platforminfo = platforminfo self.client = ec2iaasclient self.conn = conn def describeSnapshot(self, snapshotId): snapshot = self.client.describeSnapshot(snapshotId) return snapshot def describeSnapshots(self): snapshots = self.client.describeSnapshots() return snapshots def createSnapshot(self, volumeNo): tableAWSVOL = self.conn.getTable("AWS_VOLUME") awsVolumes = self.conn.selectOne( tableAWSVOL.select(tableAWSVOL.c.VOLUME_NO == volumeNo)) volumeId = awsVolumes['VOLUME_ID'] snapshot = self.client.createSnapshot(volumeId) tableCSSNP = self.conn.getTable("CLOUDSTACK_SNAPSHOT") sql = tableCSSNP.insert({ "SNAPSHOT_NO": None, "FARM_NO": awsVolumes["FARM_NO"], "PLATFORM_NO": awsVolumes["PLATFORM_NO"], "VOLUME_NO": volumeNo, "SNAPSHOT_ID": snapshot.snapshotId, "CREATE_DATE": snapshot.startTime }) self.conn.execute(sql) return snapshot def deleteSnapshot(self, snapshotNo): tableAWSSNP = self.conn.getTable("CLOUDSTACK_SNAPSHOT") awsSnap = self.conn.selectOne( tableAWSSNP.select(tableAWSSNP.c.SNAPSHOT_NO == snapshotNo)) self.client.deleteSnapshot(awsSnap["SNAPSHOT_ID"]) def getPasswordData(self, instanceNo): tableAWSINS = self.conn.getTable("AWS_INSTANCE") awsInstance = self.conn.selectOne( tableAWSINS.select(tableAWSINS.c.INSTANCE_NO == instanceNo)) passwd = self.client.getPasswordData(awsInstance["INSTANCE_ID"]) #前後の改行コードを抜く為改行コードでスプリット passwdArray = passwd.splitlines() #1つ目が空白になるので2つめを使う if passwdArray[0] == '': passwd = passwdArray[1] else: passwd = passwdArray[0] return passwd
class EC2LBConnectionUSE(ConnectionUserAndKey): logger = IaasLogger() responseCls = EC2Response useProxy = False host = LBHOSTS["US_EAST"] def __init__(self, user_id, key, secure=True, host=None, port=None, url=None): super(EC2LBConnectionUSE, self).__init__(user_id, key, secure=secure, host=host, port=port, url=url) def connect(self, host=None, port=None, base_url = None): # prefer the attribute base_url if its set or sent connection = None secure = self.secure if getattr(self, 'base_url', None) and base_url == None: (host, port, secure, self.request_path) = self._tuple_from_url(self.base_url) elif base_url != None: (host, port, secure, self.request_path) = self._tuple_from_url(base_url) else: host = host or self.host port = port or self.port kwargs = {'host': host, 'port': int(port)} if not self.useProxy: #self.logger.debug("**************** OFF PROXY !") connection = self.conn_classes[secure](**kwargs) elif proxy_port is None or proxy_port == "": #self.logger.debug("**************** NON PROXY !") connection = self.conn_classes[secure](**kwargs) else: #self.logger.debug("**************** ON PROXY !") connection = self.conn_classes[secure](proxy_host, proxy_port) if proxy_user is not None and proxy_user != "": headers = {"Proxy-Authorization":"Basic " + base64.b64encode(proxy_user + ":" + proxy_pass)} kwargs["headers"] = headers connection.set_tunnel(**kwargs) self.connection = connection def add_default_params(self, params): params['SignatureVersion'] = '2' params['SignatureMethod'] = 'HmacSHA1' params['AWSAccessKeyId'] = self.user_id params['Version'] = API_VERSION params['Timestamp'] = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()) params['Signature'] = self._get_aws_auth_param(params, self.key, self.action) return params def _get_aws_auth_param(self, params, secret_key, path='/'): keys = params.keys() keys.sort() pairs = [] for key in keys: pairs.append(urllib.quote(key, safe='') + '=' + urllib.quote(params[key], safe='-_~')) qs = '&'.join(pairs) string_to_sign = '\n'.join(('GET', self.host, path, qs)) b64_hmac = base64.b64encode( hmac.new(secret_key, string_to_sign, digestmod=sha1).digest() ) return b64_hmac
class VCloudInstanceController(object): client = None conn = None logger = IaasLogger() platforminfo = None def __init__(self, platforminfo, vciaasclient, conn): self.client = vciaasclient self.conn = conn self.platforminfo = platforminfo def startInstance(self, instanceNo): #AWS_INSTANCE 取得 tableVCINS = self.conn.getTable("VCLOUD_INSTANCE") vcInstance = self.conn.selectOne( tableVCINS.select(tableVCINS.c.INSTANCE_NO == instanceNo)) #PCC_INSTANCE 取得 tableINS = self.conn.getTable("INSTANCE") pccInstance = self.conn.selectOne( tableINS.select(tableINS.c.INSTANCE_NO == instanceNo)) #FARM 取得 tableFarm = self.conn.getTable("FARM") farm = self.conn.selectOne( tableFarm.select(tableFarm.c.FARM_NO == pccInstance["FARM_NO"])) #組織 vdc = self.client.getUseVdc() #マイクラウド vApp = self.client.describeMyCloud(vdc, farm["FARM_NAME"]) #イメージの取得 再考の余地あり image = getImage(pccInstance["IMAGE_NO"]) #既存VM検索 vm = self.client.describeInstance(vApp, vcInstance["VM_NAME"]) #VMが既に存在する場合はStart なければClone if vm is None: #インスタンスの作成 vm = self.cloneVM(vdc, vApp, image, vcInstance, pccInstance) #最新情報を取得 vcInstance = self.conn.selectOne( tableVCINS.select(tableVCINS.c.INSTANCE_NO == instanceNo)) #インスタンスの起動 self.start(vdc, vApp, vm, vcInstance, pccInstance) #winodowsなら #if (startsWithIgnoreCase(image["os"], "windows")): # self.client.getPasswordData(vcInstance["INSTANCE_ID"]) else: # インスタンスが停止中でない場合はスキップ if (vcInstance["STATUS"] != VCloudIaasClient.STOPPED): return # インスタンスの起動 self.start(vdc, vApp, vm, vcInstance, pccInstance) def stopInstance(self, instanceNo): #AWS_INSTANCE 取得 tableVCINS = self.conn.getTable("VCLOUD_INSTANCE") vcInstance = self.conn.selectOne( tableVCINS.select(tableVCINS.c.INSTANCE_NO == instanceNo)) #PCC_INSTANCE 取得 tableINS = self.conn.getTable("INSTANCE") pccInstance = self.conn.selectOne( tableINS.select(tableINS.c.INSTANCE_NO == instanceNo)) #FARM 取得 tableFarm = self.conn.getTable("FARM") farm = self.conn.selectOne( tableFarm.select(tableFarm.c.FARM_NO == pccInstance["FARM_NO"])) #組織 vdc = self.client.getUseVdc() #マイクラウド vApp = self.client.describeMyCloud(vdc, farm["FARM_NAME"]) #既存VM検索 vm = self.client.describeInstance(vApp, vcInstance["VM_NAME"]) # インスタンスが存在しない場合は何もしない if vm is None: return # インスタンスの停止 self.stop(vApp, vm, vcInstance, pccInstance) #################################################################################### def cloneVM(self, vdc, vApp, image, vcInstance, pccInstance): #イベントログ出力 platformTable = self.conn.getTable("PLATFORM") platform = self.conn.selectOne( platformTable.select( platformTable.c.PLATFORM_NO == pccInstance["PLATFORM_NO"])) self.conn.debug( pccInstance["FARM_NO"], None, None, pccInstance["INSTANCE_NO"], pccInstance["INSTANCE_NAME"], "VCloudInstanceCreate", [platform["PLATFORM_NAME"], pccInstance["INSTANCE_NAME"]]) tableIN = self.conn.getTable("VCLOUD_INSTANCE_NETWORK") instanceNW = self.conn.select( tableIN.select(tableIN.c.INSTANCE_NO == vcInstance["INSTANCE_NO"])) tableStorage = self.conn.getTable("PLATFORM_VCLOUD_STORAGE_TYPE") storage = self.conn.selectOne( tableStorage.select(tableStorage.c.STORAGE_TYPE_NO == vcInstance["STORAGE_TYPE_NO"])) #イメージリンク imageHarf = self.client.describeImageHref(image["templateName"]) #VAPPネットワークのアップデート確認 self.client.checkNetwork(vApp, instanceNW) #ネットワーク設定 INDEX「0」にはPCCネットワークが入る為ダミーを設定 useNetworks = [ PccVMNetwork("", "", "", 0, 0), ] for net in instanceNW: #PCCネットワーク if getOtherProperty("vCloud.PCCNetwork") == net["NETWORK_NAME"]: useNetworks[0] = PccVMNetwork(net["NETWORK_NAME"], net["IP_ADDRESS"], net["IP_MODE"], 0, net["IS_PRIMARY"]) else: useNetworks.append( PccVMNetwork(net["NETWORK_NAME"], net["IP_ADDRESS"], net["IP_MODE"], net["NETWORK_INDEX"], net["IS_PRIMARY"])) #ストレージ storageProfile = self.client.describeStorageProfile( vdc, storage["STORAGE_TYPE_NAME"]) #パラメータ作成 info = { "image": imageHarf, "vm_name": pccInstance["INSTANCE_NAME"], "vm_storage": storageProfile, "vm_networks": useNetworks, "fqdn": pccInstance["FQDN"] } #仮想マシンを作成 node = self.client.createInstances(vApp, **info) vm = self.client.describeInstance(node, pccInstance["INSTANCE_NAME"]) self.logger.info(vm) #イベントログ出力 self.conn.debug( pccInstance["FARM_NO"], None, None, pccInstance["INSTANCE_NO"], pccInstance["INSTANCE_NAME"], "VCloudInstanceCreateFinish", [platform["PLATFORM_NAME"], pccInstance["INSTANCE_NAME"]]) #データベース更新 tableVCINS = self.conn.getTable("VCLOUD_INSTANCE") updateDict = self.conn.selectOne( tableVCINS.select( tableVCINS.c.INSTANCE_NO == pccInstance["INSTANCE_NO"])) updateDict["VM_NAME"] = vm["name"] updateDict["STATUS"] = vm["state"] publicIp = vm["public_ips"] privateIp = vm["private_ips"] if len(publicIp) > 0: updateDict["IP_ADDRESS"] = publicIp[0] if len(privateIp) > 0: updateDict["PRIVATE_IP_ADDRESS"] = privateIp[0] else: updateDict["PRIVATE_IP_ADDRESS"] = updateDict["IP_ADDRESS"] sql = tableVCINS.update( tableVCINS.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) # TODO ここでネットーワークインデックスを更新 self.reflectVMNetwork(vm, pccInstance["INSTANCE_NO"]) return vm def start(self, vdc, vApp, vm, vcInstance, pccInstance): #プラットフォーム platformTable = self.conn.getTable("PLATFORM") platform = self.conn.selectOne( platformTable.select( platformTable.c.PLATFORM_NO == pccInstance["PLATFORM_NO"])) tableIN = self.conn.getTable("VCLOUD_INSTANCE_NETWORK") instanceNw = self.conn.select( tableIN.select(tableIN.c.INSTANCE_NO == vcInstance["INSTANCE_NO"])) tableStorage = self.conn.getTable("PLATFORM_VCLOUD_STORAGE_TYPE") storage = self.conn.selectOne( tableStorage.select(tableStorage.c.STORAGE_TYPE_NO == vcInstance["STORAGE_TYPE_NO"])) # イベントログ出力 self.conn.debug( pccInstance["FARM_NO"], None, None, pccInstance["INSTANCE_NO"], pccInstance["INSTANCE_NAME"], "VCloudInstanceStart", [platform["PLATFORM_NAME"], pccInstance["INSTANCE_NAME"]]) #インスタンスタイプの取得 tableType = self.conn.getTable("PLATFORM_VCLOUD_INSTANCE_TYPE") instype = self.conn.selectOne( tableType.select( and_( tableType.c.INSTANCE_TYPE_NAME == vcInstance["INSTANCE_TYPE"], tableType.c.PLATFORM_NO == pccInstance["PLATFORM_NO"]))) #現状を取得 setCpu = self.client.describeCPU(vm) setMemory = self.client.describeMemory(vm) #変更が有れば通知 if str(instype["CPU"]) != str(setCpu): self.client._change_vm_cpu(vm["id"], instype["CPU"]) if str(instype["MEMORY"]) != str(setMemory): self.client._change_vm_memory(vm["id"], instype["MEMORY"]) #ストレージ変更 if storage["STORAGE_TYPE_NAME"] != vm["storageprofile"]: #変更後のストレージプロファイル storageProfile = self.client.describeStorageProfile( vdc, storage["STORAGE_TYPE_NAME"]) self.client.editInstance(vm, **{"storageProfile": storageProfile}) #VAPPネットワークのアップデート確認 self.client.checkNetwork(vApp, instanceNw) #IPアドレスの再設定 self.client._change_vm_nw(vm["id"], instanceNw) #UserDataを作成 userData = self.createUserData(pccInstance["INSTANCE_NO"], pccInstance, vcInstance) #PCCネットワークGWを設定 vappnw = self.client.describeVappNetwork(vApp) for net in vappnw: if net.name == getOtherProperty("vCloud.PCCNetwork"): userData.update({"pccgateway": net.gateway}) #ルーティングIP userData.update(self.createUserNetwork()) #UserDataを整形 userData = self.makeUserData(userData) #UserDataのキー とりあえず固定(VMWareと同一の物) key = "guestinfo.userdata" metadata = VCloudMetadataSet(key=key, value=userData) metadatas = [ metadata, ] #ユーザーデータ登録 self.client.setProductSections(vm, metadatas) # VCLOUD上のステータスを確認インスタンスが停止中 startvm = None if (vm["state"] == VCloudIaasClient.STOPPED): # インスタンスの起動 node = self.client.startInstance(vApp, vm) startvm = self.client.describeInstance(node, vcInstance["VM_NAME"]) else: #既にスタートしている startvm = vm #イベントログ出力 self.conn.debug( pccInstance["FARM_NO"], None, None, pccInstance["INSTANCE_NO"], pccInstance["INSTANCE_NAME"], "VCloudInstanceStartFinish", [platform["PLATFORM_NAME"], pccInstance["INSTANCE_NAME"]]) # データベース更新 table = self.conn.getTable("VCLOUD_INSTANCE") updateDict = self.conn.selectOne( table.select(table.c.INSTANCE_NO == pccInstance["INSTANCE_NO"])) updateDict["STATUS"] = startvm["state"] publicIp = startvm["public_ips"] privateIp = startvm["private_ips"] if len(publicIp) > 0: updateDict["IP_ADDRESS"] = publicIp[0] if len(privateIp) > 0: updateDict["PRIVATE_IP_ADDRESS"] = privateIp[0] else: updateDict["PRIVATE_IP_ADDRESS"] = updateDict["IP_ADDRESS"] sql = table.update(table.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) # TODO ここでネットーワークインデックス等を更新 self.reflectVMNetwork(vm, pccInstance["INSTANCE_NO"]) def stop(self, vApp, vm, vcInstance, pccInstance): #プラットフォーム platformTable = self.conn.getTable("PLATFORM") platform = self.conn.selectOne( platformTable.select( platformTable.c.PLATFORM_NO == pccInstance["PLATFORM_NO"])) # イベントログ出力 self.conn.debug( pccInstance["FARM_NO"], None, None, pccInstance["INSTANCE_NO"], pccInstance["INSTANCE_NAME"], "VCloudInstanceStop", [platform["PLATFORM_NAME"], pccInstance["INSTANCE_NAME"]]) # VCLOUD上のステータスを確認インスタンスが実行中 stopvm = None if (vm["state"] == VCloudIaasClient.RUNNING): # インスタンスの停止 node = self.client.stopInstance(vApp, vm) stopvm = self.client.describeInstance(node, vcInstance["VM_NAME"]) else: stopvm = vm if stopvm["state"] != VCloudIaasClient.STOPPED: # インスタンス停止失敗時 raise IaasException("EPROCESS-000718", [vcInstance["VM_NAME"], stopvm["state"]]) # イベントログ出力 self.conn.debug( pccInstance["FARM_NO"], None, None, pccInstance["INSTANCE_NO"], pccInstance["INSTANCE_NAME"], "VCloudInstanceStopFinish", [platform["PLATFORM_NAME"], pccInstance["INSTANCE_NAME"]]) # データベース更新 table = self.conn.getTable("VCLOUD_INSTANCE") updateDict = self.conn.selectOne( table.select(table.c.INSTANCE_NO == pccInstance["INSTANCE_NO"])) updateDict["STATUS"] = stopvm["state"] sql = table.update(table.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) def terminate(self, vm_name): #vCloud_INSTANCE 取得 tableVCINS = self.conn.getTable("VCLOUD_INSTANCE") vcInstance = self.conn.selectOne( tableVCINS.select(tableVCINS.c.VM_NAME == vm_name)) #PCC_INSTANCE 取得 tableINS = self.conn.getTable("INSTANCE") pccInstance = self.conn.selectOne( tableINS.select( tableINS.c.INSTANCE_NO == vcInstance["INSTANCE_NO"])) #FARM 取得 tableFarm = self.conn.getTable("FARM") farm = self.conn.selectOne( tableFarm.select(tableFarm.c.FARM_NO == pccInstance["FARM_NO"])) #プラットフォーム platformTable = self.conn.getTable("PLATFORM") platform = self.conn.selectOne( platformTable.select( platformTable.c.PLATFORM_NO == pccInstance["PLATFORM_NO"])) # イベントログ出力 self.conn.debug( pccInstance["FARM_NO"], None, None, pccInstance["INSTANCE_NO"], pccInstance["INSTANCE_NAME"], "VCloudInstanceDelete", [platform["PLATFORM_NAME"], pccInstance["INSTANCE_NAME"]]) #組織 vdc = self.client.getUseVdc() #マイクラウド vApp = self.client.describeMyCloud(vdc, farm["FARM_NAME"]) #既存VM検索 vm = self.client.describeInstance(vApp, vcInstance["VM_NAME"]) if vm is None: #存在しない場合はそのまま返す return # インスタンスの削除 self.client.terminateInstance(vApp, vcInstance["VM_NAME"]) # データベース更新は不要? # イベントログ出力 self.conn.debug( pccInstance["FARM_NO"], None, None, pccInstance["INSTANCE_NO"], pccInstance["INSTANCE_NAME"], "VCloudInstanceDeleteFinish", [platform["PLATFORM_NAME"], pccInstance["INSTANCE_NAME"]]) def reflectVMNetwork(self, vm, instanceNo): tableIN = self.conn.getTable("VCLOUD_INSTANCE_NETWORK") instanceNW = self.conn.select( tableIN.select(tableIN.c.INSTANCE_NO == instanceNo)) vmNetworks = self.client.describeVMNetwork(vm) #既存ネットワークの更新 for net in instanceNW: for vmNet in vmNetworks: if vmNet.name == net["NETWORK_NAME"] and vmNet.index == str( net["NETWORK_INDEX"]): net["IP_MODE"] = vmNet.ipMode net["IP_ADDRESS"] = vmNet.ipAddress if vmNet.isPrimary: net["IS_PRIMARY"] = 1 else: net["IS_PRIMARY"] = 0 sql = tableIN.update( tableIN.c.NETWORK_NO == net["NETWORK_NO"], values=net) self.conn.execute(sql) vmNetworks.remove(vmNet) break #新規ネットワークの更新 上記で残ったネットワークを使う for net in instanceNW: if net["NETWORK_INDEX"] is None: for vmNet in vmNetworks: if vmNet.name == net["NETWORK_NAME"]: net["IP_MODE"] = vmNet.ipMode net["IP_ADDRESS"] = vmNet.ipAddress net["NETWORK_INDEX"] = vmNet.index if vmNet.isPrimary: net["IS_PRIMARY"] = 1 else: net["IS_PRIMARY"] = 0 sql = tableIN.update( tableIN.c.NETWORK_NO == net["NETWORK_NO"], values=net) self.conn.execute(sql) vmNetworks.remove(vmNet) break def createUserNetwork(self): # UserDataを作成 userData = {} zabbixserver = getOtherProperty("zabbix.server") if (isNotEmpty(zabbixserver)): #Zabbixサーバー(ルーティング用) userData.update({"zabbixserver": zabbixserver}) routeAddserver = getOtherProperty("vCloud.routeAddserver") if (isNotEmpty(routeAddserver)): #ユーザー指定ルーティングサーバ userData.update({"routeAddserver": routeAddserver}) return userData def createUserData(self, instanceNo, pccInstance, vcInstance): table = self.conn.getTable("FARM") fram = self.conn.selectOne( table.select(table.c.FARM_NO == pccInstance["FARM_NO"])) #UserDataを作成 userData = {} #DB情報 userData.update({"instanceName": pccInstance["INSTANCE_NAME"]}) userData.update({"farmName": fram["FARM_NAME"]}) # FQDN userData.update({"hostname": pccInstance["FQDN"]}) #初期スクリプト情報 userData.update({"scriptserver": getScriptProperty("script.server")}) #DNS情報 userData.update(self.createDnsUserData(instanceNo)) # Puppet情報 userData.update(self.createPuppetUserData()) # VPN情報 internal = self.platforminfo["internal"] if (internal == 0): userData.update(self.createVpnUserData(pccInstance)) # SSHキー userData.update(self.createSshUserData(vcInstance)) return userData def createDnsUserData(self, instanceNo): # UserDataを作成 userData = {} # Primary DNSサーバ userData.update({"dns": getDnsProperty("dns.server")}) # Secondry DNSサーバ dns2 = getDnsProperty("dns.server2") if (isNotEmpty(dns2)): userData.update({"dns2": dns2}) # DNSドメイン userData.update({"dnsdomain": getDnsProperty("dns.domain")}) return userData def createPuppetUserData(self): # UserDataを作成 userData = {} # PuppetMaster情報 userData.update( {"puppetmaster": getPuppetProperty("puppet.masterHost")}) return userData def createVpnUserData(self, pccInstance): # UserDataを作成 userData = {} #VPN情報のユーザとパスワードをセットする userData.update({"vpnuser": pccInstance["FQDN"]}) userData.update({"vpnuserpass": pccInstance["INSTANCE_CODE"]}) # VPNサーバ情報 userData.update({"vpnserver": getVpnProperty("vpn.server")}) userData.update({"vpnport": getVpnProperty("vpn.port")}) # userData.update({"vpnuser": getVpnProperty("vpn.user")}) # userData.update({"vpnuserpass": getVpnProperty("vpn.userpass")}) # ZIPパスワード userData.update({"vpnzippass": getVpnProperty("vpn.zippass")}) # クライアント証明書ダウンロードURL userData.update({"vpnclienturl": getVpnProperty("vpn.clienturl")}) return userData def createSshUserData(self, vcInstance): table = self.conn.getTable("VCLOUD_KEY_PAIR") sshkey = self.conn.selectOne( table.select(table.c.KEY_NO == vcInstance["KEY_PAIR_NO"])) # UserDataを作成 userData = {} # ZIPパスワード userData.update({"sshpubkey": sshkey["KEY_PUBLIC"]}) return userData def makeUserData(self, map): if not map or len(map) == 0: return None userdata = '' for key in map.keys(): value = map[key] if isNotEmpty(value): if userdata != '': userdata = userdata + ';' userdata = userdata + key + "=" + value return userdata
class OpenStackInstanceController(object): logger = IaasLogger() client = None conn = None platforminfo = None def __init__(self, platforminfo, openstackiaasclient, conn): self.client = openstackiaasclient self.conn = conn self.platforminfo = platforminfo return def _createVirtualMachine(self, instanceNo, instanceName, instanceInfo, openstackInstanceInfo): # プラットフォーム番号の取得 platformNo = instanceInfo['PLATFORM_NO'] # VM作成に必要なパラメータを取得 # キーペア名 keyName = openstackInstanceInfo['KEY_NAME'] if isEmpty(keyName): self.logger.debug(' No Keipair specified. Using default.') # ファーム番号の取得 farmNo = instanceInfo['FARM_NO'] farmTable = self.conn.getTable("FARM") farmInfo = self.conn.selectOne(farmTable.select\ (farmTable.c.FARM_NO==farmNo)) userNo = farmInfo['USER_NO'] openstackCertificateTable = self.conn.getTable("OPENSTACK_CERTIFICATE") certificateInfo = self.conn.selectOne(openstackCertificateTable.select\ (and_(openstackCertificateTable.c.USER_NO==userNo, \ openstackCertificateTable.c.PLATFORM_NO==platformNo))) keyName = certificateInfo['DEF_KEYPAIR'] self.logger.debug(' Keypair: %s' % (keyName)) # フレーバーID instanceType = openstackInstanceInfo['INSTANCE_TYPE'] self.logger.debug(' Instance Type: %s' % (instanceType)) # セキュリティグループID securityGroup = openstackInstanceInfo['SECURITY_GROUPS'] self.logger.debug(' Security Group: %s' % (securityGroup)) # ゾーンID availabilityZone = openstackInstanceInfo['AVAILABILITY_ZONE'] if isEmpty(availabilityZone): self.logger.debug(' No Availability Zone specified. Using default.') platformOpenStackTable = self.conn.getTable("PLATFORM_OPENSTACK") platformOpenStackInfo = self.conn.selectOne(platformOpenStackTable.select\ (platformOpenStackTable.c.PLATFORM_NO==platformNo)) availabilityZone = platformOpenStackInfo['AVAILABILITY_ZONE'] self.logger.debug(' Availability Zone: %s' % (availabilityZone)) # ネットワークID networkId = openstackInstanceInfo['NETWORK_ID'] if isEmpty(networkId): self.logger.debug(' No Network ID specified. Using default.') platformOpenStackTable = self.conn.getTable("PLATFORM_OPENSTACK") platformOpenStackInfo = self.conn.selectOne(platformOpenStackTable.select\ (platformOpenStackTable.c.PLATFORM_NO==platformNo)) networkId = platformOpenStackInfo['NETWORK_ID'] self.logger.debug(' Network: %s' % (networkId)) # イメージID imageNo = instanceInfo['IMAGE_NO'] imageOpenstackTable = self.conn.getTable("IMAGE_OPENSTACK") imageOpenstackInfo = self.conn.selectOne(imageOpenstackTable.select\ (imageOpenstackTable.c.IMAGE_NO==imageNo)) imageId = imageOpenstackInfo['IMAGE_ID'] self.logger.debug(' Image: %s' % (imageId)) # ユーザデータ userData = self.createUserData(instanceNo, instanceInfo, openstackInstanceInfo) userData = self.makeUserData(userData) self.logger.debug(' User Data: %s' %(userData)) try: instanceObj = self.client.createVirtualMachine(instanceName, instanceType, \ imageId, availabilityZone, networkId, userData, securityGroup, keyName) except: raise IaasException("EPROCESS-001002", [instanceName]) status = instanceObj.status if status != 'ACTIVE': raise IaasException("EPROCESS-001003", [instanceName, status]) openstackInstanceId = instanceObj.id connectedNetworks = instanceObj.addresses.keys() # IPは1つのみであることを仮定 connectedNw = connectedNetworks[0] try: ipAddr = instanceObj.addresses[connectedNw][0]['addr'] self.logger.debug(' IP Address: %s' %(ipAddr)) except: ipAddr = None # データベース更新 table = self.conn.getTable("OPENSTACK_INSTANCE") updateDict = self.conn.selectOne(table.select(table.c.INSTANCE_NO==instanceNo)) updateDict["STATUS"] = status updateDict["INSTANCE_ID"] = openstackInstanceId updateDict["PRIVATE_IP_ADDRESS"] = ipAddr updateDict["NETWORK_ID"] = networkId updateDict["KEY_NAME"] = keyName updateDict["AVAILABILITY_ZONE"] = availabilityZone sql = table.update(table.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) return True def startInstance(self, instanceNo): self.logger.info(' StartInstance: %s' % (instanceNo)) # インスタンスIDの取得 openstackInstanceTable = self.conn.getTable("OPENSTACK_INSTANCE") openstackInstanceInfo = self.conn.selectOne(openstackInstanceTable.select\ (openstackInstanceTable.c.INSTANCE_NO==instanceNo)) openstackInstanceId = openstackInstanceInfo['INSTANCE_ID'] # インスタンス名の取得 instanceTable = self.conn.getTable("INSTANCE") instanceInfo = self.conn.selectOne(instanceTable.select\ (instanceTable.c.INSTANCE_NO==instanceNo)) instanceName = instanceInfo['FQDN'] if isEmpty(openstackInstanceId): # 新規作成 self.logger.info(' Creating Instance: %s' % (instanceName)) return self._createVirtualMachine(instanceNo, instanceName, instanceInfo, openstackInstanceInfo) else: # 既存インスタンス # ステータスを確認する try: status = self.client.getVirtualMachineStatus(openstackInstanceId) except: raise IaasException("EPROCESS-001008", [instanceName]) if status == 'ACTIVE': # 既にインスタンスは起動しているため、statusを更新して終了する。 self.logger.info(' Instance: %s is already ACTIVE' % (instanceName)) # データベース更新 table = self.conn.getTable("OPENSTACK_INSTANCE") updateDict = self.conn.selectOne(table.select(table.c.INSTANCE_NO==instanceNo)) updateDict["STATUS"] = status sql = table.update(table.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) return True elif status == 'ERROR': # インスタンスの状態がERRORならば、起動は意味がないのでエラーにする。 self.logger.info(' Instance: %s is in ERROR status' % (instanceName)) raise IaasException("EPROCESS-001003", [instanceName, status]) else: # 既に作成され、停止しているインスタンスを起動する。 # SHUTOFF 状態のインスタンスに対して起動するのが通常の処理だが、 # SHUTOFF 状態以外の場合でも、起動を試みて結果を返す。 self.logger.info(' Starting Instance: %s' % (instanceName)) try: instanceObj = self.client.startVirtualMachine(openstackInstanceId) except: raise IaasException("EPROCESS-001004", [instanceName]) status = instanceObj.status self.logger.info(' StartInstance finished. Status: %s' % (status)) if status != 'ACTIVE': raise IaasException("EPROCESS-001003", [instanceName, status]) # データベース更新 table = self.conn.getTable("OPENSTACK_INSTANCE") updateDict = self.conn.selectOne(table.select(table.c.INSTANCE_NO==instanceNo)) updateDict["STATUS"] = status sql = table.update(table.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) return True def stopInstance(self, instanceNo): self.logger.info(' StopInstance: %s' % (instanceNo)) # インスタンスIDの取得 openstackInstanceTable = self.conn.getTable("OPENSTACK_INSTANCE") openstackInstanceInfo = self.conn.selectOne(openstackInstanceTable.select\ (openstackInstanceTable.c.INSTANCE_NO==instanceNo)) openstackInstanceId = openstackInstanceInfo['INSTANCE_ID'] # インスタンス名の取得 instanceTable = self.conn.getTable("INSTANCE") instanceInfo = self.conn.selectOne(instanceTable.select\ (instanceTable.c.INSTANCE_NO==instanceNo)) instanceName = instanceInfo['FQDN'] if isEmpty(openstackInstanceId): # 一度もStartしたことがない self.logger.info(' Nonexistent Instance: %s' % (instanceName)) raise IaasException("EPROCESS-001006", [instanceName]) # ステータスを確認する try: status = self.client.getVirtualMachineStatus(openstackInstanceId) except: raise IaasException("EPROCESS-001008", [instanceName]) if status == 'SHUTOFF': # 既にインスタンスは起動しているため、statusを更新して終了する。 self.logger.info(' Instance: %s is already SHUTOFF' % (instanceName)) # データベース更新 table = self.conn.getTable("OPENSTACK_INSTANCE") updateDict = self.conn.selectOne(table.select(table.c.INSTANCE_NO==instanceNo)) updateDict["STATUS"] = status sql = table.update(table.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) return True self.logger.info(' Stopping Instance: %s' % (instanceName)) try: instanceObj = self.client.stopVirtualMachine(openstackInstanceId) except: raise IaasException("EPROCESS-001006", [instanceName]) status = instanceObj.status if status != 'SHUTOFF': raise IaasException("EPROCESS-001007", [instanceName, status]) self.logger.info(' StopInstance finished. Status: %s' % (status)) # データベース更新 table = self.conn.getTable("OPENSTACK_INSTANCE") updateDict = self.conn.selectOne(table.select(table.c.INSTANCE_NO==instanceNo)) updateDict["STATUS"] = status sql = table.update(table.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) return True def terminateInstance(self, instanceNo): self.logger.info(' TerminateInstance: %s' % (instanceNo)) # インスタンスIDの取得 openstackInstanceTable = self.conn.getTable("OPENSTACK_INSTANCE") openstackInstanceInfo = self.conn.selectOne(openstackInstanceTable.select\ (openstackInstanceTable.c.INSTANCE_NO==instanceNo)) openstackInstanceId = openstackInstanceInfo['INSTANCE_ID'] # インスタンス名の取得 instanceTable = self.conn.getTable("INSTANCE") instanceInfo = self.conn.selectOne(instanceTable.select\ (instanceTable.c.INSTANCE_NO==instanceNo)) instanceName = instanceInfo['FQDN'] if isEmpty(openstackInstanceId): # 一度もStartしたことがない raise IaasException("EPROCESS-001009", [instanceName]) # ステータスを確認する try: status = self.client.getVirtualMachineStatus(openstackInstanceId) except: raise IaasException("EPROCESS-001008", [instanceName]) self.logger.info(' Instance: %s, Status: %s' % (instanceName, status)) if status != 'SHUTOFF': # 削除を許さない。 self.logger.error(' Instance: %s cannot be terminated because the status is not SHUTOFF (%s)' % (instanceName, status)) raise IaasException("EPROCESS-001010", [instanceName]) else: self.logger.info(' Terminating Instance: %s' % (instanceName)) try: self.client.deleteVirtualMachine(openstackInstanceId) except: raise IaasException("EPROCESS-001010", [instanceName]) # ステータスは確認しない self.logger.info(' Terminated %s' % (instanceName)) return True def createUserData(self, instanceNo, pccInstance, azureInstance): table = self.conn.getTable("FARM") farm = self.conn.selectOne(table.select(table.c.FARM_NO==pccInstance["FARM_NO"])) #UserDataを作成 userData = {} #DB情報 userData.update({"instanceName": pccInstance["INSTANCE_NAME"]}) userData.update({"farmName": farm["FARM_NAME"]}) # FQDN userData.update({"hostname": pccInstance["FQDN"]}) #初期スクリプト情報 userData.update({"scriptserver": getScriptProperty("script.server")}) #DNS情報 userData.update(self.createDnsUserData(instanceNo)) # Puppet情報 userData.update(self.createPuppetUserData()) # VPN情報 internal = self.platforminfo["internal"] if (internal == 0): userData.update(self.createVpnUserData(pccInstance)) return userData; def createDnsUserData(self,instanceNo): # UserDataを作成 userData = {} # Primary DNSサーバ userData.update({"dns": getDnsProperty("dns.server")}) # Secondry DNSサーバ dns2 = getDnsProperty("dns.server2") if (isNotEmpty(dns2)): userData.update({"dns2": dns2}) # DNSドメイン userData.update({"dnsdomain": getDnsProperty("dns.domain")}) return userData; def createPuppetUserData(self): # UserDataを作成 userData = {} # PuppetMaster情報 userData.update({"puppetmaster": getPuppetProperty("puppet.masterHost")}) return userData; def createVpnUserData(self, pccInstance): # UserDataを作成 userData = {} #VPN情報のユーザとパスワードをセットする userData.update({"vpnuser": pccInstance["FQDN"]}) userData.update({"vpnuserpass": pccInstance["INSTANCE_CODE"]}) # VPNサーバ情報 userData.update({"vpnserver": getVpnProperty("vpn.server")}) userData.update({"vpnport": getVpnProperty("vpn.port")}) # userData.update({"vpnuser": getVpnProperty("vpn.user")}) # userData.update({"vpnuserpass": getVpnProperty("vpn.userpass")}) # ZIPパスワード userData.update({"vpnzippass": getVpnProperty("vpn.zippass")}) # クライアント証明書ダウンロードURL userData.update({"vpnclienturl": getVpnProperty("vpn.clienturl")}) return userData; def makeUserData(self, map): if not map or len(map) == 0: return None userdata = '' for key in map.keys(): value = map[key] if isNotEmpty(value): if userdata != '': userdata = userdata + ';' userdata = userdata + key + "=" + value return userdata
class azureInstanceController(object): logger = IaasLogger() client = None conn = None platforminfo = None volumecontroller = None def __init__(self, platforminfo, azureiaasclient, conn): self.client = azureiaasclient self.conn = conn self.platforminfo = platforminfo self.volumecontroller = azureVolumeController(self.platforminfo, self.client, self.conn) self.passwordencryptor = PasswordEncryptor() def _generateOsHardDisk(self, storageAccountName, instanceName, imageName): # OS用ハードディスクの設定を生成する # URLを生成 mediaLink = 'https://%s.blob.core.windows.net/vhds/%s.vhd' % \ (storageAccountName, instanceName) return self.client.generateOSHardDiskConfig(mediaLink, imageName) def _generateConfigurationSet(self, osType, instanceNo): # 仮想マシン作成時に指定する設定を生成する instanceTable = self.conn.getTable("INSTANCE") instanceInfo = self.conn.selectOne(instanceTable.select\ (instanceTable.c.INSTANCE_NO==instanceNo)) # ホスト名 hostName = instanceInfo['INSTANCE_NAME'] farmNo = instanceInfo['FARM_NO'] farmTable = self.conn.getTable("FARM") farmInfo = self.conn.selectOne(farmTable.select\ (farmTable.c.FARM_NO==farmNo)) userNo = farmInfo['USER_NO'] userTable = self.conn.getTable("USER") userInfo = self.conn.selectOne(userTable.select\ (userTable.c.USER_NO==userNo)) azureInstanceTable = self.conn.getTable("AZURE_INSTANCE") azureInstanceInfo = self.conn.selectOne(azureInstanceTable.select\ (azureInstanceTable.c.INSTANCE_NO==instanceNo)) platformNo = instanceInfo['PLATFORM_NO'] azureCertificateTable = self.conn.getTable("AZURE_CERTIFICATE") azureCertificateInfo = self.conn.selectOne(azureCertificateTable.select\ (azureCertificateTable.c.USER_NO==userNo and azureCertificateTable.c.PLATFORM_NO==platformNo)) keyPublic = azureCertificateInfo['KEY_PUBLIC'] # カスタムデータ userData = self.createUserData(instanceNo, instanceInfo, azureInstanceInfo, keyPublic) userData = self.makeUserData(userData) customData = userData self.logger.debug("userData:"+userData) # Salt情報 pccSystemInfoTable = self.conn.getTable("PCC_SYSTEM_INFO") pccSystemInfo = self.conn.selectOne(pccSystemInfoTable.select()) # パスワード復号化 userPassword = self.passwordencryptor.decrypt(userInfo['PASSWORD'], pccSystemInfo['SECRET_KEY']) if osType == 'Linux': # Linuxのユーザ名 (rootのsshキー認証が設定できるのが望ましい) userName = userInfo['USERNAME'] return self.client.generateLinuxConfig(hostName, userName, userPassword, customData) elif osType == 'Windows': # Windowsのユーザ名 userName = userInfo['USERNAME'] return self.client.generateWindowsConfig(hostName, userName, userPassword, customData) else: return None def _generateVirtualMachineName(self, instanceNo): # インスタンスNoとサーバ名を組み合わせてAzureの仮想マシン名を生成する instanceTable = self.conn.getTable("INSTANCE") instanceInfo = self.conn.selectOne(instanceTable.select\ (instanceTable.c.INSTANCE_NO==instanceNo)) # サーバ名 instanceName = instanceInfo['INSTANCE_NAME'] # "インスタンスNo"_"サーバ名"をAzureの仮想マシン名とする return '%s_%s' % (instanceNo, instanceName) def _createInstance(self, platformNo, instanceNo): # 作成パラメータの取得 platformAzureTable = self.conn.getTable("PLATFORM_AZURE") platformAzureInfo = self.conn.selectOne(platformAzureTable.select\ (platformAzureTable.c.PLATFORM_NO==platformNo)) # クラウドサービス名 cloudService = platformAzureInfo['CLOUD_SERVICE_NAME'] self.logger.debug(' Cloud Serivce: %s' % (cloudService)) # ストレージアカウント名 storageAccount = platformAzureInfo['STORAGE_ACCOUNT_NAME'] self.logger.debug(' Storage Account: %s' % (storageAccount)) # ネットワーク名 networkName = platformAzureInfo['NETWORK_NAME'] self.logger.debug(' Network: %s' % (networkName)) # インスタンス名 instanceName = self._generateVirtualMachineName(instanceNo) self.logger.debug(' Virtual Machine Name: %s' % (instanceName)) # インスタンスタイプ azureInstanceTable = self.conn.getTable("AZURE_INSTANCE") azureInstanceInfo = self.conn.selectOne(azureInstanceTable.select\ (azureInstanceTable.c.INSTANCE_NO==instanceNo)) instanceType = azureInstanceInfo['INSTANCE_TYPE'] self.logger.debug(' Instance Type: %s' % (instanceType)) # 可用性セット availabilitySet = azureInstanceInfo['AVAILABILITY_SET'] self.logger.debug(' Availability Set: %s' % (availabilitySet)) # サブネットID subnetID = azureInstanceInfo['SUBNET_ID'] self.logger.debug(' Subnet ID: %s' % (subnetID)) networkConfig = self.client.generateNetworkConfig(subnetID) # イメージ名 instanceTable = self.conn.getTable("INSTANCE") instanceInfo = self.conn.selectOne(instanceTable.select\ (instanceTable.c.INSTANCE_NO==instanceNo)) imageNo = instanceInfo['IMAGE_NO'] imageAzureTable = self.conn.getTable("IMAGE_AZURE") imageAzureInfo = self.conn.selectOne(imageAzureTable.select\ (imageAzureTable.c.IMAGE_NO==imageNo)) imageName = imageAzureInfo['IMAGE_NAME'] self.logger.debug(' Image: %s' % (imageName)) # OSタイプ(Azureから取得) osType = self.client.identifyImageOsType(imageName) self.logger.debug(' OS: %s' % (osType)) # ホスト名、パスワード等のOSにまつわる設定 osConfig = self._generateConfigurationSet(osType, instanceNo) osHardDisk = self._generateOsHardDisk(storageAccount, instanceName, imageName) # VM作成 status = self.client.createVirtualMachine(cloudService, instanceName, \ osConfig, osHardDisk, instanceType, networkConfig, networkName, availabilitySet) # プライベートIPを取得する前に、VMの作成成功を確認する privateIp = self.client.getVirtualMachineIpAddress(cloudService, instanceName) self.logger.debug(' Instance: %s, Status: %s, Private IP Address: %s' \ % (instanceName, status, privateIp)) # 異常系テストコード #status = 'None' if status != 'ReadyRole': # 新規作成時、VMが起動成功しなかったら、データベースを更新せずに終了 # status ReadyRoleになる前にタイムアウトした場合と、最終的にReadyRoleにならない場合に分けて検討する必要あり。 raise IaasException("EPROCESS-000918", [instanceName, status]) # データベース更新 table = self.conn.getTable("AZURE_INSTANCE") updateDict = self.conn.selectOne(table.select(table.c.INSTANCE_NO==instanceNo)) updateDict["INSTANCE_NAME"] = instanceName updateDict["STATUS"] = status updateDict["PRIVATE_IP_ADDRESS"] = privateIp sql = table.update(table.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) def startInstance(self, instanceNo): self.logger.info(' StartInstance: %s' % (instanceNo)) # プラットフォーム番号の取得 instanceTable = self.conn.getTable("INSTANCE") instanceInfo = self.conn.selectOne(instanceTable.select\ (instanceTable.c.INSTANCE_NO==instanceNo)) platformNo = instanceInfo['PLATFORM_NO'] # 仮想マシンの起動実績確認 azureInstanceTable = self.conn.getTable("AZURE_INSTANCE") azureInstanceInfo = self.conn.selectOne(azureInstanceTable.select\ (azureInstanceTable.c.INSTANCE_NO==instanceNo)) # インスタンス名 instanceName = azureInstanceInfo['INSTANCE_NAME'] if isEmpty(instanceName): # 仮想マシンの新規作成 self._createInstance(platformNo, instanceNo) return else: # クラウドサービス名 platformAzureTable = self.conn.getTable("PLATFORM_AZURE") platformAzureInfo = self.conn.selectOne(platformAzureTable.select\ (platformAzureTable.c.PLATFORM_NO==platformNo)) cloudService = platformAzureInfo['CLOUD_SERVICE_NAME'] # 既存仮想マシンの起動 # Azure上に仮想マシンが存在するか確認 status = self.client.getVirtualMachineStatus(cloudService, instanceName) self.logger.info(' Instance: %s, Status: %s' % (instanceName, status)) if status is None: # インスタンスが存在しないまたは、状態取得に失敗した場合は、処理を終了する # ステータスは変更しない raise IaasException("EPROCESS-000914", [instanceName]) elif status == 'ReadyRole': self.logger.info(' Instance %s is already running' % (instanceName)) # インスタンスタイプをチェックし、食い違う場合は警告をログに出力する # インスタンスタイプ instanceType = azureInstanceInfo['INSTANCE_TYPE'] currentInstanceType = self.client.getVirtualMachineType(cloudService, instanceName) if currentInstanceType != instanceType: raise IaasException("EPROCESS-000913", [instanceName]) # Azure上では起動している場合、DBを更新して終了。 pass else: # ReadyRole以外の場合、起動を試みる # インスタンスタイプをチェックし、食い違う場合は警告をログに出力する # インスタンスタイプ instanceType = azureInstanceInfo['INSTANCE_TYPE'] currentInstanceType = self.client.getVirtualMachineType(cloudService, instanceName) if currentInstanceType != instanceType: self.logger.info(' Changing its instance type to %s' % (instanceType)) # サブネット subnetID = azureInstanceInfo['SUBNET_ID'] self.logger.info(' Subnet ID: %s' % (subnetID)) networkConfig = self.client.generateNetworkConfig(subnetID) # 可用性セット availabilitySet = azureInstanceInfo['AVAILABILITY_SET'] self.logger.info(' Availability Set: %s' % (availabilitySet)) # インスタンスタイプの変更を反映 newInstanceType = self.client.updateVirtualMachineType(cloudService, instanceName, instanceType, \ networkConfig, availabilitySet) if isEmpty(newInstanceType): # インスタンスタイプの変更に失敗した場合は、起動も行わない raise IaasException("EPROCESS-000913", [instanceName]) self.logger.info(' Instance type for %s has been updated: %s' % (instanceName, newInstanceType)) # インスタンス起動 status = self.client.startVirtualMachine(cloudService, instanceName) # 異常系テストコード #status = 'None' if status != 'ReadyRole': # VMが起動成功しなかったら、データベースを更新せずに終了 raise IaasException("EPROCESS-000906", [instanceName, status]) # データベース更新 table = self.conn.getTable("AZURE_INSTANCE") updateDict = self.conn.selectOne(table.select(table.c.INSTANCE_NO==instanceNo)) updateDict["STATUS"] = status sql = table.update(table.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) return def stopInstance(self, instanceNo): # インスタンス名の取得 azureInstanceTable = self.conn.getTable("AZURE_INSTANCE") azureInstanceInfo = self.conn.selectOne(azureInstanceTable.select\ (azureInstanceTable.c.INSTANCE_NO==instanceNo)) instanceName = azureInstanceInfo['INSTANCE_NAME'] #1度も起動されていない if (isEmpty(instanceName)) : return instanceTable = self.conn.getTable("INSTANCE") instanceInfo = self.conn.selectOne(instanceTable.select\ (instanceTable.c.INSTANCE_NO==instanceNo)) platformNo = instanceInfo['PLATFORM_NO'] platformAzureTable = self.conn.getTable("PLATFORM_AZURE") platformAzureInfo = self.conn.selectOne(platformAzureTable.select\ (platformAzureTable.c.PLATFORM_NO==platformNo)) # クラウドサービス名の取得 cloudService = platformAzureInfo['CLOUD_SERVICE_NAME'] status = self.client.getVirtualMachineStatus(cloudService, instanceName) self.logger.info(' Instance: %s, Status: %s' % (instanceName, status)) if status != 'ReadyRole' and status != 'RoleStateUnknown': if status == 'StoppedVM': self.logger.info(' Instance: %s is already stopped' % (instanceName)) else: # 停止できる状態ではない。 raise IaasException("EPROCESS-000908", [instanceName, status]) else: status = self.client.stopVirtualMachine(cloudService, instanceName) # データベース更新 table = self.conn.getTable("AZURE_INSTANCE") updateDict = self.conn.selectOne(table.select(table.c.INSTANCE_NO==instanceNo)) updateDict["STATUS"] = status sql = table.update(table.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) # ボリュームに関する処理 azureDiskTable = self.conn.getTable("AZURE_DISK") disks = self.conn.select(azureDiskTable.select(azureDiskTable.c.INSTANCE_NO==instanceNo)) for azureDisk in disks: self.volumecontroller.stopVolume(instanceNo, azureDisk["DISK_NO"]) return def terminateInstance(self, instanceNo): instanceTable = self.conn.getTable("INSTANCE") instanceInfo = self.conn.selectOne(instanceTable.select\ (instanceTable.c.INSTANCE_NO==instanceNo)) platformNo = instanceInfo['PLATFORM_NO'] platformAzureTable = self.conn.getTable("PLATFORM_AZURE") platformAzureInfo = self.conn.selectOne(platformAzureTable.select\ (platformAzureTable.c.PLATFORM_NO==platformNo)) # クラウドサービス名の取得 cloudService = platformAzureInfo['CLOUD_SERVICE_NAME'] # ストレージアカウント名の取得 storageAccount = platformAzureInfo['STORAGE_ACCOUNT_NAME'] # インスタンス名の取得 azureInstanceTable = self.conn.getTable("AZURE_INSTANCE") azureInstanceInfo = self.conn.selectOne(azureInstanceTable.select\ (azureInstanceTable.c.INSTANCE_NO==instanceNo)) instanceName = azureInstanceInfo['INSTANCE_NAME'] status = self.client.getVirtualMachineStatus(cloudService, instanceName) self.logger.info(' Instance: %s, Status: %s' % (instanceName, status)) if status is None: # 既に削除されているので、何もしない self.logger.info(' Instance: %s does not exist, Status: %s' % (instanceName, status)) self.conn.info(instanceInfo["FARM_NO"], None, None, instanceNo, \ instanceInfo["INSTANCE_NAME"], "AzureInstanceNotExist",["AZURE", instanceName, status]) elif status == 'StoppedVM': self.client.deleteVirtualMachine(cloudService, instanceName, storageAccount, \ instanceNo, instanceInfo["FARM_NO"], instanceInfo["INSTANCE_NAME"]) self.logger.info(' Terminated %s' % (instanceName)) else: # 削除を許さない。 self.logger.error(' Instance: %s cannot be terminated because the status is not StoppedVM (%s)' % (instanceName, status)) self.conn.error(instanceInfo["FARM_NO"], None, None, instanceNo, \ instanceInfo["INSTANCE_NAME"], "AzureInstanceDeleteFail",["AZURE", instanceName, status]) raise IaasException("EPROCESS-000904", [instanceName]) # データベース更新 # テスト目的で、terminate後のDB状態でstart(作成)できるようにしている table = self.conn.getTable("AZURE_INSTANCE") updateDict = self.conn.selectOne(table.select(table.c.INSTANCE_NO==instanceNo)) updateDict["INSTANCE_NAME"] = None updateDict["STATUS"] = None updateDict["SUBNET_ID"] = None updateDict["PRIVATE_IP_ADDRESS"] = None sql = table.update(table.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) return def createUserData(self, instanceNo, pccInstance, azureInstance, keyPublic): table = self.conn.getTable("FARM") farm = self.conn.selectOne(table.select(table.c.FARM_NO==pccInstance["FARM_NO"])) #UserDataを作成 userData = {} #DB情報 userData.update({"instanceName": pccInstance["INSTANCE_NAME"]}) userData.update({"farmName": farm["FARM_NAME"]}) # FQDN userData.update({"hostname": pccInstance["FQDN"]}) #初期スクリプト情報 userData.update({"scriptserver": getScriptProperty("script.server")}) # Publicキー userData.update({"sshpubkey": keyPublic}) #DNS情報 userData.update(self.createDnsUserData(instanceNo)) # Puppet情報 userData.update(self.createPuppetUserData()) # VPN情報 # VPNについては別途検討とする #internal = self.platforminfo["internal"] #if (internal == 0): # userData.update(self.createVpnUserData(pccInstance)) return userData; def createDnsUserData(self,instanceNo): # UserDataを作成 userData = {} # Primary DNSサーバ userData.update({"dns": getDnsProperty("dns.server")}) # Secondry DNSサーバ dns2 = getDnsProperty("dns.server2") if (isNotEmpty(dns2)): userData.update({"dns2": dns2}) # DNSドメイン userData.update({"dnsdomain": getDnsProperty("dns.domain")}) return userData; def createPuppetUserData(self): # UserDataを作成 userData = {} # PuppetMaster情報 userData.update({"puppetmaster": getPuppetProperty("puppet.masterHost")}) return userData; def createVpnUserData(self, pccInstance): # UserDataを作成 userData = {} #VPN情報のユーザとパスワードをセットする userData.update({"vpnuser": pccInstance["FQDN"]}) userData.update({"vpnuserpass": pccInstance["INSTANCE_CODE"]}) # VPNサーバ情報 userData.update({"vpnserver": getVpnProperty("vpn.server")}) userData.update({"vpnport": getVpnProperty("vpn.port")}) # userData.update({"vpnuser": getVpnProperty("vpn.user")}) # userData.update({"vpnuserpass": getVpnProperty("vpn.userpass")}) # ZIPパスワード userData.update({"vpnzippass": getVpnProperty("vpn.zippass")}) # クライアント証明書ダウンロードURL userData.update({"vpnclienturl": getVpnProperty("vpn.clienturl")}) return userData; def makeUserData(self, map): if not map or len(map) == 0: return None userdata = '' for key in map.keys(): value = map[key] if isNotEmpty(value): if userdata != '': userdata = userdata + ';' userdata = userdata + key + "=" + value return userdata
class CloudStackLoadBalancercontroller(object): logger = IaasLogger() client = None conn = None platforminfo = None STOPPED = "STOPPED" STARTING = "STARTING" RUNNING = "RUNNING" STOPPING = "STOPPING" CONFIGURING = "CONFIGURING" WARNING = "WARNING" STATUS = { STOPPED: STOPPED, RUNNING: RUNNING, STOPPING: STOPPING, CONFIGURING: CONFIGURING, WARNING: WARNING, } def __init__(self, platforminfo, ec2iaasclientLb, conn): self.client = ec2iaasclientLb self.conn = conn self.platforminfo = platforminfo def getStatusString(self, key): if not key: return "STOPPED" value = self.STATUS[key] if value != None: return value return "STOPPED" def createLoadBalancer(self, loadBalancerNo): tableCSLB = self.conn.getTable("CLOUDSTACK_LOAD_BALANCER") csLoadBalancer = self.conn.selectOne( tableCSLB.select(tableCSLB.c.LOAD_BALANCER_NO == loadBalancerNo)) tableLB = self.conn.getTable("LOAD_BALANCER") loadBalancer = self.conn.selectOne( tableLB.select(tableLB.c.LOAD_BALANCER_NO == loadBalancerNo)) # ロードバランサ作成情報 loadBalancerName = csLoadBalancer["NAME"] #アルゴリズム algorithm = csLoadBalancer["ALGORITHM"] # ゾーン zoneid = csLoadBalancer["ZONEID"] # パブリックポート port = csLoadBalancer["PUBLICPORT"] # プライベートポート private_port = csLoadBalancer["PRIVATEPORT"] # ロードバランサの作成 balancer = self.client.createLoadBalancer(loadBalancerName, algorithm, port, private_port, zoneid) #実行ログ self.logger.info(None, "IPROCESS-200621", [ loadBalancerName, ]) # イベントログ出力 self.conn.debug(loadBalancer["FARM_NO"], None, None, None, None, "CloudStackLBCreate", ["CLOUDSTACK", loadBalancerName]) # データベース更新 updateDict = self.conn.selectOne( tableCSLB.select(tableCSLB.c.LOAD_BALANCER_NO == loadBalancerNo)) updateDict["LOAD_BALANCER_ID"] = balancer.id updateDict["PUBLICIP"] = balancer.ip updateDict["STATE"] = balancer.state updateDict["ADDRESS_ID"] = balancer.ex_public_ip_id sql = tableCSLB.update( tableCSLB.c.LOAD_BALANCER_NO == updateDict["LOAD_BALANCER_NO"], values=updateDict) self.conn.execute(sql) def deleteLoadBalancer(self, loadBalancerNo): tableCSLB = self.conn.getTable("CLOUDSTACK_LOAD_BALANCER") csLoadBalancer = self.conn.selectOne( tableCSLB.select(tableCSLB.c.LOAD_BALANCER_NO == loadBalancerNo)) tableLB = self.conn.getTable("LOAD_BALANCER") loadBalancer = self.conn.selectOne( tableLB.select(tableLB.c.LOAD_BALANCER_NO == loadBalancerNo)) # ロードバランサ loadBalancer = csLoadBalancer["LOAD_BALANCER_ID"] try: self.client.deleteLoadBalancer(loadBalancer) #実行ログ self.logger.info(None, "IPROCESS-200622", [ csLoadBalancer["NAME"], ]) # イベントログ出力 self.conn.debug(loadBalancer["FARM_NO"], None, None, None, None, "CloudStackLBDelete", ["CLOUDSTACK", csLoadBalancer["NAME"]]) except Exception: self.logger.error(traceback.format_exc()) # データベース更新 updateDict = self.conn.selectOne( tableCSLB.select(tableCSLB.c.LOAD_BALANCER_NO == loadBalancerNo)) updateDict["LOAD_BALANCER_ID"] = None updateDict["PUBLICIP"] = None updateDict["STATE"] = None updateDict["ADDRESS_ID"] = None sql = tableCSLB.update( tableCSLB.c.LOAD_BALANCER_NO == updateDict["LOAD_BALANCER_NO"], values=updateDict) self.conn.execute(sql) def configureInstances(self, loadBalancerNo): tableLBINS = self.conn.getTable("LOAD_BALANCER_INSTANCE") loadBalancerInstances = self.conn.select( tableLBINS.select(tableLBINS.c.LOAD_BALANCER_NO == loadBalancerNo)) # 振り分け設定するインスタンスがない場合はスキップ if not loadBalancerInstances or len(loadBalancerInstances) == 0: return tableLB = self.conn.getTable("LOAD_BALANCER") loadBalancer = self.conn.selectOne( tableLB.select(tableLB.c.LOAD_BALANCER_NO == loadBalancerNo)) # 振り分けを登録・解除するインスタンスを仕分けする enabledInstances = [] disabledInstances = [] # 振り分けするインスタンス情報を取得 instanceMap = {} for loadBalancerInstance in loadBalancerInstances: table = self.conn.getTable("INSTANCE") instanceNo = loadBalancerInstance["INSTANCE_NO"] #インスタンス獲得 instance = self.conn.selectOne( table.select(table.c.INSTANCE_NO == instanceNo)) instanceMap.update({instanceNo: instance}) # ロードバランサが無効の場合は振り分けを解除する if not isBit(loadBalancer["ENABLED"]): disabledInstances.append(instance) continue # インスタンスが無効の場合は振り分けを解除する if not isBit(instance["ENABLED"]): disabledInstances.append(instance) continue if isBit(loadBalancerInstance["ENABLED"]): enabledInstances.append(instance) else: disabledInstances.append(instance) # 振り分けを登録する self.registerInstances(loadBalancerNo, loadBalancer["FARM_NO"], enabledInstances, loadBalancerInstances) # 振り分けを解除する self.unregisterInstances(loadBalancerNo, loadBalancer["FARM_NO"], disabledInstances, loadBalancerInstances) def registerInstances(self, loadBalancerNo, farmNo, instances, loadBalancerInstances): if not instances or len(instances) == 0: # 振り分け登録するインスタンスがない場合はスキップ return # 振り分けされていないインスタンス番号を抽出 tmpInstances = [] for loadBalancerInstance in loadBalancerInstances: for instance in instances: if instance["INSTANCE_NO"] == loadBalancerInstance[ "INSTANCE_NO"]: status = self.getStatusString( loadBalancerInstance["STATUS"]) if status == self.STOPPED: tmpInstances.append(instance) instances = tmpInstances # 振り分けされていないインスタンスがない場合はスキップ if not instances or len(instances) == 0: return # 起動しているインスタンス番号を抽出 tmpInstanceNos = [] for instance in instances: status = self.getStatusString(instance["STATUS"]) if status == self.RUNNING: tmpInstanceNos.append(instance) instances = tmpInstanceNos if not instances or len(instances) == 0: # 起動しているインスタンスがない場合はスキップ return # AWSインスタンスのIDを取得 instanceIds = [] tableCSINS = self.conn.getTable("CLOUDSTACK_INSTANCE") for instance in instances: csInstance = self.conn.selectOne( tableCSINS.select( tableCSINS.c.INSTANCE_NO == instance["INSTANCE_NO"])) instanceIds.append(csInstance["INSTANCE_ID"]) try: # 振り分け登録 tableCSLB = self.conn.getTable("CLOUDSTACK_LOAD_BALANCER") csLoadBalancer = self.conn.selectOne( tableCSLB.select( tableCSLB.c.LOAD_BALANCER_NO == loadBalancerNo)) loadBalancerid = csLoadBalancer["LOAD_BALANCER_ID"] self.client.attach_members(loadBalancerid, instanceIds) for instanceid in instanceIds: #実行ログ self.logger.info(None, "IPROCESS-200623", [csLoadBalancer["NAME"], instanceid]) # イベントログ出力 self.conn.debug( farmNo, None, None, None, None, "CloudStackLBInstancesRegist", ["CLOUDSTACK", csLoadBalancer["NAME"], instanceid]) except Exception, e: self.logger.error(traceback.format_exc()) # ステータスの更新 tableLBINS = self.conn.getTable("LOAD_BALANCER_INSTANCE") for instance in instances: loadBalancerInstance = self.conn.selectOne( tableLBINS.select( and_( tableLBINS.c.LOAD_BALANCER_NO == loadBalancerNo, tableLBINS.c.INSTANCE_NO == instance["INSTANCE_NO"]))) loadBalancerInstance["STATUS"] = self.WARNING sql = tableLBINS.update(and_( tableLBINS.c.LOAD_BALANCER_NO == loadBalancerInstance["LOAD_BALANCER_NO"], tableLBINS.c.INSTANCE_NO == loadBalancerInstance["INSTANCE_NO"]), values=loadBalancerInstance) self.conn.execute(sql) raise # ステータスの更新 tableLBINS = self.conn.getTable("LOAD_BALANCER_INSTANCE") for instance in instances: loadBalancerInstance = self.conn.selectOne( tableLBINS.select( and_(tableLBINS.c.LOAD_BALANCER_NO == loadBalancerNo, tableLBINS.c.INSTANCE_NO == instance["INSTANCE_NO"]))) loadBalancerInstance["STATUS"] = self.RUNNING sql = tableLBINS.update(and_( tableLBINS.c.LOAD_BALANCER_NO == loadBalancerInstance["LOAD_BALANCER_NO"], tableLBINS.c.INSTANCE_NO == loadBalancerInstance["INSTANCE_NO"]), values=loadBalancerInstance) self.conn.execute(sql)
# # You should have received a copy of the GNU General Public License # along with PrimeCloud Controller(TM). If not, see <http://www.gnu.org/licenses/>. # from iaasgw.log.log import IaasLogger import base64 import hashlib import hmac import json import logging import sys import urllib import urllib2 logger = IaasLogger() class PccAPIException(Exception): """ generic zabbix api exception code list: -32602 - Invalid params (eg already exists) -32500 - no permissions """ pass class Already_Exists(PccAPIException): pass
# coding: UTF-8 # # Copyright 2014 by SCSK Corporation. # # This file is part of PrimeCloud Controller(TM). # # PrimeCloud Controller(TM) is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # PrimeCloud Controller(TM) is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PrimeCloud Controller(TM). If not, see <http://www.gnu.org/licenses/>. # from iaasgw.db.mysqlConnector import MysqlConnector from iaasgw.log.log import IaasLogger from xmlrpclib import datetime import time if __name__ == '__main__': logger = IaasLogger() logger.debug(u"テスト出力", "IPROCESS-200112", ["TEST",]) print datetime.datetime.today()
class OpenStackController(IaasController): logger = IaasLogger() conn = None accessInfo = None client = None instancecontroller = None volumecontroller = None othercontroller = None def __init__(self, conn, accessInfo, platforminfo, isLb=False): self.conn = conn self.accessInfo = accessInfo username = accessInfo['OS_ACCESS_ID'] password = accessInfo['OS_SECRET_KEY'] self.client = OpenStackIaasClient(platforminfo, username, password) #コントローラ作成 self.instancecontroller = OpenStackInstanceController( platforminfo, self.client, self.conn) self.volumecontroller = OpenStackVolumeController( platforminfo, self.client, self.conn) self.othercontroller = OpenStackOtherController( platforminfo, self.client, self.conn) def __del__(self): self.conn.rollback() self.conn.close() def startInstance(self, instanceNo): try: self.instancecontroller.startInstance(instanceNo) except Exception: self.logger.error(traceback.format_exc()) raise # ボリュームに関する処理 table = self.conn.getTable("OPENSTACK_VOLUME") volumes = self.conn.select( table.select(table.c.INSTANCE_NO == instanceNo)) for volume in volumes: if isNotEmpty(volume["COMPONENT_NO"]): # コンポーネント番号がある場合はスキップ continue #Volumeスタート self.volumecontroller.startVolume(instanceNo, volume["VOLUME_NO"]) self.conn.commit() return True def stopInstance(self, instanceNo): try: self.instancecontroller.stopInstance(instanceNo) except Exception: self.logger.error(traceback.format_exc()) raise try: # ボリュームに関する処理 tableOSVOL = self.conn.getTable("OPENSTACK_VOLUME") volumes = self.conn.select( tableOSVOL.select(tableOSVOL.c.INSTANCE_NO == instanceNo)) for volume in volumes: self.volumecontroller.stopVolume(instanceNo, volume["VOLUME_NO"]) except Exception: self.logger.error(traceback.format_exc()) self.conn.commit() return True def terminateInstance(self, instanceNo): try: self.instancecontroller.terminateInstance(instanceNo) except Exception: self.logger.error(traceback.format_exc()) raise self.conn.commit() return True def startVolume(self, instanceNo, volumeNo): try: self.volumecontroller.startVolume(instanceNo, volumeNo) except Exception: self.logger.error(traceback.format_exc()) raise self.conn.commit() return True def stopVolume(self, instanceNo, volumeNo): try: self.volumecontroller.stopVolume(instanceNo, volumeNo) except Exception: self.logger.error(traceback.format_exc()) raise self.conn.commit() return True def deleteVolume(self, volumeId): try: self.volumecontroller.deleteVolume(volumeId) except Exception: self.logger.error(traceback.format_exc()) raise self.conn.commit() return True def describeSecurityGroups(self, vpcid=None): securityGroupList = self.client.describeSecurityGroups() rtString = '' for securityGroup in securityGroupList: if rtString != '': rtString = rtString + "##" rtString = rtString + securityGroup.name + "#" + securityGroup.id return "RESULT:" + rtString def describeAvailabilityZones(self): zoneList = self.client.describeAvailabilityZones() rtString = '' for zone in zoneList: if rtString != '': rtString = rtString + "##" #必要な情報のみ返却。IDに相当するパラメータがないためNONEをセット rtString = rtString + zone.zoneName + "#NONE" return "RESULT:" + rtString def describeNetwork(self): networkList = self.client.describeNetworks() rtString = '' for nw in networkList: if rtString != '': rtString = rtString + "##" rtString = rtString + nw.id + "#" + nw.label return "RESULT:" + rtString def describeFlavors(self, flavorIds): flavorIdList = flavorIds.split(',') flavorNameList = [] flvs = self.client.describeFlavors() rtString = '' for flavorId in flavorIdList: for flv in flvs: if flv.id != flavorId: continue if rtString != '': rtString = rtString + "##" rtString = rtString + flv.id + "#" + flv.name break else: pass return "RESULT:" + rtString def describeKeyPairs(self): keypairs = self.client.describeKeyPairs() rtString = '' for keypair in keypairs: if rtString != '': rtString = rtString + "##" #とりあえず必要な情報のみ返します rtString = rtString + keypair.name self.conn.commit() return "RESULT:" + rtString def importKeyPair(self, keyName, publicKeyMaterial): self.client.createKeyPair(keyName, publicKeyMaterial) self.conn.commit() return "RESULT:" + ''
class CloudStackVolumController(object): logger = IaasLogger() client = None conn = None platforminfo = None def __init__(self, platforminfo, cs2iaasclient, conn): self.client = cs2iaasclient self.conn = conn self.platforminfo = platforminfo def startVolumes(self, instanceNo) : # ボリューム情報の取得 table = self.conn.getTable("CLOUDSTACK_VOLUME") volumes = self.conn.select(table.select(table.c.INSTANCE_NO==instanceNo)) for volume in volumes : self.startVolume(instanceNo, volume["VOLUME_NO"]) def startVolume(self, instanceNo, volumeNo) : table = self.conn.getTable("CLOUDSTACK_VOLUME") volume = self.conn.selectOne(table.select(table.c.VOLUME_NO==volumeNo)) # インスタンスIDがある場合はスキップ if (isNotEmpty(volume["INSTANCE_ID"])) : return if (isEmpty(volume["VOLUME_ID"])) : # ボリュームIDがない場合は新規作成 self.createVolume(instanceNo, volumeNo) # ボリュームのアタッチ self.attachVolume(instanceNo, volumeNo) #ディスク認識の為リブート ##self.rebootInstance(instanceNo) #起動スクリプトを待つ time.sleep(10) def stopVolumes(self, instanceNo) : # ボリューム情報の取得 csVolumes = self.geCsVolumes(instanceNo) for volume in csVolumes : self.stopVolume(instanceNo, volume["VOLUME_NO"]) def stopVolume(self, instanceNo, volumeNo): tableCSVOL = self.conn.getTable("CLOUDSTACK_VOLUME") csVolumes = self.conn.selectOne(tableCSVOL.select(tableCSVOL.c.VOLUME_NO==volumeNo)) # ボリュームIDがない場合はスキップ if (isEmpty(csVolumes["VOLUME_ID"])): return # インスタンスIDがない場合はスキップ if (isEmpty(csVolumes["INSTANCE_ID"])) : return; try : # ボリュームのデタッチ self.detachVolume(instanceNo, volumeNo) except Exception, e: self.logger.error(traceback.format_exc()) # 情報が不整合(インスタンス異常終了時など)の場合、警告ログと後始末のみ行う self.logger.warn(e.massage); updateDict = self.conn.selectOne(tableCSVOL.select(tableCSVOL.c.VOLUME_NO==volumeNo)) updateDict["STATE"] = "error" updateDict["INSTANCE_ID"] = None sql = tableCSVOL.update(tableCSVOL.c.VOLUME_NO ==updateDict["VOLUME_NO"], values=updateDict) self.conn.execute(sql)
class EC2IaasClient(EC2APNENodeDriver): logger = IaasLogger() connectionCls = EC2APNEConnection type = Provider.EC2 api_name = 'ec2_ap_northeast' name = 'Amazon EC2 (ap-northeast-1)' friendly_name = 'Amazon Asia-Pacific Tokyo' country = 'JP' region_name = 'ap-northeast-1' path = '/' platformNo = None debugout = True ############################################################ # # 基礎データ # ############################################################ def getPlatformNo(self): return self.platformNo def setPlatformNo(self, platformNo): self.platformNo = platformNo ############################################################ # # 参照系 describe # ############################################################ def describeImages(self, location=None): return None def describeImage(self, imageId): return NodeImage("IMAGEID", "IMAGELOCATION", "DRIVER", extra={ 'ROOTDEVICETYPE': "ROOTDEVICETYPE", 'PLATFORM': "PLATFORM" }) #list_nodesとして提供されているが、機能としてはインスタンス指定を利用がいいか? def describeInstances(self, instanceid): return None #list_nodesとして提供されているものをそのまま使って必要な物だけ def describeInstance(self, instanceid): extra = {} extra.update({"availability": "ap-northeast-1"}) extra.update({"dns_name": "TESTDNS"}) extra.update({"private_dns": "TEST_PDNS"}) extra.update({"private_dns": "TEST_PDNS"}) return TestModule("TEST2", "running", '0.0.0.1', '0.0.0.1', extra) #return TestModule("TEST2", "stopped", '0.0.0.1','0.0.0.1', extra) #LibCloudで提供されていない為独自実装 def describeVolume(self, volumeId): volumes = self.describeVolumes(volumeId) if not volumes or len(volumes) == 0: #インスタンスが存在しない場合 raise IaasException("EPROCESS-000110", [ volumeId, ]) if len(volumes) > 1: #インスタンスを複数参照できた場合 raise IaasException("EPROCESS-000111", [ volumeId, ]) return volumes[0] #LibCloudで提供されていない為独自実装 def describeVolumes(self, volumeId): #volume = Volume("TESTVOLID", None, None, None, 'in-use', None, None, None) volume = Volume("TESTVOLID", None, None, None, 'available', None, None, None) volumes = [ volume, ] return volumes def describeAddress(self, publicIp): address = self.describeAddresses(publicIp) if not address or len(address) == 0: #アドレスが存在しない場合 raise IaasException("EPROCESS-000117", [ publicIp, ]) if len(address) > 1: #アドレスを複数参照できた場合 raise IaasException("EPROCESS-000118", [ publicIp, ]) return address[0] #LibCloudで提供されているDescribeAddressesラップ関数は利用形態がマッチしないので独自実装とする #本来はpublicIpを省略する事も可能だが用途的に固定する def describeAddresses(self, publicIp=None): volume = Address(None, None, None) volumes = [ volume, ] return volumes #LibCloudで提供されているdescribeKeyPairsラップ関数はNameの入力が必須である為用途が異なる為、独自実装 def describeKeyPairs(self): return None #LibCloudで提供されていない為独自実装 def describeSecurityGroups(self): return None #ex_list_availability_zonesとして提供されているものをラップ def describeAvailabilityZones(self, only_available=True): zone = ExEC2AvailabilityZone("TESTTESTLB", None, None) zones = [ zone, ] return zones #LibCloudで提供されていない為独自実装 def describeSnapshot(self, snapshotId): return None #LibCloudで提供されていない為独自実装 def describeSnapshots(self, snapshotId=None): return None def describeRegions(self, regionName=None): return None def describeVpcs(self, vpcId=None): return None def describeSubnets(self, subnetId=None): return None def describeTags(self, instanceId=None): return None ############################################################ # # Instance 系 # ############################################################ #*********************そのまま***************** def runInstances(self, **kwargs): print ">>>>>>>", kwargs params = { 'Action': 'RunInstances', 'ImageId': kwargs.get('imageId'), 'InstanceType': kwargs.get('instanceType'), 'MinCount': kwargs.get('ex_mincount', '1'), 'MaxCount': kwargs.get('ex_maxcount', '1'), } if 'securityGroup' in kwargs: if not isinstance(kwargs['securityGroup'], list): kwargs['securityGroup'] = [kwargs['securityGroup']] for sig in range(len(kwargs['securityGroup'])): params['SecurityGroup.%d' % (sig + 1, )] = kwargs['securityGroup'][sig] if 'blockDeviceMapping' in kwargs: if kwargs['blockDeviceMapping']: if not isinstance(kwargs['blockDeviceMapping'], list): kwargs['blockDeviceMapping'] = [ kwargs['blockDeviceMapping'] ] for sig, blockDevice in enumerate( kwargs['blockDeviceMapping']): params['BlockDeviceMapping.%d.DeviceName' % (sig + 1, )] = blockDevice["DeviceName"] params['BlockDeviceMapping.%d.VirtualName' % (sig + 1, )] = blockDevice["VirtualName "] if 'location' in kwargs: availability_zone = kwargs['location'] if availability_zone: if availability_zone != self.region_name: raise IaasException('Invalid availability zone: %s' % availability_zone) params['Placement.AvailabilityZone'] = availability_zone if 'kernelId' in kwargs: params['KernelId'] = kwargs['kernelId'] if 'ramdiskId' in kwargs: params['RamdiskId'] = kwargs['ramdiskId'] if 'keyName' in kwargs: params['KeyName'] = kwargs['keyName'] if 'subnetId' in kwargs: params['SubnetId'] = kwargs['subnetId'] if 'userData' in kwargs: params['UserData'] = base64.b64encode(kwargs['userData']) if 'ex_clienttoken' in kwargs: params['ClientToken'] = kwargs['ex_clienttoken'] extra = {} extra.update({"availability": "TESTZONE"}) extra.update({"'dns_name'": "TESTDNS"}) extra.update({"'private_dns'": "TEST_PDNS"}) extra.update({"'private_dns'": "TEST_PDNS"}) return TestModule("TEST2", "TESTING", '0.0.0.1', '0.0.0.1', extra) #LibCloudで提供されていない為独自実装 def startInstance(self, instanceid): params = {'Action': 'StartInstances', 'InstanceId.0': instanceid} return {"code": 'code', "name": 'running'} #LibCloudで提供されていない為独自実装 def stopInstance(self, instanceid): params = {'Action': 'StopInstances', 'InstanceId.0': instanceid} return {"code": 'code', "name": 'stopped'} #本来destroy_nodeはnode自体を受け取るがこの関数はIDを受ける形とした def terminateInstance(self, instanceid): params = {'Action': 'TerminateInstances', 'InstanceId': instanceid} return {"code": 'code', "name": 'terminated'} ############################################################ # # Volume 系 # ############################################################ #LibCloudで提供されていない為独自実装 def createVolume(self, availabilityZone, size=None, snapshotId=None): params = { 'Action': 'CreateVolume', 'AvailabilityZone': availabilityZone } #任意 if size != None: params.update({'Size': size}) if snapshotId != None: params.update({'SnapshotId': snapshotId}) return Volume("TESTVOLID", None, None, None, 'available', None, None, None) #LibCloudで提供されていない為独自実装 def attachVolume(self, volumeId, instanceId, device): params = { 'Action': 'AttachVolume', 'VolumeId': volumeId, 'InstanceId': instanceId, 'Device': device } return None #LibCloudで提供されていない為独自実装 def detachVolume(self, volumeId, instanceId=None, device=None): params = {'Action': 'DetachVolume', 'VolumeId': volumeId} #任意パラメータ if instanceId != None: params.update({'InstanceId': instanceId}) if device != None: params.update({'Device': device}) return None #LibCloudで提供されていない為独自実装 def deleteVolume(self, volumeId): params = {'Action': 'DeleteVolume', 'VolumeId': volumeId} ############################################################ # # Address 系 # ############################################################ #LibCloudで提供されていない為独自実装 #Domainを指定することも可能だが無視する def allocateAddress(self): params = {'Action': 'AllocateAddress'} return None #LibCloudで提供されていない為独自実装 def associateAddress(self, publicIp, instanceId): params = { 'Action': 'AssociateAddress', 'PublicIp': publicIp, 'InstanceId': instanceId } #LibCloudで提供されていない為独自実装 def disassociateAddress(self, publicIp, instanceId): params = {'Action': 'DisassociateAddress', 'PublicIp': publicIp} #LibCloudで提供されていない為独自実装 def releaseAddress(self, publicIp): params = {'Action': 'ReleaseAddress', 'PublicIp': publicIp} ############################################################ # # KeyPair 系 # ############################################################ #LibCloudで提供されてるex_create_keypairはKeyNameを戻り値に含まない為、独自実装 def createKeyPair(self, keyName): params = {'Action': 'CreateKeyPair', 'KeyName': keyName} #LibCloudで提供されていない為独自実装 def deleteKeyPair(self, keyName): params = {'Action': 'DeleteKeyPair', 'KeyName': keyName} #LibCloudで提供されてるex_import_keypairはファイルベースの為、独自実装 def importKeyPair(self, keyName, publicKeyMaterial): ########################################### # # まだ動きません createKeyPairから直接使うとだめ # PCCで利用されていない為後回しとする # ########################################### publicKeyMaterial = base64.b64encode(publicKeyMaterial) params = { 'Action': 'ImportKeyPair', 'KeyName': keyName, 'PublicKeyMaterial': publicKeyMaterial } ############################################################ # # Snapshot 系 # ############################################################ def createSnapshot(self, volumeId, description=None): #Owner, RestorableBy, Filter(name/Value)で絞る事ができるが制限する params = {'Action': 'CreateSnapshot', 'VolumeId': volumeId} #任意パラメータ if description != None: params.update({'Description': description}) return None def deleteSnapshot(self, snapshotId): params = {'Action': 'DeleteSnapshot', 'SnapshotId': snapshotId} ############################################################ # # Tags 系 # ############################################################ def createTags(self, instanceId, tagSets): if not tagSets: return params = {'Action': 'CreateTags', 'ResourceId.0': instanceId} i = 0 for tag in tagSets: params['Tag.%d.Key' % i] = tag.key params['Tag.%d.Value' % i] = tag.value i = i + 1 # ログ出力 self.logger.info(None, "IPROCESS-100154", [instanceId, tag.key, tag.value]) def createTag(self, instanceId, tag): if not tag: return tags = [tag] self.createTags(instanceId, tags) def deleteTags(self, instanceId, tagSets): if not tagSets: return params = {'Action': 'DeleteTags', 'ResourceId.0': instanceId} i = 0 for tag in tagSets: params['Tag.%d.Key' % i] = tag.key params['Tag.%d.Value' % i] = tag.value i = i + 1 ############################################################ # # その他 # ############################################################ def getPasswordData(self, InstanceId): params = {'Action': 'GetPasswordData', 'InstanceId': InstanceId} elem = self.connection.request(self.path, params=params).object
class CloudStackIaasClient(CloudStackNodeDriver): logger = IaasLogger() platformNo = None timeout = 600 devicetype = None username = None hostid = None connectionCls = PCCCloudStackConnection def __init__(self, platforminfo, username, key, secret=None): self.platformNo = platforminfo["platformNo"] self.username = username self.logger.info(u"利用プラットフォーム" + str(self.platformNo)) #接続情報 cloudstackInfo = getCloudStackInfo(self.platformNo) host = cloudstackInfo["host"] path = cloudstackInfo["path"] port = cloudstackInfo["port"] secure = cloudstackInfo["secure"] pltfmNotimeout = cloudstackInfo["timeout"] self.devicetype = cloudstackInfo["device"] self.hostid = cloudstackInfo["hostid"] #タイムアウト if pltfmNotimeout is not None: self.connectionCls.timeout = int(pltfmNotimeout) #プロキシ利用 useProxy = platforminfo["proxy"] if useProxy == 1: useProxy = True else: useProxy = False self.connectionCls.useProxy = useProxy #プロトコル if secure == 1: secure = True else: secure = False self.logger.info(u"接続情報==> " + host + ":" + port + path + " secure=" + str(secure)) CloudStackNodeDriver.__init__(self, key=key, secret=secret, secure=secure, host=host, path=path, port=port) ############################################################ # # 基礎データ # ############################################################ def getPlatformNo(self): return self.platformNo def getDeviceType(self): return self.devicetype def getUsername(self): return self.username ############################################################ # # 参照系 describe # ############################################################ def getHypervisor(self, zoneid): args = {'zoneid': zoneid} result = self._sync_request('listHypervisors', **args) hypervisor = result.get('hypervisor', []) return hypervisor[0] def describeImages(self, location=None): args = {'templatefilter': 'executable'} if location is not None: args['zoneid'] = location.id result = self._sync_request('listTemplates', **args) imgs = result.get('template', []) return imgs def describeImage(self, imageId): images = self.describeImages() retImage = None for image in images: if imageId == image['id']: retImage = image if not retImage: #イメージが存在しない場合 raise IaasException("EPROCESS-000724", [ imageId, ]) return retImage def describeOnlyInstances(self): vms = self._sync_request('listVirtualMachines') return vms def describeInstances(self, instanceid=None, name=None): args = {} if instanceid is not None: args['id'] = instanceid if name is not None: args['name'] = name vms = self._sync_request('listVirtualMachines', **args) addrs = self._sync_request('listPublicIpAddresses') public_ips = {} for addr in addrs.get('publicipaddress', []): if 'virtualmachineid' not in addr: continue vm_id = addr['virtualmachineid'] if vm_id not in public_ips: public_ips[vm_id] = {} public_ips[vm_id][addr['ipaddress']] = addr['id'] nodes = [] for vm in vms.get('virtualmachine', []): private_ips = [] for nic in vm['nic']: if 'ipaddress' in nic: private_ips.append(nic['ipaddress']) node = CloudStackNode( id=vm['id'], name=vm.get('displayname', None), state=self.NODE_STATE_MAP[vm['state']], #Libcloudのバージョンによってはこちらを利用してください #public_ip=public_ips.get(vm['id'], {}).keys(), #private_ip=private_ips, public_ips=public_ips.get(vm['id'], {}).keys(), private_ips=private_ips, driver=self, extra={ 'zoneid': vm['zoneid'], 'serviceofferingid': vm['serviceofferingid'], 'displayname': vm['displayname'], }) addrs = public_ips.get(vm['id'], {}).items() addrs = [CloudStackAddress(node, v, k) for k, v in addrs] node.extra['ip_addresses'] = addrs nodes.append(node) return nodes def describeInstance(self, instanceid): nodes = self.describeInstances(instanceid=instanceid) if not nodes or len(nodes) == 0: #インスタンスが存在しない場合 raise IaasException("EPROCESS-000701", [ instanceid, ]) if len(nodes) > 1: #インスタンスを複数参照できた場合 raise IaasException("EPROCESS-000702", [ instanceid, ]) return nodes[0] def describeVolume(self, volumeId): volumes = self.describeVolumes(volumeId=volumeId) if not volumes or len(volumes) == 0: #インスタンスが存在しない場合 raise IaasException("EPROCESS-000705", [ volumeId, ]) if len(volumes) > 1: #インスタンスを複数参照できた場合 raise IaasException("EPROCESS-000706", [ volumeId, ]) return volumes[0] def describeVolumes(self, volumeId=None): args = {} if volumeId is not None: args['id'] = volumeId result = self._sync_request('listVolumes', **args) volumes = result.get('volume', []) return volumes def describeKeyPairs(self): result = self._sync_request('listSSHKeyPairs') keypairs = result.get('sshkeypair', []) return keypairs def describeSecurityGroups(self): result = self._sync_request('listSecurityGroups') securityGroups = result.get('securitygroup', []) return securityGroups def describeAvailabilityZones(self): result = self._sync_request('listZones') zones = result['zone'] return zones def describeSnapshot(self, snapshotId): snapshots = self.describeSnapshots(snapshotId) if not snapshots or len(snapshots) == 0: #アドレスが存在しない場合 raise IaasException("EPROCESS-000713", [ snapshotId, ]) if len(snapshots) > 1: #アドレスを複数参照できた場合 raise IaasException("EPROCESS-000714", [ snapshotId, ]) return snapshots[0] def describeSnapshots(self, snapshotId=None): args = {} if snapshotId is not None: args['id'] = snapshotId result = self._sync_request('listSnapshots', **args) snapshots = result.get('snapshot', []) return snapshots def describeLoadBalancer(self, loadBalancerid): loadBalancers = self.describeLoadBalancers(loadBalancerid) if len(loadBalancers) == 0: #インスタンスが存在しない場合 raise IaasException("EPROCESS-000719", [ loadBalancerid, ]) if len(loadBalancers) > 1: #インスタンスを複数参照できた場合 raise IaasException("EPROCESS-000720", [ loadBalancerid, ]) return loadBalancers[0] def describeLoadBalancers(self, loadBalancerid=None): args = {} if loadBalancerid is not None: args['id'] = loadBalancerid loadBalancers = self._sync_request('listLoadBalancerRules', **args) balancers = loadBalancers.get('loadbalancerrule', []) return [self._to_balancer(balancer) for balancer in balancers] def describeLoadBalancerRuleInstances(self, loadBalancerid, instances=None): balancer = self.describeLoadBalancer(loadBalancerid) members = self._sync_request('listLoadBalancerRuleInstances', id=balancer.id) members = members['loadbalancerruleinstance'] return [self._to_member(m, balancer.ex_private_port) for m in members] def describeServiceOfferings(self, domainid=None): args = {} if domainid is not None: args['domainid'] = domainid result = self._sync_request('listServiceOfferings', **args) serviceOffs = result['serviceoffering'] return serviceOffs def describeDiskOfferings(self, domainid=None): args = {} if domainid is not None: args['domainid'] = domainid result = self._sync_request('listDiskOfferings', **args) diskofferings = result['diskoffering'] return diskofferings def describeNetworks(self): result = self._sync_request('listNetworks') network = result['network'] return network def describePublicIpAddress(self, addressid): addresses = self.describePublicIpAddresses(addressid) if len(addresses) == 0: #インスタンスが存在しない場合 raise IaasException("EPROCESS-000708", [ addressid, ]) if len(addresses) > 1: #インスタンスを複数参照できた場合 raise IaasException("EPROCESS-000709", [ addressid, ]) return addresses[0] def describePublicIpAddresses(self, addressid=None): args = {} if addressid is not None: args['id'] = addressid result = self._sync_request('listPublicIpAddresses', **args) network = result['publicipaddress'] return network ############################################################ # # Instance 系 # ############################################################ def runInstances(self, name, dname, serviceofferingid, imageid, zoneid, **kwargs): extra_args = {} if zoneid is None: location = self.describeAvailabilityZones()[0] zoneid = location['id'] #以下任意パラメータ if self.hostid is not None: extra_args['hostid'] = self.hostid network_id = kwargs.pop('network_id', None) if network_id is not None: extra_args['networkids'] = network_id securityGroups = kwargs.pop('securitygroupids', None) if securityGroups is not None: extra_args['securitygroupnames'] = securityGroups keypair = kwargs.pop('keypair', None) if keypair is not None: extra_args['keypair'] = keypair userdata = kwargs.pop('userdata', None) if userdata is not None: extra_args['userdata'] = base64.b64encode(userdata) #インスタンス作成 result = self._async_request('deployVirtualMachine', name=name, displayname=dname, serviceofferingid=serviceofferingid, templateid=imageid, zoneid=zoneid, **extra_args) node = None if 'virtualmachine' in result: node = result['virtualmachine'] else: raise IaasException("EPROCESS-000703", []) return node def startInstance(self, instanceid): params = { 'id': instanceid, } result = self._async_request('startVirtualMachine', **params) node = None if 'virtualmachine' in result: node = result['virtualmachine'] else: raise IaasException("EPROCESS-000715", []) return node def changeInstance(self, instanceid, serviceofferingid): params = {'id': instanceid, 'serviceofferingid': serviceofferingid} result = self._sync_request('changeServiceForVirtualMachine', **params) node = None if 'virtualmachine' in result: node = result['virtualmachine'] else: raise IaasException("EPROCESS-000715", []) return node def stopInstance(self, instanceid): params = {'id': instanceid} result = self._async_request('stopVirtualMachine', **params) node = None if 'virtualmachine' in result: node = result['virtualmachine'] else: raise IaasException("EPROCESS-000717", []) return node #本来destroy_nodeはnode自体を受け取るがこの関数はIDを受ける形とした def terminateInstance(self, instanceid): result = self._async_request('destroyVirtualMachine', id=instanceid) node = None if 'virtualmachine' in result: node = result['virtualmachine'] else: raise IaasException("EPROCESS-000704", []) return node def rebootInstance(self, instanceid): params = {'id': instanceid} result = self._async_request('rebootVirtualMachine', **params) node = None if 'virtualmachine' in result: node = result['virtualmachine'] else: raise IaasException("EPROCESS-000717", []) return node ############################################################ # # Volume 系 # ############################################################ def createVolume(self, name, location=None, size=None, snapshotId=None, diskid=None, iscustomized=True): args = {} if snapshotId is None and diskid is None: # ボリューム作成失敗時 raise IaasException("**********") if snapshotId is not None: args['snapshotid'] = snapshotId if diskid is not None: args['diskofferingid'] = diskid if size is not None and iscustomized: args['size'] = str(size) if location is None: location = self.describeAvailabilityZones()[0]["id"] args['zoneid'] = location result = self._async_request('createVolume', name=name, **args) volume = None if 'volume' in result: volume = result['volume'] else: raise IaasException("EPROCESS-000707", []) return volume def attachVolume(self, volumeId, instanceId, deviceid=None): args = {} if deviceid is not None: args['deviceid'] = deviceid result = self._async_request('attachVolume', id=volumeId, virtualmachineid=instanceId, **args) volume = result['volume'] return volume def detachVolume(self, volumeId, instanceId=None, deviceid=None): args = {} if volumeId is not None: args['id'] = volumeId else: if deviceid is not None: args['deviceid'] = deviceid if instanceId is not None: args['virtualmachineid'] = instanceId result = self._async_request('detachVolume', **args) volume = result['volume'] return volume def deleteVolume(self, volumeId): result = self._sync_request('deleteVolume', id=volumeId) if result.get('success', '').lower() != 'true': return False else: return True ############################################################ # # Address 系 # ############################################################ def enableStaticNat(self, addressid, virtualmachineid): result = self._sync_request('enableStaticNat', ipaddressid=addressid, virtualmachineid=virtualmachineid) if result.get('success', '').lower() != 'true': return False else: return True def associateAddress(self, zoneid=None): #渡されてなければデフォルトゾーン if zoneid is None: zoneid = self.describeAvailabilityZones()[0]["id"] result = self._sync_request('associateIpAddress', zoneid=zoneid) addressid = result['id'] return addressid def disassociateAddress(self, addressid): result = self._async_request('disassociateIpAddress', id=addressid) if result['success'] != 'true': return False else: return True def disableStaticNat(self, addressid): result = self._async_request('disableStaticNat', ipaddressid=addressid) if result['success'] != 'true': return False else: return True ############################################################ # # KeyPair 系 # ############################################################ def createKeyPair(self, keyName): result = self._sync_request('createSSHKeyPair', name=keyName) keyPair = result['keypair'] return keyPair def deleteKeyPair(self, keyName): result = self._sync_request('deleteSSHKeyPair', name=keyName) if result.get('success', '').lower() != 'true': return False else: return True def registerSSHKeyPair(self, keyName, keyMaterial): result = self._sync_request('registerSSHKeyPair', name=keyName, publickey=keyMaterial) keypair = result['keypair'] keyFingerprint = keypair['fingerprint'] return keyFingerprint ############################################################ # # Snapshot 系 # ############################################################ def createSnapshot(self, volumeId): result = self._async_request('createSnapshot', volumeid=volumeId) snapshot = result['snapshot'] return snapshot def deleteSnapshot(self, snapshotId): result = self._async_request('deleteSnapshot', id=snapshotId) if result['success'] != 'true': return False else: return True ############################################################ # # Tags 系 # ############################################################ #存在しません ############################################################ # # その他 # ############################################################ def getPasswordData(self, instanceId): try: result = self._sync_request('getVMPassword', id=instanceId) password = result['password'] encryptedpassword = password['encryptedpassword'] except Exception: raise IaasException("EPROCESS-000721", [ instanceId, ]) return encryptedpassword ############################################################ # # LoadBalancer 操作系 # ############################################################ ALGORITHM_ROUND_ROBIN = 'roundrobin' ALGORITHM_LEAST_CONNECTIONS = 'leastconn' def createLoadBalancer(self, name, algorithm=None, port=80, private_port=None, zoneid=None, addressid=None): if algorithm is None: algorithm = self.ALGORITHM_ROUND_ROBIN if zoneid is None: zoneid = self.describeAvailabilityZones()[0]['id'] else: zoneid = zoneid if private_port is None: private_port = port if addressid is None: result = self._async_request('associateIpAddress', zoneid=zoneid) addressid = result['ipaddress']['id'] result = self._sync_request( 'createLoadBalancerRule', algorithm=algorithm, name=name, privateport=private_port, publicport=port, publicipid=addressid, ) balancerid = result['id'] balancer = self.describeLoadBalancer(balancerid) return balancer def deleteLoadBalancer(self, loadBalancerid): balancer = self.describeLoadBalancer(loadBalancerid) self._async_request('deleteLoadBalancerRule', id=balancer.id) self._async_request('disassociateIpAddress', id=balancer.ex_public_ip_id) def attach_members(self, loadBalancerid, virtualmachineids): for virtualmachineid in virtualmachineids: self._async_request('assignToLoadBalancerRule', id=loadBalancerid, virtualmachineids=virtualmachineid) return True def detach_members(self, loadBalancerid, virtualmachineids): for virtualmachineid in virtualmachineids: self._async_request('removeFromLoadBalancerRule', id=loadBalancerid, virtualmachineids=virtualmachineid) return True def _to_balancer(self, obj): balancer = LoadBalancer(id=obj['id'], name=obj['name'], state=obj['state'], ip=obj['publicip'], port=obj['publicport'], driver=self.connection.driver) balancer.ex_private_port = obj['privateport'] balancer.ex_public_ip_id = obj['publicipid'] return balancer def _to_member(self, obj, port): return Member(id=obj['id'], ip=obj['nic'][0]['ipaddress'], port=port)
class ec2LoadBalancercontroller(object): logger = IaasLogger() client = None conn = None platforminfo = None STOPPED = "STOPPED" STARTING = "STARTING" RUNNING = "RUNNING" STOPPING = "STOPPING" CONFIGURING = "CONFIGURING" WARNING = "WARNING" STATUS={ STOPPED:STOPPED, RUNNING:RUNNING, STOPPING:STOPPING, CONFIGURING:CONFIGURING, WARNING:WARNING, } def __init__(self, platforminfo, ec2iaasclientLb, conn): self.client = ec2iaasclientLb self.conn = conn self.platforminfo = platforminfo def getStatusString(self, key): if not key: return "STOPPED" value = self.STATUS[key] if value != None: return value return "STOPPED" def createLoadBalancer(self, farmNo, loadBalancerNo, availabilityZones, subnets, groupmap) : tableAWSLB = self.conn.getTable("AWS_LOAD_BALANCER") awsLoadBalancer = self.conn.selectOne(tableAWSLB.select(tableAWSLB.c.LOAD_BALANCER_NO==loadBalancerNo)) # ロードバランサ作成情報 loadBalancerName = awsLoadBalancer["NAME"] # 内部ロードバランサ internal = awsLoadBalancer["INTERNAL"] # デフォルトゾーンの特定 デフォルト1件目 availabilityZone = None for zone in availabilityZones: availabilityZone = zone.name #セキュリティグループ securityGroups = [] if (isNotEmpty(awsLoadBalancer["SECURITY_GROUPS"])): securityGroups = awsLoadBalancer["SECURITY_GROUPS"].split(",") #サブネットID subnetIds = [] if (isNotEmpty(awsLoadBalancer["SUBNET_ID"])): subnetIds = awsLoadBalancer["SUBNET_ID"].split(",") # サブネット(VPC)との関係からセキュリティグループIDを取得 securityGroupIds = [] if len(subnetIds) != 0: for subnet in subnets: if subnetIds[0] == subnet.subnetId: #セキュリティグループID for group in securityGroups: key = group+subnet.vpcId securityGroupIds.append(groupmap[key]) # ダミーのリスナーの設定 instancePort, instanceProtocol, loadBalancerPort, protocol, sslCertificateId listener = Listener("65535", None, "65535","TCP",None) listeners = [listener] # ロードバランサの作成 dnsName = self.client.createLoadBalancer(availabilityZone, listeners, loadBalancerName, subnetIds, securityGroupIds, internal) #実行ログ self.logger.info(None ,"IPROCESS-200111", [awsLoadBalancer["NAME"],]) # イベントログ出力 self.conn.debug(farmNo, None, None, None, None, "AwsElbCreate", ["EC2", loadBalancerName] ) # ダミーのリスナーの削除 self.client.deleteLoadBalancerListeners(["65535",], loadBalancerName) #クロスゾーン負荷分散を有効化 self.client.modifyLoadBalancer(loadBalancerName) #実行ログ self.logger.info(None ,"IPROCESS-200226", [awsLoadBalancer["NAME"],]) # イベントログ出力 self.conn.debug(farmNo, None, None, None, None, "AwsCrossZoneEnabled", ["EC2", loadBalancerName] ) # データベース更新 updateDict = self.conn.selectOne(tableAWSLB.select(tableAWSLB.c.LOAD_BALANCER_NO==loadBalancerNo)) updateDict["DNS_NAME"] = dnsName sql = tableAWSLB.update(tableAWSLB.c.LOAD_BALANCER_NO ==updateDict["LOAD_BALANCER_NO"], values=updateDict) self.conn.execute(sql) return dnsName; def deleteLoadBalancer(self, farmNo, loadBalancerNo) : tableAWSLB = self.conn.getTable("AWS_LOAD_BALANCER") awsLoadBalancer = self.conn.selectOne(tableAWSLB.select(tableAWSLB.c.LOAD_BALANCER_NO==loadBalancerNo)) # ロードバランサ名 loadBalancerName = awsLoadBalancer["NAME"] try : self.client.deleteLoadBalancer(loadBalancerName); #実行ログ self.logger.info(None ,"IPROCESS-200112", [awsLoadBalancer["NAME"],]) # イベントログ出力 self.conn.debug(farmNo, None, None, None, None, "AwsElbDelete", ["EC2", loadBalancerName] ) except Exception: self.logger.error(traceback.format_exc()) # データベース更新 updateDict = self.conn.selectOne(tableAWSLB.select(tableAWSLB.c.LOAD_BALANCER_NO==loadBalancerNo)) updateDict["DNS_NAME"] = None sql = tableAWSLB.update(tableAWSLB.c.LOAD_BALANCER_NO ==updateDict["LOAD_BALANCER_NO"], values=updateDict) self.conn.execute(sql) def configureListeners(self, farmNo, loadBalancerNo) : table = self.conn.getTable("LOAD_BALANCER_LISTENER") listeners = self.conn.select(table.select(table.c.LOAD_BALANCER_NO==loadBalancerNo)) # リスナーの起動・停止処理 for listener in listeners : status = self.getStatusString(listener["STATUS"]) if isBit(listener["ENABLED"]): if status == self.STOPPED : # 有効で停止しているリスナーは処理対象 self.startListener(farmNo, loadBalancerNo, listener["LOAD_BALANCER_PORT"]) elif status == self.RUNNING: # 有効で起動しているリスナーの場合、処理を行わずにフラグを変更する if isBit(listener["CONFIGURE"]): listener["CONFIGURE"] = "0" sql = table.update(and_(table.c.LOAD_BALANCER_NO ==listener["LOAD_BALANCER_NO"], table.c.LOAD_BALANCER_PORT == listener["LOAD_BALANCER_PORT"]), values=listener) self.conn.execute(sql) else : if (status == self.RUNNING or status == self.WARNING) : # 無効で起動または異常なリスナーは処理対象 self.stopListener(farmNo, loadBalancerNo, listener["LOAD_BALANCER_PORT"]) elif (status == self.STOPPED) : # 無効で停止しているリスナーの場合、処理を行わずにフラグを変更する if isBit(listener["CONFIGURE"]): listener["CONFIGURE"] = "0" sql = table.update(and_(table.c.LOAD_BALANCER_NO ==loadBalancerNo, table.c.LOAD_BALANCER_PORT == listener["LOAD_BALANCER_PORT"]), values=listener) self.conn.execute(sql) def startListener(self, farmNo, loadBalancerNo, loadBalancerPort) : table = self.conn.getTable("LOAD_BALANCER_LISTENER") listener = self.conn.selectOne(table.select(and_(table.c.LOAD_BALANCER_NO==loadBalancerNo, table.c.LOAD_BALANCER_PORT ==loadBalancerPort))) try : # リスナー作成情報 tableAWSLB = self.conn.getTable("AWS_LOAD_BALANCER") awsLoadBalancer = self.conn.selectOne(tableAWSLB.select(tableAWSLB.c.LOAD_BALANCER_NO==loadBalancerNo)) sslKey = None if (isNotEmpty(listener["SSL_KEY_NO"])): # リスナー作成情報 tableAWSSSL = self.conn.getTable("AWS_SSL_KEY") awsSslKey = self.conn.selectOne(tableAWSSSL.select(tableAWSSSL.c.KEY_NO==listener["SSL_KEY_NO"])) sslKey = awsSslKey["SSLCERTIFICATEID"] # ロードバランサ名 loadBalancerName = awsLoadBalancer["NAME"] # リスナーの設定 instancePort, instanceProtocol, loadBalancerPort, protocol, sslCertificateId listeners = [ Listener(listener["SERVICE_PORT"], None, listener["LOAD_BALANCER_PORT"], listener["PROTOCOL"], sslKey),] # リスナーの作成 self.client.createLoadBalancerListeners(listeners, loadBalancerName) #実行ログ self.logger.info(None ,"IPROCESS-200121", [awsLoadBalancer["NAME"], listener["LOAD_BALANCER_PORT"]]) # イベントログ出力 self.conn.debug(farmNo, None, None, None, None, "AwsElbListenerCreate", ["EC2", loadBalancerName, listener["LOAD_BALANCER_PORT"]] ) except Exception: self.logger.error(traceback.format_exc()) # ステータスを更新 tableLBL = self.conn.getTable("LOAD_BALANCER_LISTENER") updateDict = self.conn.selectOne(tableLBL.select(and_(tableLBL.c.LOAD_BALANCER_NO==loadBalancerNo, tableLBL.c.LOAD_BALANCER_PORT ==loadBalancerPort))) updateDict["STATUS"] = self.WARNING sql = tableLBL.update(and_(tableLBL.c.LOAD_BALANCER_NO==loadBalancerNo, tableLBL.c.LOAD_BALANCER_PORT ==loadBalancerPort), values=updateDict) self.conn.execute(sql) raise # ステータスを更新 tableLBL = self.conn.getTable("LOAD_BALANCER_LISTENER") updateDict = self.conn.selectOne(table.select(and_(tableLBL.c.LOAD_BALANCER_NO==loadBalancerNo, tableLBL.c.LOAD_BALANCER_PORT ==loadBalancerPort))) updateDict["STATUS"] = self.RUNNING sql = tableLBL.update(and_(tableLBL.c.LOAD_BALANCER_NO==loadBalancerNo, tableLBL.c.LOAD_BALANCER_PORT ==loadBalancerPort), values=updateDict) self.conn.execute(sql) def stopListener(self, farmNo, loadBalancerNo, loadBalancerPort) : tableLBL = self.conn.getTable("LOAD_BALANCER_LISTENER") listener = self.conn.selectOne(tableLBL.select(and_(tableLBL.c.LOAD_BALANCER_NO==loadBalancerNo, tableLBL.c.LOAD_BALANCER_PORT ==loadBalancerPort))) try : # リスナー削除情報 table = self.conn.getTable("AWS_LOAD_BALANCER") awsLoadBalancer = self.conn.selectOne(table.select(table.c.LOAD_BALANCER_NO==loadBalancerNo)) # ロードバランサ名 loadBalancerName = awsLoadBalancer["NAME"] # ロードバランサポート loadBalancerPort = listener["LOAD_BALANCER_PORT"] loadBalancerPorts = [loadBalancerPort,] # リスナーの削除 self.client.deleteLoadBalancerListeners(loadBalancerPorts, loadBalancerName); #実行ログ self.logger.info(None ,"IPROCESS-200122", [awsLoadBalancer["NAME"], listener["LOAD_BALANCER_PORT"]]) # イベントログ出力 self.conn.debug(farmNo, None, None, None, None, "AwsElbListenerDelete", ["EC2", loadBalancerName, listener["LOAD_BALANCER_PORT"]] ) except Exception, e: self.logger.error(traceback.format_exc()) self.logger.warn(e.getMessage()) # ステータスを更新 updateDict = self.conn.selectOne(tableLBL.select(and_(tableLBL.c.LOAD_BALANCER_NO==loadBalancerNo, tableLBL.c.LOAD_BALANCER_PORT ==loadBalancerPort))) updateDict["STATUS"] = self.STOPPED sql = tableLBL.update(and_(tableLBL.c.LOAD_BALANCER_NO==loadBalancerNo, tableLBL.c.LOAD_BALANCER_PORT ==loadBalancerPort), values=updateDict) self.conn.execute(sql)
class ec2AddressController(object): client = None conn = None logger = IaasLogger() platforminfo = None def __init__(self, platforminfo, ec2iaasclient, conn): self.client = ec2iaasclient self.conn = conn self.platforminfo = platforminfo def startAddress(self, instanceNo): # アドレス情報の取得 awsAddress = self.getAwsAddress(instanceNo) if not awsAddress: # アドレス情報がない場合は終了 return if isNotEmpty(awsAddress["INSTANCE_ID"]): # インスタンスIDがある場合はスキップ return addressNo = awsAddress["ADDRESS_NO"] # アドレスのステータスチェック self.checkAvailableAddress(instanceNo, addressNo) # アドレスの関連付け self.associateAddress(instanceNo, addressNo) def stopAddress(self, instanceNo): # アドレス情報の取得 awsAddress = self.getAwsAddress(instanceNo) # アドレス情報がない場合は終了 if not awsAddress: return # インスタンスIDがない場合はスキップ if isEmpty(awsAddress["INSTANCE_ID"]): return addressNo = awsAddress["ADDRESS_NO"] try: # アドレスのステータスチェック self.checkAssociatedAddress(instanceNo, addressNo) # アドレスの切り離し self.disassociateAddress(instanceNo, addressNo) except Exception, e: # 情報が不整合(インスタンス異常終了時など)の場合、警告ログと後始末のみ行う self.logger.warn(e.__repr__()) table = self.conn.getTable("AWS_ADDRESS") updateDict = self.conn.selectOne( table.select(table.c.ADDRESS_NO == addressNo)) updateDict["INSTANCE_ID"] = None sql = table.update(table.c.ADDRESS_NO == updateDict["ADDRESS_NO"], values=updateDict) self.conn.execute(sql)
class MysqlConnector(object): logger = IaasLogger() session = None userNo = None LOGLEVEL = { "OFF": 100, "ERROR": 40, "WARN": 30, "INFO": 20, "DEBUG": 10, "ALL": 100, } def __init__(self, userNo=None): #self.logger.info(connectinfo) self.session = Session() self.userNo = userNo def getTable(self, tableName): table_object = Table(tableName, METADATA, autoload=True) return table_object def execute(self, sql, autocommit=True): res = self.session.execute(sql) if autocommit == True: self.commit() return res.rowcount def selectOne(self, sql): res = self.select(sql) if res: return res[0] else: return None def select(self, sql): #res = sql.execute() res = self.session.execute(sql) values = res.fetchall() keys = res.keys() rs = [] for row in values: rec = {} for i, item in enumerate(keys): rec.update({item: row[i]}) rs.append(rec) return rs def rollback(self): return self.session.rollback() def commit(self): return self.session.commit() def close(self): self.session.close() #基本的に利用しないでください def remakeSession(self): self.session.close() self.session = Session() ##################################################### # #以下イベントログ登録 # ##################################################### def error(self, farmNo, componentNo, componentName, instanceNo, instanceName, code, additions): self.beforOutLog("ERROR", farmNo, componentNo, componentName, instanceNo, instanceName, code, additions) def warn(self, farmNo, componentNo, componentName, instanceNo, instanceName, code, additions): self.beforOutLog("WARN", farmNo, componentNo, componentName, instanceNo, instanceName, code, additions) def info(self, farmNo, componentNo, componentName, instanceNo, instanceName, code, additions): self.beforOutLog("INFO", farmNo, componentNo, componentName, instanceNo, instanceName, code, additions) def debug(self, farmNo, componentNo, componentName, instanceNo, instanceName, code, additions): self.beforOutLog("DEBUG", farmNo, componentNo, componentName, instanceNo, instanceName, code, additions) def beforOutLog(self, logLevel, farmNo, componentNo, componentName, instanceNo, instanceName, code, additions): farmT = Table("FARM", METADATA, autoload=True) farm = self.selectOne(farmT.select(farmT.c.FARM_NO == farmNo)) farmName = None if farm is not None: farmName = farm["FARM_NAME"] userT = Table("USER", METADATA, autoload=True) user = self.selectOne(userT.select(userT.c.USER_NO == self.userNo)) userName = None if user is not None: userName = user["USERNAME"] instanceType = None platformNo = None if instanceNo is not None: instanceT = Table("INSTANCE", METADATA, autoload=True) instance = self.selectOne( instanceT.select(instanceT.c.INSTANCE_NO == instanceNo)) if instance is not None: platformNo = instance["PLATFORM_NO"] isSelect = True if isSelect: awsinstanceT = Table("AWS_INSTANCE", METADATA, autoload=True) awsinstance = self.selectOne( awsinstanceT.select( awsinstanceT.c.INSTANCE_NO == instanceNo)) if awsinstance is not None: instanceType = awsinstance["INSTANCE_TYPE"] isSelect = False if isSelect: csinstanceT = Table("CLOUDSTACK_INSTANCE", METADATA, autoload=True) csinstance = self.selectOne( csinstanceT.select( csinstanceT.c.INSTANCE_NO == instanceNo)) if csinstance is not None: instanceType = csinstance["INSTANCE_TYPE"] isSelect = False if isSelect: vminstanceT = Table("VMWARE_INSTANCE", METADATA, autoload=True) vminstance = self.selectOne( vminstanceT.select( vminstanceT.c.INSTANCE_NO == instanceNo)) if vminstance is not None: instanceType = vminstance["INSTANCE_TYPE"] isSelect = False if isSelect: nifinstanceT = Table("NIFTY_INSTANCE", METADATA, autoload=True) nifinstance = self.selectOne( nifinstanceT.select( nifinstanceT.c.INSTANCE_NO == instanceNo)) if nifinstance is not None: instanceType = nifinstance["INSTANCE_TYPE"] isSelect = False self.outLog(logLevel, self.userNo, userName, farmNo, farmName, componentNo, componentName, instanceNo, instanceName, code, instanceType, platformNo, additions) def outLog(self, logLevel, userNo, userName, farmNo, farmName, componentNo, componentName, instanceNo, instanceName, code, instanceType, platformNo, additions): # イベントログメッセージの取得 message = getMassage(code, additions) log_table = Table("EVENT_LOG", METADATA2, autoload=True) log_table.insert({ "LOG_NO": None, "LOG_DATE": datetime.datetime.today(), "LOG_LEVEL": self.LOGLEVEL[logLevel], "USER_NO": userNo, "USER_NAME": userName, "FARM_NO": farmNo, "FARM_NAME": farmName, "COMPONENT_NO": componentNo, "COMPONENT_NAME": componentName, "INSTANCE_NO": instanceNo, "INSTANCE_NAME": instanceName, "MESSAGE_CODE": code, "MESSAGE": message, "INSTANCE_TYPE": instanceType, "PLATFORM_NO": platformNo }).execute()
class EC2Controller(IaasController): logger = IaasLogger() conn = None accessInfo = None client = None clientLb = None instancecontroller = None volumecontroller = None addresscontroller = None loadBalancercontroller = None othercontroller = None def __init__(self, conn, accessInfo, platforminfo, isLb = False): self.conn = conn self.accessInfo = accessInfo self.client = EC2IaasClient(platforminfo, accessInfo["USER_NAME"], accessInfo["ACCESS_ID"], accessInfo["SECRET_KEY"]) #コントローラ作成 self.instancecontroller = ec2InstanceController(platforminfo, self.client, self.conn) self.volumecontroller = ec2VolumController(platforminfo, self.client, self.conn) self.addresscontroller = ec2AddressController(platforminfo, self.client, self.conn) self.othercontroller = ec2OtherController(platforminfo, self.client, self.conn) if isLb: #self.clientLb = ec2iaasclientLB(userInfo.getAccessId(), userInfo.getSecretKey) self.clientLb = EC2IaasClientLB(platforminfo, accessInfo["USER_NAME"], accessInfo["ACCESS_ID"], accessInfo["SECRET_KEY"]) #コントローラ作成 self.loadBalancercontroller = ec2LoadBalancercontroller(platforminfo, self.clientLb, self.conn) def __del__(self): self.conn.rollback() self.conn.close() def startInstance(self, instanceNo): # インスタンスに関する処理 TODO タイムアウトリトライは未実装 try: self.instancecontroller.startInstance(instanceNo) except Exception: self.logger.error(traceback.format_exc()) raise # ボリュームに関する処理 table = self.conn.getTable("AWS_VOLUME") volumes = self.conn.select(table.select(table.c.INSTANCE_NO==instanceNo)) for volume in volumes: if isNotEmpty(volume["COMPONENT_NO"]): # コンポーネント番号がある場合はスキップ continue #Volumeスタート self.volumecontroller.startVolume(instanceNo, volume["VOLUME_NO"]) # アドレスに関する処理 self.addresscontroller.startAddress(instanceNo) self.conn.commit() return "RESULT:TRUE" def stopInstance(self, instanceNo): try : # アドレスに関する処理 self.addresscontroller.stopAddress(instanceNo) except Exception: self.logger.error(traceback.format_exc()) try : # インスタンスに関する処理 self.instancecontroller.stopInstance(instanceNo); except Exception: self.logger.error(traceback.format_exc()) try : # ボリュームに関する処理 tableAWSVOL = self.conn.getTable("AWS_VOLUME") volumes = self.conn.select(tableAWSVOL.select(tableAWSVOL.c.INSTANCE_NO==instanceNo)) #PCC_INSTANCE 取得 tableINS = self.conn.getTable("INSTANCE") pccInstance = self.conn.selectOne(tableINS.select(tableINS.c.INSTANCE_NO==instanceNo)) #イメージの取得 再考の余地あり image = getImage(pccInstance["IMAGE_NO"]) for awsVolume in volumes: if (image["ebsImage"]=="true"): self.volumecontroller.stopVolume(instanceNo, awsVolume["VOLUME_NO"]) else: if (isNotEmpty(awsVolume["VOLUME_ID"]) and isNotEmpty(awsVolume["INSTANCE_ID"])): updateDict = self.conn.selectOne(tableAWSVOL.select(tableAWSVOL.c.VOLUME_NO==awsVolume["VOLUME_NO"])) updateDict["STATUS"] = None updateDict["INSTANCE_ID"] = None sql = tableAWSVOL.update(tableAWSVOL.c.VOLUME_NO ==updateDict["VOLUME_NO"], values=updateDict) self.conn.execute(sql) except Exception: self.logger.error(traceback.format_exc()) self.conn.commit() return "RESULT:TRUE" def terminateInstance(self, instanceId): #1度も起動されていない if instanceId is None: return #AWS_INSTANCE 取得 tableAWSINS = self.conn.getTable("AWS_INSTANCE") awsInstance = self.conn.selectOne(tableAWSINS.select(tableAWSINS.c.INSTANCE_ID==instanceId)) # インスタンスの停止 change = self.client.terminateInstance(instanceId); # データベース更新 awsInstance["STATUS"] = change["name"] sql = tableAWSINS.update(tableAWSINS.c.INSTANCE_NO ==awsInstance["INSTANCE_NO"], values=awsInstance) self.conn.execute(sql) self.conn.commit() return "RESULT:TRUE" def startVolume(self, instanceNo, volumeNo): self.volumecontroller.startVolume(instanceNo, volumeNo) self.conn.commit() return "RESULT:TRUE" def stopVolume(self, instanceNo, volumeNo): self.volumecontroller.stopVolume(instanceNo, volumeNo) self.conn.commit() return "RESULT:TRUE" def deleteVolume(self, volumeId): self.client.deleteVolume(volumeId) self.conn.commit() return "RESULT:TRUE" def startLoadBalancer(self, loadBalancerNo): tableLB = self.conn.getTable("LOAD_BALANCER") loadBalancer = self.conn.selectOne(tableLB.select(tableLB.c.LOAD_BALANCER_NO==loadBalancerNo)) # ゾーン情報の取得 zones = self.client.describeAvailabilityZones() # サブネットID subnets = self.client.describeSubnets() # セキュリティグループ groups = self.client.describeSecurityGroups() groupmap = {} for group in groups: if group.vpcId is not None: key = group.groupName+group.vpcId groupmap.update({key:group.groupId}) # ロードバランサの作成 self.loadBalancercontroller.createLoadBalancer(loadBalancer["FARM_NO"], loadBalancerNo, zones, subnets, groupmap) # DNSサーバへの追加 ここは未定 #self.loadBalancercontroller.addDns(loadBalancerNo) self.conn.commit() return "RESULT:TRUE" def stopLoadBalancer(self, loadBalancerNo): tableLB = self.conn.getTable("LOAD_BALANCER") loadBalancer = self.conn.selectOne(tableLB.select(tableLB.c.LOAD_BALANCER_NO==loadBalancerNo)) # DNSサーバからの削除 #self.loadBalancercontroller.deleteDns(loadBalancerNo); # ロードバランサの削除 self.loadBalancercontroller.deleteLoadBalancer(loadBalancer["FARM_NO"],loadBalancerNo) self.conn.commit() return "RESULT:TRUE" def configureLoadBalancer(self, loadBalancerNo): table = self.conn.getTable("LOAD_BALANCER") loadBalancer = self.conn.selectOne(table.select(table.c.LOAD_BALANCER_NO==loadBalancerNo)) # リスナーの設定 try : self.loadBalancercontroller.configureListeners(loadBalancer["FARM_NO"], loadBalancerNo) except Exception: self.logger.error(traceback.format_exc()) # ロードバランサが無効な場合は例外を握りつぶす if isBit(loadBalancer["ENABLED"]): raise # ヘルスチェックの設定 try : self.loadBalancercontroller.configureHealthCheck(loadBalancer["FARM_NO"], loadBalancerNo) except Exception: self.logger.error(traceback.format_exc()) # ロードバランサが無効な場合は例外を握りつぶす if isBit(loadBalancer["ENABLED"]): raise # セキュリティグループの設定 try : # サブネットID subnets = self.client.describeSubnets() # セキュリティグループ groups = self.client.describeSecurityGroups() groupmap = {} for group in groups: if group.vpcId is not None: key = group.groupName+group.vpcId groupmap.update({key:group.groupId}) self.loadBalancercontroller.applySecurityGroupsToLoadBalancer(loadBalancer["FARM_NO"], loadBalancerNo, groupmap, subnets) except Exception: self.logger.error(traceback.format_exc()) # ロードバランサが無効な場合は例外を握りつぶす if isBit(loadBalancer["ENABLED"]): raise # インスタンスの振り分け設定 try : self.loadBalancercontroller.configureInstances(loadBalancer["FARM_NO"], loadBalancerNo); except Exception: self.logger.error(traceback.format_exc()) # ロードバランサが無効な場合は例外を握りつぶす if isBit(loadBalancer["ENABLED"]): raise self.logger.info(None, "IPROCESS-200106", [loadBalancerNo, loadBalancer["LOAD_BALANCER_NAME"]]) self.conn.commit() return "RESULT:TRUE" def allocateAddress(self): publicIp = None platformNo = self.client.getPlatformNo() tablePLAWS = self.conn.getTable("PLATFORM_AWS") awsPlatform = self.conn.selectOne(tablePLAWS.select(tablePLAWS.c.PLATFORM_NO==platformNo)) if awsPlatform["VPC"] == 1: #VPC用のElasticIP発行処理呼び出し publicIp = self.client.allocateVpcAddress() else: #ElasticIP発行処理呼び出し publicIp = self.client.allocateAddress() #イベントログ出力 self.conn.debug(None, None, None, None, None, "AwsElasticIpAllocate", ["EC2", publicIp]) #DBへ登録 table = self.conn.getTable("AWS_ADDRESS") sql = table.insert({"ADDRESS_NO":None, "USER_NO":self.accessInfo["USER"], "PLATFORM_NO":platformNo, "PUBLIC_IP":publicIp, "COMMENT":None, "INSTANCE_NO":None, "INSTANCE_ID":None}) self.conn.execute(sql) newAddress = self.conn.selectOne(table.select(table.c.PUBLIC_IP==publicIp)) self.conn.commit() return "RESULT:" + str(newAddress["ADDRESS_NO"]) def releaseAddress(self, addressNo): platformNo = self.client.getPlatformNo() tablePLAWS = self.conn.getTable("PLATFORM_AWS") awsPlatform = self.conn.selectOne(tablePLAWS.select(tablePLAWS.c.PLATFORM_NO==platformNo)) table = self.conn.getTable("AWS_ADDRESS") address = self.conn.selectOne(table.select(table.c.ADDRESS_NO==addressNo)) if not address: return ipaddress = address["PUBLIC_IP"] instanceId = address["INSTANCE_ID"] instanceNo = address["INSTANCE_NO"] if awsPlatform["VPC"] == 1: #アドレス情報取得 address = self.client.describeAddress(ipaddress) #VPC用のElasticIP解放処理呼び出し self.client.releaseVpcAddress(ipaddress, address.allocationId) else: #ElasticIP解放処理呼び出し self.client.releaseAddress(ipaddress) #イベントログ self.conn.debug(None, None, None, None, None, "AwsElasticIpRelease", ["EC2", ipaddress]) #DBから削除 table.delete(table.c.ADDRESS_NO==addressNo).execute() self.conn.commit() return "RESULT:TRUE" def describeSnapshot(self, snapshotId): snapshots = self.othercontroller.describeSnapshot(snapshotId) rtString = '' for snapshot in snapshots: if rtString != '': rtString = rtString + "##" #とりあえず全部 rtString = rtString + snapshot.snapshotId + '#' \ + snapshot.volumeId + '#' \ + snapshot.status + '#' \ + snapshot.startTime + '#' \ + snapshot.progress + '#' \ + snapshot.ownerId + '#' \ + snapshot.volumeSize + '#' \ + snapshot.description + '#' \ + snapshot.tagSet self.conn.commit() return "RESULT:" + rtString def createSnapshot(self, volumeNo): self.othercontroller.createSnapshot(volumeNo) self.conn.commit() return "RESULT:TRUE" def deleteSnapshot(self, snapshotNo): self.othercontroller.deleteSnapshot(snapshotNo) self.conn.commit() return "RESULT:TRUE" def getPasswordData(self, instanceNo): passwordData = self.othercontroller.getPasswordData(instanceNo) self.conn.commit() return "RESULT:" + passwordData def describeKeyPairs(self): keypairs = self.client.describeKeyPairs() rtString = '' for keypair in keypairs: if rtString != '': rtString = rtString + "##" #とりあえず必要な情報のみ返します rtString = rtString + keypair.keyName self.conn.commit() return "RESULT:" + rtString def createKeyPair(self, keyName): self.client.createKeyPair(keyName) self.conn.commit() return "RESULT:TRUE" def deleteKeyPair(self, keyName): self.client.deleteKeyPair(keyName) self.conn.commit() return "RESULT:TRUE" def importKeyPair(self, keyName, publicKeyMaterial): keyPair = self.client.importKeyPair(keyName, publicKeyMaterial) keyFingerprint = keyPair.keyFingerprint self.conn.commit() return "RESULT:" + keyFingerprint def describeSecurityGroups(self, vpcid = None): groups = self.client.describeSecurityGroups() rtString = '' for group in groups: #VPCIDが一致する物以外は除外 if vpcid is not None: if vpcid != group.vpcId: continue #VPCID未入力時はVPCIDが設定されていない物のみ使用 else: if group.vpcId is not None: continue if rtString != '': rtString = rtString + "##" #とりあえず必要な情報のみ返します rtString = rtString + group.groupName self.conn.commit() return "RESULT:" + rtString def describeAvailabilityZones(self): zones = self.client.describeAvailabilityZones() #available rtString = '' for zone in zones: #有効な物のみ利用する if zone.zone_state != "available": continue if rtString != '': rtString = rtString + "##" #とりあえず必要な情報のみ返します IDに相当するパラメータが無い為NONEを入れておく rtString = rtString + zone.name + "#NONE" self.conn.commit() #出力として返す return "RESULT:" + rtString def describeSubnets(self, vpcid = None): subnets = self.client.describeSubnets() rtString = '' for subnet in subnets: if vpcid is not None: if vpcid != subnet.vpcId: continue if rtString != '': rtString = rtString + "##" #とりあえず必要な情報のみ返します rtString = rtString + subnet.subnetId + '#' + subnet.availabilityZone+ '#' + subnet.cidrBlock self.conn.commit() return "RESULT:" + rtString
class ec2VolumController(object): logger = IaasLogger() client = None conn = None platforminfo = None def __init__(self, platforminfo, ec2iaasclient, conn): self.client = ec2iaasclient self.conn = conn self.platforminfo = platforminfo def startVolumes(self, instanceNo): # ボリューム情報の取得 table = self.conn.getTable("AWS_VOLUME") volumes = self.conn.select( table.select(table.c.INSTANCE_NO == instanceNo)) for volume in volumes: self.startVolume(instanceNo, volume["VOLUME_NO"]) def startVolume(self, instanceNo, volumeNo): table = self.conn.getTable("AWS_VOLUME") volume = self.conn.selectOne( table.select(table.c.VOLUME_NO == volumeNo)) # インスタンスIDがある場合はスキップ if (isNotEmpty(volume["INSTANCE_ID"])): return if (isEmpty(volume["VOLUME_ID"])): # ボリュームIDがない場合は新規作成 self.createVolume(instanceNo, volumeNo) # ボリュームの作成待ち self.waitCreateVolume(instanceNo, volumeNo) # ボリュームにタグを付ける self.createTag(volumeNo) # ボリュームのアタッチ self.attachVolume(instanceNo, volumeNo) # ボリュームのアタッチ待ち self.waitAttachVolume(instanceNo, volumeNo) def stopVolumes(self, instanceNo): # ボリューム情報の取得 awsVolumes = self.getAwsVolumes(instanceNo) for volume in awsVolumes: self.stopVolume(instanceNo, volume["VOLUME_NO"]) def stopVolume(self, instanceNo, volumeNo): table = self.conn.getTable("AWS_VOLUME") awsVolume = self.conn.selectOne( table.select(table.c.VOLUME_NO == volumeNo)) # ボリュームIDがない場合はスキップ if (isEmpty(awsVolume["VOLUME_ID"])): return # インスタンスIDがない場合はスキップ if (isEmpty(awsVolume["INSTANCE_ID"])): return try: # ボリュームのデタッチ self.detachVolume(instanceNo, volumeNo) # ボリュームのデタッチ待ち self.waitDetachVolume(instanceNo, volumeNo) except Exception, e: self.logger.error(traceback.format_exc()) # 情報が不整合(インスタンス異常終了時など)の場合、警告ログと後始末のみ行う self.logger.warn(e.massage) table = self.conn.getTable("AWS_VOLUME") updateDict = self.conn.selectOne( table.select(table.c.VOLUME_NO == volumeNo)) updateDict["STATUS"] = "error" updateDict["INSTANCE_ID"] = None sql = table.update(table.c.VOLUME_NO == updateDict["VOLUME_NO"], values=updateDict) self.conn.execute(sql)
class OpenStackIaasClient: logger = IaasLogger() platformNo = None username = None tenant = None tenant_id = None auth_url = None nova = None timeout = False TIMEOUT = 600 def __init__(self, platforminfo, username, password): self.username = username self.platformNo = platforminfo["platformNo"] openstackInfo = getOpenStackInfo(self.platformNo) self.tenant = openstackInfo['TENANT_NM'] self.tenant_id = openstackInfo['TENANT_ID'] self.auth_url = openstackInfo['URL'] self.logger.debug('username=%s' % (self.username)) self.logger.debug('password=%s' % (password)) self.logger.debug('tenant=%s' % (self.tenant)) self.logger.debug('auth_url=%s' % (self.auth_url)) self.logger.debug('tenant_id=%s' % (self.tenant_id)) # NOVAマネージャ作成 self.nova = nclient(self.username, password, self.tenant, self.auth_url, tenant_id=self.tenant_id) # CINDERマネージャ作成 self.cinder = cclient(self.username, password, self.tenant, self.auth_url, tenant_id=self.tenant_id) signal.signal(signal.SIGALRM, self._taskTimeout) def _taskTimeout(self, signum, frame): self.timeout = True return def _setTimeout(self, TIMEOUT): self.timeout = False signal.alarm(TIMEOUT) def _resetTimeout(self): self.timeout = False def _isTimeout(self): return self.timeout def _findServerById(self, instanceId): try: instanceObj = self.nova.servers.get(instanceId) except: self.logger.error(traceback.format_exc()) raise else: return instanceObj def _getVirtualMachine(self, instanceId): try: instanceObj = self._findServerById(instanceId) except: self.logger.error(traceback.format_exc()) raise else: return instanceObj def _waitServerStatus(self, serverId, waitStatus, timeout=TIMEOUT): SLEEP = 10 self._setTimeout(timeout) while True: time.sleep(SLEEP) instanceObj = self._getVirtualMachine(serverId) status = instanceObj.status self.logger.debug(' Status: %s' % (status)) if status == waitStatus: return instanceObj elif status == 'ERROR': return instanceObj if self._isTimeout() is True: self._resetTimeout() return instanceObj def _findFlavorById(self, flavorId): try: flavorList = self.nova.flavors.list() except: self.logger.error(traceback.format_exc()) for flavorObject in flavorList: fId = flavorObject.id if fId == flavorId: flavorName = flavorObject.name self.logger.debug(' Flavor Name: %s' % (flavorName)) return flavorObject else: return None def _findFlavorByName(self, flavorName): try: flavorList = self.nova.flavors.list() except: self.logger.error(traceback.format_exc()) for flavorObject in flavorList: fNm = flavorObject.name if fNm == flavorName: flavorId = flavorObject.id self.logger.debug(' Flavor Name: %s' % (flavorName)) return flavorObject else: return None def _findImageById(self, imageId): try: imageList = self.nova.images.list() except: self.logger.error(traceback.format_exc()) for imageObject in imageList: iId = imageObject.id if iId == imageId: imageName = imageObject.name self.logger.debug(' Image Name: %s' % (imageName)) return imageObject else: return None def getVirtualMachineStatus(self, instanceId): try: instanceObj = self._getVirtualMachine(instanceId) except: # NotFound or any other exception self.logger.error(traceback.format_exc()) raise status = instanceObj.status self.logger.debug(' Instance Status: %s' % (status)) return status def deleteVirtualMachine(self, serverId): instanceObj = self._findServerById(serverId) # VM削除 try: novaResponse = self.nova.servers.delete(instanceObj) except: self.logger.error(traceback.format_exc()) raise return None def stopVirtualMachine(self, serverId): instanceObj = self._findServerById(serverId) # VM停止 try: novaResponse = self.nova.servers.stop(instanceObj) except: # BadRequest: Instance xxx in vm_state stopped. Cannot stop while the instance is in this state. # (HTTP 400) (Request-ID: xxx) self.logger.error(traceback.format_exc()) raise # 停止完了まで待つ instanceObj = self._waitServerStatus(serverId, 'SHUTOFF') status = instanceObj.status if status != 'SHUTOFF' and status != 'ERROR': # タイムアウト self.logger.error('The operation timed out.') # 呼び出し側で例外を補足して、異なる例外を送出しているため、下記例外は失われる。 raise IaasException("EPROCESS-001011") return instanceObj def startVirtualMachine(self, serverId): instanceObj = self._findServerById(serverId) # VM起動 try: novaResponse = self.nova.servers.start(instanceObj) except: self.logger.error(traceback.format_exc()) raise # 起動完了まで待つ instanceObj = self._waitServerStatus(serverId, 'ACTIVE') status = instanceObj.status if status != 'ACTIVE' and status != 'ERROR': # タイムアウト self.logger.error('The operation timed out.') # 呼び出し側で例外を補足して、異なる例外を送出しているため、下記例外は失われる。 raise IaasException("EPROCESS-001011") return instanceObj def createVirtualMachine(self, serverName, flavorNm, imageId, availabilityZoneId, networkId, userData, securityGroupId, keyName): # フレーバーIDからフレーバーオブジェクトへの変換 flavorObject = self._findFlavorByName(flavorNm) if flavorObject is None: self.logger.error(' Flavor Not Found: %s' % (flavorId)) raise IaasException("EPROCESS-001001") # イメージIDからイメージオブジェクトへの変換 imageObject = self._findImageById(imageId) if imageObject is None: self.logger.error(' Image Not Found: %s' % (imageId)) raise IaasException("EPROCESS-001001") # NICリストの作成 nics = [{"net-id": networkId, "v4-fixed-ip": "", "port-id": ""}] # セキュリティグループリストの作成 securityGroupList = [securityGroupId] # VM作成 try: novaResponse = self.nova.servers.create( serverName, flavor=flavorObject, image=imageObject, availability_zone=availabilityZoneId, nics=nics, userdata=userData, security_groups=securityGroupList, key_name=keyName) except: self.logger.error(traceback.format_exc()) raise # 作成完了まで待つ serverId = novaResponse.id instanceObj = self._waitServerStatus(serverId, 'ACTIVE') status = instanceObj.status if status != 'ACTIVE' and status != 'ERROR': # タイムアウト self.logger.error('The operation timed out.') # 呼び出し側で例外を補足して、異なる例外を送出しているため、下記例外は失われる。 raise IaasException("EPROCESS-001011") return instanceObj def createVolume(self, name, availabilityZone, size=None, snapshotId=None): #volume = self.nova.volumes.create(size=1, display_name='test02') volume = self.cinder.volumes.create(size=size, display_name=name) return volume def attachVolume(self, volumeId, instanceId, device): #self.cinder.volumes.attach(volumeId, instanceId, device) self.nova.volumes.create_server_volume(instanceId, volumeId, device) def detachVolume(self, instanceId, volumeId): #self.cinder.volumes.detach(volumeId) self.nova.volumes.delete_server_volume(instanceId, volumeId) def deleteVolume(self, volumeId): self.cinder.volumes.delete(volumeId) def describeVolume(self, volumeId): volume = self.cinder.volumes.get(volumeId) return volume def describeSecurityGroups(self, vpcid=None): secgroups = self.nova.security_groups.list() return secgroups def describeAvailabilityZones(self): zones = self.nova.availability_zones.list(detailed=False) return zones def describeNetworks(self): networks = self.nova.networks.list() return networks def describeFlavors(self): flavorList = self.nova.flavors.list() return flavorList def describeKeyPairs(self): keypairList = self.nova.keypairs.list() return keypairList def createKeyPair(self, keyName, publicKeyMaterial): self.nova.keypairs.create(name=keyName, public_key=publicKeyMaterial) return
class EC2IaasClient(EC2IaasNodeDriver): logger = IaasLogger() platformNo = None debugout = True username = None def __init__(self, platforminfo, username, key, secret=None): self.platformNo = platforminfo["platformNo"] self.username = username useProxy = platforminfo["proxy"] #プロキシ利用 if useProxy == 1: useProxy = True else: useProxy = False #リュージョン取得 awsInfo = getAwsInfo(self.platformNo) region = awsInfo["region"] super(EC2IaasClient, self).__init__(region=region, key=key, secret=secret, useProxy=useProxy) ############################################################ # # 基礎データ # ############################################################ def getPlatformNo(self): return self.platformNo def setPlatformNo(self, platformNo): self.platformNo = platformNo def getUsername(self): return self.username ############################################################ # # 参照系 describe # ############################################################ def describeImages(self, location=None): return super(EC2IaasClient, self).list_images(location) def describeImage(self, imageId): params = {'Action': 'DescribeImages', 'ImageId.0': imageId} #ここで利用する_to_imagesは拡張版です images = self._to_images( self.connection.request(self.path, params=params).object) if not images or len(images) == 0: #インスタンスが存在しない場合 return None return images[0] #list_nodesとして提供されているが、機能としてはインスタンス指定を利用がいいか? def describeInstances(self, instanceid=None): params = {'Action': 'DescribeInstances'} #任意パラメータ if instanceid != None: params.update({'InstanceId.0': instanceid}) elem = self.connection.request(self.path, params=params).object nodes = [] for rs in findall(element=elem, xpath='reservationSet/item', namespace=NAMESPACE): groups = [] for g in findall( element=rs, xpath= 'instancesSet/item/networkInterfaceSet/item/groupSet/item', namespace=NAMESPACE): groups.append( findattr(element=g, xpath='groupId', namespace=NAMESPACE)) nodes += self._to_nodes(rs, 'instancesSet/item', groups) nodes_elastic_ips_mappings = self.ex_describe_addresses(nodes) for node in nodes: node.public_ip.extend(nodes_elastic_ips_mappings[node.id]) return nodes #list_nodesとして提供されているものをそのまま使って必要な物だけ def describeInstance(self, instanceid): nodes = self.describeInstances(instanceid) if not nodes or len(nodes) == 0: #インスタンスが存在しない場合 raise IaasException("EPROCESS-000101", [ instanceid, ]) if len(nodes) > 1: #インスタンスを複数参照できた場合 raise IaasException("EPROCESS-000102", [ instanceid, ]) return nodes[0] #LibCloudで提供されていない為独自実装 def describeVolume(self, volumeId): volumes = self.describeVolumes(volumeId) if not volumes or len(volumes) == 0: #インスタンスが存在しない場合 raise IaasException("EPROCESS-000110", [ volumeId, ]) if len(volumes) > 1: #インスタンスを複数参照できた場合 raise IaasException("EPROCESS-000111", [ volumeId, ]) return volumes[0] #LibCloudで提供されていない為独自実装 def describeVolumes(self, volumeId=None): params = {'Action': 'DescribeVolumes'} #任意パラメータ if volumeId != None: params.update({'VolumeId.0': volumeId}) elem = self.connection.request(self.path, params=params).object volumes = [] for rs in findall(element=elem, xpath='volumeSet/item', namespace=NAMESPACE): volumes.append(self._to_volumes(rs)) return volumes def describeAddress(self, publicIp): address = self.describeAddresses(publicIp) if not address or len(address) == 0: #アドレスが存在しない場合 raise IaasException("EPROCESS-000117", [ publicIp, ]) if len(address) > 1: #アドレスを複数参照できた場合 raise IaasException("EPROCESS-000118", [ publicIp, ]) return address[0] def describeVpcAddress(self, publicIp=None): params = {'Action': 'DescribeAddresses'} #任意パラメータ if publicIp != None: params.update({'PublicIp.0': publicIp}) elem = self.connection.request(self.path, params=params).object address = [] for rs in findall(element=elem, xpath='addressesSet/item', namespace=NAMESPACE): address.append(self._to_vpcaddress(rs)) if not address or len(address) == 0: #アドレスが存在しない場合 raise IaasException("EPROCESS-000117", [ publicIp, ]) if len(address) > 1: #アドレスを複数参照できた場合 raise IaasException("EPROCESS-000118", [ publicIp, ]) return address[0] #LibCloudで提供されているDescribeAddressesラップ関数は利用形態がマッチしないので独自実装とする #本来はpublicIpを省略する事も可能だが用途的に固定する def describeAddresses(self, publicIp=None): params = {'Action': 'DescribeAddresses'} #任意パラメータ if publicIp != None: params.update({'PublicIp.0': publicIp}) elem = self.connection.request(self.path, params=params).object address = [] for rs in findall(element=elem, xpath='addressesSet/item', namespace=NAMESPACE): address.append(self._to_address(rs)) return address #LibCloudで提供されているdescribeKeyPairsラップ関数はNameの入力が必須である為用途が異なる為、独自実装 def describeKeyPairs(self): params = {'Action': 'DescribeKeyPairs'} elem = self.connection.request(self.path, params=params).object keypairs = [] for rs in findall(element=elem, xpath='keySet/item', namespace=NAMESPACE): keypairs.append(self._to_keypair(rs)) return keypairs #LibCloudで提供されていない為独自実装 def describeSecurityGroups(self, groupName=None, vpcId=None): #GroupName, GroupId, Filter(name/Value)で絞る事ができるがPCCでは利用しないデフォルト検索を提供する params = {'Action': 'DescribeSecurityGroups'} #任意パラメータ if groupName != None: params.update({'Filter.0.Name': 'group-name'}) params.update({'Filter.0.Value.0': groupName}) if vpcId != None: params.update({'Filter.1.Name': 'vpc-id'}) params.update({'Filter.1.Value.0': vpcId}) elem = self.connection.request(self.path, params=params).object securityGroups = [] for rs in findall(element=elem, xpath='securityGroupInfo/item', namespace=NAMESPACE): securityGroups.append(self._to_securityGroup(rs)) return securityGroups #ex_list_availability_zonesとして提供されているものをラップ def describeAvailabilityZones(self, only_available=True): return super(EC2IaasClient, self).ex_list_availability_zones(only_available) #LibCloudで提供されていない為独自実装 def describeSnapshot(self, snapshotId): snapshots = self.describeSnapshots(snapshotId) if not snapshots or len(snapshots) == 0: #アドレスが存在しない場合 raise IaasException("EPROCESS-000122", [ snapshotId, ]) if len(snapshots) > 1: #アドレスを複数参照できた場合 raise IaasException("EPROCESS-000123", [ snapshotId, ]) return snapshots[0] #LibCloudで提供されていない為独自実装 def describeSnapshots(self, snapshotId=None): #Owner, RestorableBy, Filter(name/Value)で絞る事ができるが制限する params = {'Action': 'DescribeSnapshots'} #任意パラメータ if snapshotId != None: params.update({'SnapshotId': snapshotId}) elem = self.connection.request(self.path, params=params).object snapshots = [] for rs in findall(element=elem, xpath='snapshotSet/item', namespace=NAMESPACE): snapshots.append(self._to_snapshot(rs)) return snapshots def describeRegions(self, regionName=None): params = {'Action': 'DescribeRegions'} #任意パラメータ if regionName != None: params.update({'RegionName': regionName}) elem = self.connection.request(self.path, params=params).object regionInfos = [] for rs in findall(element=elem, xpath='regionInfo/item', namespace=NAMESPACE): regionInfos.append(self._to_regionInfo(rs)) return regionInfos def describeVpcs(self, vpcId=None): params = {'Action': 'DescribeVpcs'} #任意パラメータ if vpcId != None: params.update({'VpcId': vpcId}) elem = self.connection.request(self.path, params=params).object vpcInfos = [] for rs in findall(element=elem, xpath='vpcSet/item', namespace=NAMESPACE): vpcInfos.append(self._to_vpcInfo(rs)) return vpcInfos def describeSubnets(self, subnetId=None): params = {'Action': 'DescribeSubnets'} #任意パラメータ if subnetId != None: params.update({'SubnetId': subnetId}) elem = self.connection.request(self.path, params=params).object subnetInfos = [] for rs in findall(element=elem, xpath='subnetSet/item', namespace=NAMESPACE): subnetInfos.append(self._to_subnetInfo(rs)) return subnetInfos def describeTags(self, instanceId=None): params = {'Action': 'DescribeTags'} #任意パラメータ if instanceId != None: params.update({'Filter.0.Name': 'resource-id'}) params.update({'Filter.0.Value.0': instanceId}) elem = self.connection.request(self.path, params=params).object tagSets = [] for rs in findall(element=elem, xpath='tagSet/item', namespace=NAMESPACE): tagSets.append(self._to_tagSet(rs)) return tagSets ############################################################ # # Instance 系 # ############################################################ def runInstances(self, groupmap, **kwargs): params = { 'Action': 'RunInstances', 'ImageId': kwargs.get('imageId'), 'InstanceType': kwargs.get('instanceType'), 'MinCount': kwargs.get('ex_mincount', '1'), 'MaxCount': kwargs.get('ex_maxcount', '1'), } isGroupID = False isPrivateIp = False if 'subnetId' in kwargs and kwargs['subnetId'] is not None: params['SubnetId'] = kwargs['subnetId'] #サブネットありの場合はセキュリティグループはIDを使う isGroupID = True isPrivateIp = True if 'securityGroup' in kwargs: if kwargs['securityGroup'] is not None: securityGroups = kwargs['securityGroup'] for sig in range(len(securityGroups)): if isGroupID: params['SecurityGroupId.%d' % (sig + 1, )] = groupmap[securityGroups[sig]] else: params['SecurityGroup.%d' % (sig + 1, )] = securityGroups[sig] if 'blockDeviceMapping' in kwargs: if kwargs['blockDeviceMapping'] is not None: if not isinstance(kwargs['blockDeviceMapping'], list): kwargs['blockDeviceMapping'] = [ kwargs['blockDeviceMapping'] ] for sig, blockDevice in enumerate( kwargs['blockDeviceMapping']): params['BlockDeviceMapping.%d.DeviceName' % (sig + 1, )] = blockDevice["DeviceName"] params['BlockDeviceMapping.%d.VirtualName' % (sig + 1, )] = blockDevice["VirtualName"] if 'location' in kwargs: availability_zone = kwargs['location'] if availability_zone: #if availability_zone != self.region_name: # raise IaasException('Invalid availability zone: %s' % availability_zone) params['Placement.AvailabilityZone'] = availability_zone if 'kernelId' in kwargs and kwargs[ 'kernelId'] is not None and '' != kwargs['kernelId']: params['KernelId'] = kwargs['kernelId'] if 'ramdiskId' in kwargs and kwargs[ 'ramdiskId'] is not None and '' != kwargs['ramdiskId']: params['RamdiskId'] = kwargs['ramdiskId'] if 'keyName' in kwargs and kwargs[ 'keyName'] is not None and '' != kwargs['keyName']: params['KeyName'] = kwargs['keyName'] if isPrivateIp and 'privateIpAddress' in kwargs and kwargs[ 'privateIpAddress'] is not None and '' != kwargs[ 'privateIpAddress']: params['PrivateIpAddress'] = kwargs['privateIpAddress'] if 'userData' in kwargs and kwargs['userData'] is not None: params['UserData'] = base64.b64encode(kwargs['userData']) if 'ex_clienttoken' in kwargs and kwargs['ex_clienttoken'] is not None: params['ClientToken'] = kwargs['ex_clienttoken'] instance = None try: self.logger.info(params) object = self.connection.request(self.path, params=params).object nodes = self._to_nodes(object, 'instancesSet/item') instance = nodes[0] except Exception: self.logger.error(traceback.format_exc()) #インスタンスが存在しない場合 raise IaasException("EPROCESS-000105", []) #実行ログ self.logger.info(None, "IPROCESS-100115", [instance.id]) return instance #LibCloudで提供されていない為独自実装 def startInstance(self, instanceid): params = {'Action': 'StartInstances', 'InstanceId.0': instanceid} try: elem = self.connection.request(self.path, params=params).object previousStates = [] for rs in findall(element=elem, xpath='instancesSet/item', namespace=NAMESPACE): code = findtext(element=rs, xpath='previousState/code', namespace=NAMESPACE) name = findtext(element=rs, xpath='previousState/name', namespace=NAMESPACE) previousStates.append({"code": code, "name": name}) if len(previousStates) > 1: raise IaasException("EPROCESS-000127", [ instanceid, ]) #実行ログ self.logger.info(None, "IPROCESS-100111", [ instanceid, ]) return previousStates[0] except Exception: # インスタンス起動失敗時 raise IaasException("EPROCESS-000125", [ instanceid, ]) return None #LibCloudで提供されていない為独自実装 def stopInstance(self, instanceid): params = {'Action': 'StopInstances', 'InstanceId.0': instanceid} try: elem = self.connection.request(self.path, params=params).object previousStates = [] for rs in findall(element=elem, xpath='instancesSet/item', namespace=NAMESPACE): code = findtext(element=rs, xpath='previousState/code', namespace=NAMESPACE) name = findtext(element=rs, xpath='previousState/name', namespace=NAMESPACE) previousStates.append({"code": code, "name": name}) if len(previousStates) > 1: raise IaasException("EPROCESS-000130", [ instanceid, ]) #実行ログ self.logger.info(None, "IPROCESS-100113", [ instanceid, ]) return previousStates[0] except Exception: # インスタンス停止失敗時 raise IaasException("EPROCESS-000128", [ instanceid, ]) return None #本来destroy_nodeはnode自体を受け取るがこの関数はIDを受ける形とした def terminateInstance(self, instanceid): params = {'Action': 'TerminateInstances', 'InstanceId': instanceid} try: elem = self.connection.request(self.path, params=params).object previousStates = [] for rs in findall(element=elem, xpath='instancesSet/item', namespace=NAMESPACE): code = findtext(element=rs, xpath='previousState/code', namespace=NAMESPACE) name = findtext(element=rs, xpath='previousState/name', namespace=NAMESPACE) previousStates.append({"code": code, "name": name}) if len(previousStates) > 1: #複数のインスタンスが削除された場合 raise IaasException("EPROCESS-000108", [ instanceid, ]) #実行ログ self.logger.info(None, "IPROCESS-100117", [ instanceid, ]) return previousStates[0] except Exception: # インスタンス削除失敗時 raise IaasException("EPROCESS-000107", [ instanceid, ]) return None def modifyInstanceAttribute(self, instanceid, **kwargs): params = { 'Action': 'ModifyInstanceAttribute', 'InstanceId': instanceid } #現状はインスタンスタイプのみ変更に対応する if 'InstanceType' in kwargs and kwargs[ 'InstanceType'] is not None and '' != kwargs['InstanceType']: params['InstanceType.Value'] = kwargs['InstanceType'] elif 'GroupId' in kwargs and kwargs[ 'GroupId'] is not None and '' != kwargs['GroupId']: params['GroupId'] = kwargs['GroupId'] try: self.connection.request(self.path, params=params).object except Exception: # インスタンス変更失敗時 raise IaasException("EPROCESS-000107", [ instanceid, ]) return None ############################################################ # # Volume 系 # ############################################################ #LibCloudで提供されていない為独自実装 def createVolume(self, availabilityZone, size=None, snapshotId=None): params = { 'Action': 'CreateVolume', 'AvailabilityZone': availabilityZone } #任意 if size != None: params.update({'Size': str(size)}) if snapshotId != None: params.update({'SnapshotId': snapshotId}) elem = self.connection.request(self.path, params=params).object voluem = self._to_volume(elem) #実行ログ self.logger.info(None, "IPROCESS-100121", [ voluem.volumeId, ]) return voluem #LibCloudで提供されていない為独自実装 def attachVolume(self, volumeId, instanceId, device): params = { 'Action': 'AttachVolume', 'VolumeId': volumeId, 'InstanceId': instanceId, 'Device': device } elem = self.connection.request(self.path, params=params).object #実行ログ self.logger.info(None, "IPROCESS-100123", [volumeId, instanceId]) return self._to_attachmentSet(elem) #LibCloudで提供されていない為独自実装 def detachVolume(self, volumeId, instanceId=None, device=None): params = {'Action': 'DetachVolume', 'VolumeId': volumeId} #任意パラメータ if instanceId != None: params.update({'InstanceId': instanceId}) if device != None: params.update({'Device': device}) elem = self.connection.request(self.path, params=params).object #実行ログ self.logger.info(None, "IPROCESS-100125", [volumeId, instanceId]) #deleteOnTerminationが戻りのエレメントに無いのでそのまま動くか不明 return self._to_attachmentSet(elem) #LibCloudで提供されていない為独自実装 def deleteVolume(self, volumeId): params = {'Action': 'DeleteVolume', 'VolumeId': volumeId} self.connection.request(self.path, params=params).object #実行ログ self.logger.info(None, "IPROCESS-100127", [ volumeId, ]) ############################################################ # # Address 系 # ############################################################ #LibCloudで提供されていない為独自実装 #Domainを指定することも可能だが無視する def allocateAddress(self): params = {'Action': 'AllocateAddress'} elem = self.connection.request(self.path, params=params).object publicIp = findattr(element=elem, xpath="publicIp", namespace=NAMESPACE) # ログ出力 self.logger.info(None, "IPROCESS-100133", [ publicIp, ]) return publicIp #LibCloudで提供されていない為独自実装 def allocateVpcAddress(self): params = {'Action': 'AllocateAddress', 'Domain': 'vpc'} elem = self.connection.request(self.path, params=params).object publicIp = findattr(element=elem, xpath="publicIp", namespace=NAMESPACE) # ログ出力 self.logger.info(None, "IPROCESS-100133", [ publicIp, ]) return publicIp #LibCloudで提供されていない為独自実装 def associateAddress(self, publicIp, instanceId): params = { 'Action': 'AssociateAddress', 'PublicIp': publicIp, 'InstanceId': instanceId } self.connection.request(self.path, params=params).object # ログ出力 self.logger.info(None, "IPROCESS-100131", [ publicIp, instanceId, ]) #LibCloudで提供されていない為独自実装 def associateVpcAddress(self, publicIp, instanceId, allocationId): params = { 'Action': 'AssociateAddress', 'InstanceId': instanceId, 'AllocationId': allocationId } self.connection.request(self.path, params=params).object # ログ出力 self.logger.info(None, "IPROCESS-100131", [ publicIp, instanceId, allocationId, ]) #LibCloudで提供されていない為独自実装 def disassociateAddress(self, publicIp, instanceId): params = {'Action': 'DisassociateAddress', 'PublicIp': publicIp} self.connection.request(self.path, params=params).object # ログ出力 self.logger.info(None, "IPROCESS-100132", [ publicIp, instanceId, ]) #LibCloudで提供されていない為独自実装 def disassociateVpcAddress(self, publicIp, instanceId, associationId): params = { 'Action': 'DisassociateAddress', 'AssociationId': associationId } self.connection.request(self.path, params=params).object # ログ出力 self.logger.info(None, "IPROCESS-100132", [ publicIp, instanceId, associationId, ]) #LibCloudで提供されていない為独自実装 def releaseAddress(self, publicIp): params = {'Action': 'ReleaseAddress', 'PublicIp': publicIp} self.connection.request(self.path, params=params).object # ログ出力 self.logger.info(None, "IPROCESS-100134", [ publicIp, ]) #LibCloudで提供されていない為独自実装 def releaseVpcAddress(self, publicIp, allocationId): params = {'Action': 'ReleaseAddress', 'AllocationId': allocationId} self.connection.request(self.path, params=params).object # ログ出力 self.logger.info(None, "IPROCESS-100134", [ publicIp, allocationId, ]) ############################################################ # # KeyPair 系 # ############################################################ #LibCloudで提供されてるex_create_keypairはKeyNameを戻り値に含まない為、独自実装 def createKeyPair(self, keyName): params = {'Action': 'CreateKeyPair', 'KeyName': keyName} elem = self.connection.request(self.path, params=params).object keypair = self._to_keypair(elem) keypair.setKeyMaterial( findattr(element=elem, xpath="keyMaterial", namespace=NAMESPACE)) #LibCloudで提供されていない為独自実装 def deleteKeyPair(self, keyName): params = {'Action': 'DeleteKeyPair', 'KeyName': keyName} self.connection.request(self.path, params=params).object #戻り値なし #LibCloudで提供されてるex_import_keypairはファイルベースの為、独自実装 def importKeyPair(self, keyName, publicKeyMaterial): publicKeyMaterial = base64.b64encode(publicKeyMaterial) params = { 'Action': 'ImportKeyPair', 'KeyName': keyName, 'PublicKeyMaterial': publicKeyMaterial } elem = self.connection.request(self.path, params=params).object return self._to_keypair(elem) ############################################################ # # Snapshot 系 # ############################################################ def createSnapshot(self, volumeId, description=None): #Owner, RestorableBy, Filter(name/Value)で絞る事ができるが制限する params = {'Action': 'CreateSnapshot', 'VolumeId': volumeId} #任意パラメータ if description != None: params.update({'Description': description}) elem = self.connection.request(self.path, params=params).object snapshot = self._to_snapshot(elem) # ログ出力 self.logger.info(None, "IPROCESS-100151", [snapshot.snapshotId, volumeId]) return snapshot def deleteSnapshot(self, snapshotId): params = {'Action': 'DeleteSnapshot', 'SnapshotId': snapshotId} self.connection.request(self.path, params=params).object # ログ出力 self.logger.info(None, "IPROCESS-100153", [snapshotId]) ############################################################ # # Tags 系 # ############################################################ def createTags(self, resourceId, tagSets): if not tagSets: return params = {'Action': 'CreateTags', 'ResourceId.0': resourceId} i = 0 for tag in tagSets: params['Tag.%d.Key' % i] = tag.key params['Tag.%d.Value' % i] = tag.value i = i + 1 # ログ出力 self.logger.info(None, "IPROCESS-100154", [resourceId, tag.key, tag.value]) self.connection.request(self.path, params=params).object def createTag(self, instanceId, tag): if not tag: return tags = [tag] self.createTags(instanceId, tags) def deleteTags(self, instanceId, tagSets): if not tagSets: return params = {'Action': 'DeleteTags', 'ResourceId.0': instanceId} i = 0 for tag in tagSets: params['Tag.%d.Key' % i] = tag.key params['Tag.%d.Value' % i] = tag.value i = i + 1 self.connection.request(self.path, params=params).object ############################################################ # # その他 # ############################################################ def getPasswordData(self, InstanceId): params = {'Action': 'GetPasswordData', 'InstanceId': InstanceId} elem = self.connection.request(self.path, params=params).object #True Falseを受ける passwdData = findattr(element=elem, xpath="passwordData", namespace=NAMESPACE) if isEmpty(passwdData): # パスワードデータを取得できない場合 raise IaasException("EPROCESS-000133", [ InstanceId, ]) return passwdData '''********************************以下ローカルメソッド****************************************** ''' def build_list_params(self, params, items, label): if isinstance(items, str): items = [items] for i, item in enumerate(items, 1): params[label % i] = item def _to_image(self, element): n = NodeImage(id=findtext(element=element, xpath='imageId', namespace=NAMESPACE), name=findtext(element=element, xpath='imageLocation', namespace=NAMESPACE), driver=self.connection.driver, extra={ 'rootDeviceType': findattr(element=element, xpath="rootDeviceType", namespace=NAMESPACE), 'platform': findattr(element=element, xpath="platform", namespace=NAMESPACE), }) return n def _to_tagSet(self, element): n = TagSet( resourceId=findattr(element=element, xpath="resourceId", namespace=NAMESPACE), resourceType=findattr(element=element, xpath="resourceType", namespace=NAMESPACE), key=findattr(element=element, xpath="key", namespace=NAMESPACE), value=findattr(element=element, xpath="value", namespace=NAMESPACE), ) return n def _to_subnetInfo(self, element): n = SubnetInfo( subnetId=findattr(element=element, xpath="subnetId", namespace=NAMESPACE), state=findattr(element=element, xpath="state", namespace=NAMESPACE), vpcId=findattr(element=element, xpath="vpcId", namespace=NAMESPACE), cidrBlock=findattr(element=element, xpath="cidrBlock", namespace=NAMESPACE), availableIpAddressCount=findattr(element=element, xpath="availableIpAddressCount", namespace=NAMESPACE), availabilityZone=findattr(element=element, xpath="availabilityZone", namespace=NAMESPACE), tagSet=findattr(element=element, xpath="tagSet", namespace=NAMESPACE), ) return n def _to_vpcInfo(self, element): n = VpcInfo( vpcId=findattr(element=element, xpath="vpcId", namespace=NAMESPACE), state=findattr(element=element, xpath="state", namespace=NAMESPACE), cidrBlock=findattr(element=element, xpath="cidrBlock", namespace=NAMESPACE), dhcpOptionsId=findattr(element=element, xpath="dhcpOptionsId", namespace=NAMESPACE), tagSet=findattr(element=element, xpath="tagSet", namespace=NAMESPACE), ) return n def _to_regionInfo(self, element): n = RegionInfo( regionName=findattr(element=element, xpath="regionName", namespace=NAMESPACE), regionEndpoint=findattr(element=element, xpath="regionEndpoint", namespace=NAMESPACE), ) return n def _to_snapshot(self, element): n = SnapshotSet( snapshotId=findattr(element=element, xpath="snapshotId", namespace=NAMESPACE), volumeId=findattr(element=element, xpath="volumeId", namespace=NAMESPACE), status=findattr(element=element, xpath="status", namespace=NAMESPACE), startTime=findattr(element=element, xpath="startTime", namespace=NAMESPACE), progress=findattr(element=element, xpath="progress", namespace=NAMESPACE), ownerId=findattr(element=element, xpath="ownerId", namespace=NAMESPACE), volumeSize=findattr(element=element, xpath="volumeSize", namespace=NAMESPACE), description=findattr(element=element, xpath="description", namespace=NAMESPACE), tagSet=findattr(element=element, xpath="tagSet", namespace=NAMESPACE), ) return n def _to_securityGroup(self, element): ipPermissions = [] for rs in findall(element=element, xpath='ipPermissions/item', namespace=NAMESPACE): ipPermissions.append(self._to_ipPermissions(rs)) n = SecurityGroup( ownerId=findattr(element=element, xpath="ownerId", namespace=NAMESPACE), groupId=findattr(element=element, xpath="groupId", namespace=NAMESPACE), groupName=findattr(element=element, xpath="groupName", namespace=NAMESPACE), groupDescription=findattr(element=element, xpath="groupDescription", namespace=NAMESPACE), vpcId=findattr(element=element, xpath="vpcId", namespace=NAMESPACE), ipPermissions=ipPermissions, ipPermissionsEgress=findattr(element=element, xpath="ipPermissionsEgress", namespace=NAMESPACE), tagSet=findattr(element=element, xpath="tagSet", namespace=NAMESPACE), ) return n def _to_ipPermissions(self, element): ipRanges = [] for rs in findall(element=element, xpath='ipRanges/item', namespace=NAMESPACE): ipRanges.append( findattr(element=rs, xpath="cidrIp", namespace=NAMESPACE)) n = IpPermissions( ipProtocol=findattr(element=element, xpath="ipProtocol", namespace=NAMESPACE), fromPort=findattr(element=element, xpath="fromPort", namespace=NAMESPACE), toPort=findattr(element=element, xpath="toPort", namespace=NAMESPACE), groups=findattr(element=element, xpath="groups", namespace=NAMESPACE), ipRanges=ipRanges, ) return n def _to_volumes(self, element): #ステータスチェック(保留) #try: # state = self.NODE_STATE_MAP[ # findattr(element=element, xpath="instanceState/name", # namespace=NAMESPACE) # ] #except KeyError: # state = NodeState.UNKNOWN tags = dict( (findtext(element=item, xpath='key', namespace=NAMESPACE), findtext(element=item, xpath='value', namespace=NAMESPACE)) for item in findall( element=element, xpath='tagSet/item', namespace=NAMESPACE)) attachment = [] for rs in findall(element=element, xpath='attachmentSet/item', namespace=NAMESPACE): attachmentset = self._to_attachmentSet(rs) attachmentset.setDeleteOnTermination( findattr(element=element, xpath="deleteOnTermination", namespace=NAMESPACE)) attachment.append(attachmentset) v = self._to_volume(element, attachment, tags) return v def _to_volume(self, element, attachmentSet=None, tags=None): v = Volume(volumeId=findattr(element=element, xpath="volumeId", namespace=NAMESPACE), size=findattr(element=element, xpath="size", namespace=NAMESPACE), snapshotId=findattr(element=element, xpath="snapshotId", namespace=NAMESPACE), availabilityZone=findattr(element=element, xpath="availabilityZone", namespace=NAMESPACE), status=findattr(element=element, xpath="status", namespace=NAMESPACE), createTime=findattr(element=element, xpath="createTime", namespace=NAMESPACE), attachmentSet=attachmentSet, tagSet=tags) return v def _to_attachmentSet(self, element): n = AttachmentSet( volumeId=findattr(element=element, xpath="volumeId", namespace=NAMESPACE), instanceId=findattr(element=element, xpath="instanceId", namespace=NAMESPACE), device=findattr(element=element, xpath="device", namespace=NAMESPACE), status=findattr(element=element, xpath="status", namespace=NAMESPACE), attachTime=findattr(element=element, xpath="attachTime", namespace=NAMESPACE), ) return n def _to_address(self, element): n = Address( publicIp=findattr(element=element, xpath="publicIp", namespace=NAMESPACE), domain=findattr(element=element, xpath="domain", namespace=NAMESPACE), instanceId=findattr(element=element, xpath="instanceId", namespace=NAMESPACE), allocationId=findattr(element=element, xpath="allocationId", namespace=NAMESPACE), associationId=findattr(element=element, xpath="associationId", namespace=NAMESPACE), ) return n def _to_keypair(self, element): n = KeyPair( keyName=findattr(element=element, xpath="keyName", namespace=NAMESPACE), keyFingerprint=findattr(element=element, xpath="keyFingerprint", namespace=NAMESPACE), #keyMaterial = findattr(element=element, xpath="keyMaterial", namespace=NAMESPACE), ) return n
class VCloudController(IaasController): logger = IaasLogger() conn = None client = None accessInfo = None instancecontroller = None volumecontroller = None addresscontroller = None loadBalancercontroller = None othercontroller = None def __init__(self, conn, accessInfo, platforminfo): self.conn = conn self.accessInfo = accessInfo self.client = VCloudIaasClient(platforminfo, accessInfo["USER_NAME"], accessInfo["ACCESS_ID"], accessInfo["SECRET_KEY"]) #コントローラ作成 self.othercontroller = VCloudOtherController(platforminfo, self.client, self.conn) self.instancecontroller = VCloudInstanceController(platforminfo, self.client, self.conn) self.volumecontroller = VCloudVolumController(platforminfo, self.client, self.conn) def __del__(self): #保険 self.conn.rollback() #エラー時に残るタスク登録を消す taskTable = self.conn.getTable("VCLOUD_TASK") sql = taskTable.delete().where(taskTable.c.P_ID == os.getpid()) self.conn.execute(sql) self.conn.commit() #セッションクローズ self.conn.close() def doWaitingExecution(self, farm_name): vdc = self.client.getUseVdc() vappname = vdc.name + "-" + farm_name #タスク情報を登録し1度コミット taskTable = self.conn.getTable("VCLOUD_TASK") sql = taskTable.insert({"ADDRESS_NO":None, "P_ID":os.getpid(), "REGIST_TIME":datetime.datetime.today(), "VAPP":vappname}) self.conn.execute(sql) self.conn.commit() #同タイム対策スリープ time.sleep(3) #自分のPIDの順番まで待つ status = "stop" prePid = "0" roopCount = 0 while status != 'go': #登録時間の早いタスクを取得(常に最新のDB状況を参照する) self.conn.remakeSession() task = self.conn.selectOne(taskTable.select() .where(taskTable.c.VAPP == vappname) .order_by(taskTable.c.REGIST_TIME, taskTable.c.P_ID)) self.logger.info(os.getpid()) self.logger.info(task) if os.getpid() == task["P_ID"]: vapp = self.client.describeMyCloud(vdc, farm_name) #VAPPが実行中タスクを持っている場合は待つ if vapp.extra["task"]: roopCount = roopCount +1 time.sleep(10) else: status = 'go' else: #前回PIDが同じ場合ループカウントを増やす if prePid == task["P_ID"]: roopCount = roopCount +1 else: #新しいPIDの場合は0に戻す roopCount = 0 prePid = task["P_ID"] time.sleep(10) #タイムアウト if roopCount > 100: raise IaasException("EPROCESS-000812", [os.getpid(),]) def doWaitingExecutionEnd(self): taskTable = self.conn.getTable("VCLOUD_TASK") sql = taskTable.delete().where(taskTable.c.P_ID == os.getpid()) self.conn.execute(sql) def getVappName(self, farmNo=None, instanceNo=None, vm_name=None): farmNo = farmNo instanceNo = instanceNo vm_name = vm_name if vm_name is not None: #vCloud_INSTANCE 取得 tableVCINS = self.conn.getTable("VCLOUD_INSTANCE") vcInstance = self.conn.selectOne(tableVCINS.select(tableVCINS.c.VM_NAME==vm_name)) instanceNo = vcInstance["INSTANCE_NO"] if instanceNo is not None: #PCC_INSTANCE 取得 tableINS = self.conn.getTable("INSTANCE") pccInstance = self.conn.selectOne(tableINS.select(tableINS.c.INSTANCE_NO==instanceNo)) farmNo = pccInstance["FARM_NO"] if farmNo is not None: #FARM 取得 tableFarm = self.conn.getTable("FARM") farm = self.conn.selectOne(tableFarm.select(tableFarm.c.FARM_NO==farmNo)) return farm["FARM_NAME"] else: return None def synchronizeCloud(self, platformNo): self.othercontroller.synchronizeCloud(platformNo) self.conn.commit() return True def describeNetwork(self): networks = self.client.describeVdcNetwork() rtString = '' for network in networks: if rtString != '': rtString = rtString + "##" name = network.name value = "GATEWAY="+str(network.gateway) value = value + ",NETMASK=" + str(network.netmask) value = value + ",DNS1=" + str(network.dns1) value = value + ",DNS2=" + str(network.dns2) value = value + ",RANGEF=" + str(network.rangeF) value = value + ",RANGET=" + str(network.rangeT) value = value + ",PRIMARY=" + str(network.primary) #とりあえず必要な情報のみ返します rtString = rtString + name + '#' + value self.conn.commit() return "RESULT:" + rtString def createMyCloud(self, platformNo, farmName): self.othercontroller.createMyCloud(platformNo, farmName) self.conn.commit() return True def terminateMyCloud(self, platformNo, farmNo): #VAPPロック self.doWaitingExecution(self.getVappName(farmNo=farmNo)) self.othercontroller.terminateMyCloud(platformNo, farmNo) #VAPPロック解除 self.doWaitingExecutionEnd() self.conn.commit() return True def startInstance(self, instanceNo): #VAPPロック self.doWaitingExecution(self.getVappName(instanceNo=instanceNo)) #仮想マシンを(作成)起動 self.instancecontroller.startInstance(instanceNo) # ボリュームに関する処理 table = self.conn.getTable("VCLOUD_DISK") volumes = self.conn.select(table.select(table.c.INSTANCE_NO==instanceNo)) for disk in volumes: if isNotEmpty(disk["COMPONENT_NO"]): # コンポーネント番号がある場合はスキップ continue if isNotEmpty(disk["DISK_ID"]): # アタッチされている場合はスキップ continue #Volumeスタート self.volumecontroller.startVolume(instanceNo, disk["DISK_NO"]) #VAPPロック解除 self.doWaitingExecutionEnd() self.conn.commit() return True def stopInstance(self, instanceNo): #VAPPロック self.doWaitingExecution(self.getVappName(instanceNo=instanceNo)) #仮想マシンを停止 self.instancecontroller.stopInstance(instanceNo) # ボリュームに関する処理 tableDsk = self.conn.getTable("VCLOUD_DISK") volumes = self.conn.select(tableDsk.select(tableDsk.c.INSTANCE_NO==instanceNo)) for disk in volumes: #アンデタッチの場合抜ける if getTrueFalseProperty("unDetachVolume"): break # filestorage は外さない if isBit(disk["DATA_DISK"]): continue #Volumのストップ self.volumecontroller.stopVolume(instanceNo, disk["DISK_NO"]) #VAPPロック解除 self.doWaitingExecutionEnd() self.conn.commit() return True def terminateInstance(self, vm_name): #vCloud_INSTANCE 取得 tableVCINS = self.conn.getTable("VCLOUD_INSTANCE") vcInstance = self.conn.selectOne(tableVCINS.select(tableVCINS.c.VM_NAME==vm_name)) if vcInstance is None: #1度も起動されて無い場合はそのまま返す return #VAPPロック self.doWaitingExecution(self.getVappName(vm_name=vm_name)) #仮想マシンを削除 self.instancecontroller.terminate(vm_name) #VAPPロック解除 self.doWaitingExecutionEnd() self.conn.commit() return True def startVolume(self, instanceNo, volumeNo): #VAPPロック self.doWaitingExecution(self.getVappName(instanceNo=instanceNo)) self.volumecontroller.startVolume(instanceNo, volumeNo) #VAPPロック解除 self.doWaitingExecutionEnd() self.conn.commit() return True def stopVolume(self, instanceNo, volumeNo): #VAPPロック self.doWaitingExecution(self.getVappName(instanceNo=instanceNo)) self.volumecontroller.stopVolume(instanceNo, volumeNo) #VAPPロック解除 self.doWaitingExecutionEnd() self.conn.commit() return True def deleteVolume(self, disk_no): tableVCDISK = self.conn.getTable("VCLOUD_DISK") vcdisk = self.conn.selectOne(tableVCDISK.select(tableVCDISK.c.DISK_NO==disk_no)) #VCLOUD_INSTANCE 取得 tableVCINS = self.conn.getTable("VCLOUD_INSTANCE") vcInstance = self.conn.selectOne(tableVCINS.select(tableVCINS.c.INSTANCE_NO==vcdisk["INSTANCE_NO"])) #FARM 取得 tableFarm = self.conn.getTable("FARM") farm = self.conn.selectOne(tableFarm.select(tableFarm.c.FARM_NO==vcdisk["FARM_NO"])) #VAPPロック self.doWaitingExecution(farm["FARM_NAME"]) #組織 vdc = self.client.getUseVdc() #マイクラウド vApp = self.client.describeMyCloud(vdc, farm["FARM_NAME"]) #既存VM検索 vm = self.client.describeInstance(vApp, vcInstance["VM_NAME"]) self.client.detachVolume(vm, vcdisk["DISK_ID"]) #VAPPロック解除 self.doWaitingExecutionEnd() self.conn.commit() return True def startLoadBalancer(self, loadBalancerNo): pass def stopLoadBalancer(self, loadBalancerNo): pass def configureLoadBalancer(self, loadBalancerNo): pass #TODO 後々はゾーンを取得するようにしなければいけない def allocateAddress(self, farmNo): pass def releaseAddress(self, addressNo, farmNo): pass def createSnapshot(self, volumeNo): pass def deleteSnapshot(self, snapshotNo): pass def getPasswordData(self, instanceNo): pass def describeKeyPairs(self): pass def createKeyPair(self, keyName): pass def deleteKeyPair(self, keyName): pass def importKeyPair(self, keyName, publicKeyMaterial): pass def describeSecurityGroups(self, vpcid = None): pass def describeAvailabilityZones(self): pass
class CloudStackController(IaasController): logger = IaasLogger() conn = None client = None accessInfo = None instancecontroller = None volumecontroller = None addresscontroller = None loadBalancercontroller = None othercontroller = None def __init__(self, conn, accessInfo, platforminfo): self.conn = conn self.accessInfo = accessInfo self.client = CloudStackIaasClient(platforminfo, accessInfo["USER_NAME"], accessInfo["ACCESS_ID"], accessInfo["SECRET_KEY"]) #コントローラ作成 self.instancecontroller = CloudStackInstanceController(platforminfo, self.client, self.conn) self.volumecontroller = CloudStackVolumController(platforminfo, self.client, self.conn) self.addresscontroller = CloudStackAddressController(platforminfo, self.client, self.conn) self.loadBalancercontroller = CloudStackLoadBalancercontroller(platforminfo, self.client, self.conn) self.othercontroller = CloudStackOtherController(platforminfo, self.client, self.conn) def __del__(self): self.conn.rollback() self.conn.close() def describeDiskOfferings(self): return self.client.describeDiskOfferings() def describePublicIpAddresses(self, id): return self.client.describePublicIpAddresses(id) def describeOnlyInstances(self): return self.client.describeOnlyInstances() def describeServiceOfferings(self): return self.client.describeServiceOfferings() def describeImages(self): return self.client.describeImages() def describeInstances(self): return self.client.describeInstances() def startInstance(self, instanceNo): # インスタンスに関する処理 TODO タイムアウトリトライは未実装 try: self.instancecontroller.startInstance(instanceNo) except Exception, e: self.logger.error(traceback.format_exc()) raise # ボリュームに関する処理 table = self.conn.getTable("CLOUDSTACK_VOLUME") volumes = self.conn.select(table.select(table.c.INSTANCE_NO==instanceNo)) for volume in volumes: if isNotEmpty(volume["COMPONENT_NO"]): # コンポーネント番号がある場合はスキップ continue #Volumeスタート self.volumecontroller.startVolume(instanceNo, volume["VOLUME_NO"]) # アドレスに関する処理 self.addresscontroller.startAddress(instanceNo) self.conn.commit() return True
class ec2InstanceController(object): logger = IaasLogger() ERROR_RETRY_COUNT = 3 client = None conn = None platforminfo = None def __init__(self, platforminfo, ec2iaasclient, conn): self.client = ec2iaasclient self.conn = conn self.platforminfo = platforminfo def startInstance(self, instanceNo): #AWS_INSTANCE 取得 tableAWSINS = self.conn.getTable("AWS_INSTANCE") awsInstance = self.conn.selectOne( tableAWSINS.select(tableAWSINS.c.INSTANCE_NO == instanceNo)) #PCC_INSTANCE 取得 tableINS = self.conn.getTable("INSTANCE") pccInstance = self.conn.selectOne( tableINS.select(tableINS.c.INSTANCE_NO == instanceNo)) #イメージの取得 再考の余地あり image = getImage(pccInstance["IMAGE_NO"]) # インスタンスイメージの場合や、EBSイメージでインスタンスIDがない場合 if (image["ebsImage"] == "false" or isEmpty(awsInstance["INSTANCE_ID"])): #インスタンスIDがある場合はスキップ if (isEmpty(awsInstance["INSTANCE_ID"]) == False): return #インスタンスの作成 self.run(instanceNo, awsInstance, pccInstance, image) #インスタンスの作成待ち self.waitRun(instanceNo, pccInstance) #インスタンスにタグをつける self.createTag(instanceNo, pccInstance) #winodowsなら if (startsWithIgnoreCase(image["os"], "windows")): self.waitGetPasswordData(instanceNo, awsInstance) # EBSイメージでインスタンスIDがある場合 else: # インスタンスが停止中でない場合はスキップ if (awsInstance["STATUS"] != "stopped"): return # インスタンスの起動 self.start(instanceNo, awsInstance, pccInstance) # インスタンスの起動待ち self.waitStart(instanceNo, pccInstance) def stopInstance(self, instanceNo): #AWS_INSTANCE 取得 tableAWSINS = self.conn.getTable("AWS_INSTANCE") awsInstance = self.conn.selectOne( tableAWSINS.select(tableAWSINS.c.INSTANCE_NO == instanceNo)) # インスタンスIDがない場合はスキップ if (isEmpty(awsInstance["INSTANCE_ID"])): return #PCC_INSTANCE 取得 tableINS = self.conn.getTable("INSTANCE") pccInstance = self.conn.selectOne( tableINS.select(tableINS.c.INSTANCE_NO == instanceNo)) #イメージの取得 再考の余地あり image = getImage(pccInstance["IMAGE_NO"]) # インスタンスイメージの場合 if image["ebsImage"] == "false": try: # インスタンスの削除 self.terminate(instanceNo, awsInstance, pccInstance) # インスタンスの削除待ち self.waitTerminate(instanceNo, pccInstance) except Exception, e: self.logger.error(traceback.format_exc()) # 情報が不整合(インスタンス異常終了時など)の場合、警告ログと後始末のみ行う self.logger.warn(e.massage) updateDict = self.conn.selectOne( tableAWSINS.select( tableAWSINS.c.INSTANCE_NO == instanceNo)) updateDict["INSTANCE_ID"] = None updateDict["STATUS"] = None updateDict["DNS_NAME"] = None updateDict["PRIVATE_DNS_NAME"] = None updateDict["IP_ADDRESS"] = None updateDict["PRIVATE_IP_ADDRESS"] = None sql = tableAWSINS.update( tableAWSINS.c.INSTANCE_NO == updateDict["INSTANCE_NO"], values=updateDict) self.conn.execute(sql) # EBSイメージの場合 else:
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PrimeCloud Controller(TM). If not, see <http://www.gnu.org/licenses/>. # from iaasgw.log.log import IaasLogger from iaasgw.utils.iaasSelecter import iaasSelect import os import sys import traceback if __name__ == '__main__': param = sys.argv logger = IaasLogger() #ログ用パラメータ logparam = ["StartVolume",os.getpid(), "インスタンスNo:%s, ボリュームNo:%s" %(str(param[3]),str(param[3]))] logger.start(logparam) #実行 try: #パラメータ解説 # 0.ファイル名 # 1.ユーザー名 # 2.プラットフォームNo # 3.インスタンスNo # 4.ボリュームNo # # 例:param = [None, "1", "6", "1", "7", "1"]
class azureOtherController(object): logger = IaasLogger() client = None conn = None platforminfo = None def __init__(self, platforminfo, azureiaasclient, conn): self.client = azureiaasclient self.conn = conn self.platforminfo = platforminfo def createCloudServiceFor(self, platformNo): platformTable = self.conn.getTable("PLATFORM_AZURE") platformInfo = self.conn.selectOne(platformTable.select\ (platformTable.c.PLATFORM_NO==platformNo)) # クラウドサービスの存在確認 cloudService = platformInfo['CLOUD_SERVICE_NAME'] status = self.client.getCloudServiceStatus(cloudService) self.logger.info(' Cloud Service: %s, Status: %s' % (cloudService, status)) # クラウドサービスが存在しない場合、作成する if status is None: affinityGroup = platformInfo['AFFINITY_GROUP_NAME'] self.logger.debug(' Trying to create Cloud Service: %s' % (cloudService)) status = self.client.createCloudService(cloudService, affinityGroup) self.logger.info(' Cloud Service: %s, Status: %s' % (cloudService, status)) else: # ステータスが作成完了以外の場合の処理は要検討 pass def createStorageAccountFor(self, platformNo): platformTable = self.conn.getTable("PLATFORM_AZURE") platformInfo = self.conn.selectOne(platformTable.select\ (platformTable.c.PLATFORM_NO==platformNo)) # ストレージアカウントの存在確認 # 名前が要件を満たしているか確認必要 # Storage account names must be between 3 and 24 characters in length and use numbers and lower-case letters only. storageAccount = platformInfo['STORAGE_ACCOUNT_NAME'] self._verifyStorageAccountName(storageAccount) status = self.client.getStorageAccountStatus(storageAccount) self.logger.info(' Storage Account: %s, Status: %s' % (storageAccount, status)) # ストレージアカウントが存在しない場合、作成する if status is None: affinityGroup = platformInfo['AFFINITY_GROUP_NAME'] self.logger.debug(' Trying to create Storage Account: %s' % (storageAccount)) status = self.client.createStorageAccount(storageAccount, affinityGroup) self.logger.info(' Storage Account: %s, Status: %s' % (storageAccount, status)) else: # ステータスが作成完了以外の場合の処理は要検討 pass def _verifyStorageAccountName(self, storageAccount): pass
# from iaasgw.log.log import IaasLogger from iaasgw.utils.iaasSelecter import iaasSelect import os import sys import traceback #***************************************************************** # # 注)これはvCloudプラットフォーム専用のインターフェースとなります # #***************************************************************** if __name__ == '__main__': param = sys.argv logger = IaasLogger() #ログ用パラメータ logparam = ["DeleteMyCloud", os.getpid(), "Farm ID:%s" % str(param[3])] logger.start(logparam) #実行 try: #パラメータ解説 # 0.ファイル名 # 1.ユーザー名 # 2.プラットフォームNo # 3.マイクラウド名 # iaasController = iaasSelect(param[1], param[2]) if iaasController == None:
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PrimeCloud Controller(TM). If not, see <http://www.gnu.org/licenses/>. # from azure import * from azure.servicemanagement import * from azure.storage import BlobService from iaasgw.log.log import IaasLogger import traceback import time if __name__ == "__main__": logger = IaasLogger() argc = len(sys.argv) if (argc != 7): logger.error('deleteOSandDataDisk.py: Usage: python %s subscription certificateFilePath storageAccount accessKey mediaLink osHardDiskName' % sys.argv[0]) sys.exit() subscription = sys.argv[1] certPath = sys.argv[2] storageAccount = sys.argv[3] accessKey = sys.argv[4] mediaLink = sys.argv[5] osHardDiskName = sys.argv[6] #-------------- # Azureサービスオブジェクトを作成