def create_bot_json(cmd, client, resource_group_name, resource_name, app_password=None, raw_bot_properties=None): if not raw_bot_properties: raw_bot_properties = client.bots.get( resource_group_name=resource_group_name, resource_name=resource_name ) if not app_password: app_settings = get_app_settings( cmd=cmd, resource_group_name=resource_group_name, name=resource_name ) app_password = [item['value'] for item in app_settings if item['name'] == 'MicrosoftAppPassword'][0] profile = Profile(cli_ctx=cmd.cli_ctx) return { 'type': 'abs', 'id': raw_bot_properties.name, 'name': raw_bot_properties.properties.display_name, 'appId': raw_bot_properties.properties.msa_app_id, 'appPassword': app_password, 'endpoint': raw_bot_properties.properties.endpoint, 'resourceGroup': str(resource_group_name), 'tenantId': profile.get_subscription(subscription=client.config.subscription_id)['tenantId'], 'subscriptionId': client.config.subscription_id }
def show(self): output = {'Application name': self.name} settings = {} for setting in get_app_settings(self.__cmd, resource_group_name=self.name, name=self.name): settings.update({setting['name']: setting['value']}) if settings: output.update({ 'Application settings (stored as environmental variables on server)': settings }) output.update({ 'Deployment info': { 'Git url': self.deployment_info.git_url, 'User name': self.deployment_info.name, 'User password': self.deployment_info.password } }) output.update( {'Website url': 'https://{}.azurewebsites.net'.format(self.name)}) return output
def process_functionapp(self): """Helper to retrieve information about a functionapp""" if self.functionapp_name is None: functionapp = self._select_functionapp() self.functionapp_name = functionapp.name else: functionapp = self.cmd_selector.cmd_functionapp( self.functionapp_name) kinds = show_functionapp(self.cmd, functionapp.resource_group, functionapp.name).kind.split(',') # Get functionapp settings in Azure app_settings = get_app_settings(self.cmd, functionapp.resource_group, functionapp.name) self.resource_group_name = functionapp.resource_group self.functionapp_type = self._find_type(kinds) try: self.functionapp_language = self._get_functionapp_runtime_language( app_settings) self.storage_name = self._get_functionapp_storage_name( app_settings) except LanguageNotSupportException as lnse: raise CLIError( "Sorry, currently we do not support {language}.".format( language=lnse.message)) from lnse
def __read_kv_from_app_service(cmd, appservice_account, prefix_to_add="", content_type=None): try: key_values = [] from azure.cli.command_modules.appservice.custom import get_app_settings settings = get_app_settings( cmd, resource_group_name=appservice_account["resource_group"], name=appservice_account["name"], slot=None) for item in settings: key = prefix_to_add + item['name'] if validate_import_key(key): tags = {'AppService:SlotSetting': str(item['slotSetting']).lower()} if item['slotSetting'] else {} value = item['value'] # Value will look like one of the following if it is a KeyVault reference: # @Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931) # @Microsoft.KeyVault(VaultName=myvault;SecretName=mysecret;SecretVersion=ec96f02080254f109c51a1f14cdb1931) if value and value.strip().lower().startswith(KeyVaultConstants.APPSVC_KEYVAULT_PREFIX.lower()): try: # Strip all whitespaces from value string. # Valid values of SecretUri, VaultName, SecretName or SecretVersion will never have whitespaces. value = value.replace(" ", "") appsvc_value_dict = dict(x.split('=') for x in value[len(KeyVaultConstants.APPSVC_KEYVAULT_PREFIX) + 1: -1].split(';')) appsvc_value_dict = {k.lower(): v for k, v in appsvc_value_dict.items()} secret_identifier = appsvc_value_dict.get('secreturi') if not secret_identifier: # Construct secreturi vault_name = appsvc_value_dict.get('vaultname') secret_name = appsvc_value_dict.get('secretname') secret_version = appsvc_value_dict.get('secretversion') secret_identifier = "https://{0}.vault.azure.net/secrets/{1}/{2}".format(vault_name, secret_name, secret_version) try: from azure.keyvault.key_vault_id import KeyVaultIdentifier # this throws an exception for invalid format of secret identifier KeyVaultIdentifier(uri=secret_identifier) kv = KeyValue(key=key, value=json.dumps({"uri": secret_identifier}, ensure_ascii=False, separators=(',', ':')), tags=tags, content_type=KeyVaultConstants.KEYVAULT_CONTENT_TYPE) key_values.append(kv) continue except (TypeError, ValueError) as e: logger.debug( 'Exception while validating the format of KeyVault identifier. Key "%s" with value "%s" will be treated like a regular key-value.\n%s', key, value, str(e)) except (AttributeError, TypeError, ValueError) as e: logger.debug( 'Key "%s" with value "%s" is not a well-formatted KeyVault reference. It will be treated like a regular key-value.\n%s', key, value, str(e)) elif content_type and __is_json_content_type(content_type): # If appservice values are being imported with JSON content type, # we need to validate that values are in valid JSON format. try: json.loads(value) except ValueError: raise CLIError('Value "{}" for key "{}" is not a valid JSON object, which conflicts with the provided content type "{}".'.format(value, key, content_type)) kv = KeyValue(key=key, value=value, tags=tags) key_values.append(kv) return key_values except Exception as exception: raise CLIError("Failed to read key-values from appservice.\n" + str(exception))
def show(self): output = {} settings = {} for setting in get_app_settings(self.__cmd, resource_group_name=self.name, name=self.name): settings.update({setting['name']: setting['value']}) output.update({'App settings': settings}) urls = {} repo_url = 'https://{}.scm.azurewebsites.net/{}.git'.format( self.name, self.name) urls.update({'Git url': repo_url}) urls.update({'Website url': repo_url.replace('scm.', '')}) output.update({'URLs': urls}) return output
def __read_kv_from_app_service(cmd, appservice_account, prefix_to_add=""): try: key_values = [] from azure.cli.command_modules.appservice.custom import get_app_settings settings = get_app_settings( cmd, resource_group_name=appservice_account["resource_group"], name=appservice_account["name"], slot=None) for item in settings: key = prefix_to_add + item['name'] value = item['value'] tags = {'AppService:SlotSetting': str(item['slotSetting']).lower()} kv = KeyValue(key=key, value=value, tags=tags) key_values.append(kv) return key_values except Exception as exception: raise CLIError( "Fail to read key-values from appservice." + str(exception))
def show(self): output = {} settings = {} for setting in get_app_settings(self.__cmd, resource_group_name=self.name, name=self.name): settings.update({setting['name']: setting['value']}) output.update({'App settings': settings}) urls = {} repo_url = show_source_control(self.__cmd, resource_group_name=self.name, name=self.name).repo_url urls.update({'Git url': repo_url}) urls.update({'Website url': repo_url.replace('scm.', '')}) output.update({'URLs': urls}) return output
def create_deploy_webapp(cmd, name, location=None, sku=None, dryrun=False): import os client = web_client_factory(cmd.cli_ctx) # the code to deploy is expected to be the current directory the command is running from src_dir = os.getcwd() # if dir is empty, show a message in dry run do_deployment = False if os.listdir(src_dir) == [] else True create_new_rg = True create_new_asp = True set_build_appSetting = False # determine the details for app to be created from src contents lang_details = get_lang_from_content(src_dir) # we support E2E create and deploy for Node & dotnetcore, any other stack, set defaults for os & runtime # and skip deployment if lang_details['language'] is None: do_deployment = False sku = sku | 'F1' os_val = OS_DEFAULT detected_version = '-' runtime_version = '-' else: # update SKU to user set value if sku is None: sku = lang_details.get("default_sku") else: sku = sku language = lang_details.get("language") is_skip_build = language.lower( ) == STATIC_RUNTIME_NAME or language.lower() == PYTHON_RUNTIME_NAME os_val = "Linux" if language.lower() == NODE_RUNTIME_NAME \ or language.lower() == PYTHON_RUNTIME_NAME else OS_DEFAULT # detect the version data = get_runtime_version_details(lang_details.get('file_loc'), language) version_used_create = data.get('to_create') detected_version = data.get('detected') runtime_version = "{}|{}".format(language, version_used_create) if \ version_used_create != "-" else version_used_create full_sku = get_sku_name(sku) if location is None: locs = client.list_geo_regions(sku, True) available_locs = [] for loc in locs: available_locs.append(loc.name) location = available_locs[0] else: location = location # Remove spaces from the location string, incase the GeoRegion string is used loc_name = location.replace(" ", "").lower() is_linux = True if os_val == 'Linux' else False asp = "appsvc_asp_{}_{}".format(os_val, loc_name) rg_name = "appsvc_rg_{}_{}".format(os_val, loc_name) str_no_contents_warn = "" if not do_deployment: str_no_contents_warn = "[Empty directory, no deployment will be triggered]" # Resource group: check if default RG is set default_rg = cmd.cli_ctx.config.get('defaults', 'group', fallback=None) if default_rg and check_resource_group_exists( cmd, default_rg) and check_resource_group_supports_os( cmd, default_rg, is_linux): create_new_rg = False elif check_resource_group_exists( cmd, rg_name) and check_resource_group_supports_os( cmd, rg_name, is_linux): create_new_rg = False else: create_new_rg = True src_path = "{} {}".format(src_dir.replace("\\", "\\\\"), str_no_contents_warn) rg_str = "{}".format(rg_name) dry_run_str = r""" { "name" : "%s", "serverfarm" : "%s", "resourcegroup" : "%s", "sku": "%s", "os": "%s", "location" : "%s", "src_path" : "%s", "version_detected": "%s", "version_to_create": "%s" } """ % (name, asp, rg_str, full_sku, os_val, location, src_path, detected_version, runtime_version) create_json = json.loads(dry_run_str) if dryrun: logger.warning( "Web app will be created with the below configuration,re-run command " "without the --dryrun flag to create & deploy a new app") return create_json # create RG if the RG doesn't already exist if create_new_rg: logger.warning("Creating Resource group '%s' ...", rg_name) create_resource_group(cmd, rg_name, location) logger.warning("Resource group creation complete") else: logger.warning("Resource group '%s' already exists.", rg_name) # create asp ], if are creating a new RG we can skip the checks for if asp exists if create_new_rg: logger.warning("Creating App service plan '%s' ...", asp) sku_def = SkuDescription(tier=full_sku, name=sku, capacity=(1 if is_linux else None)) plan_def = AppServicePlan(location=loc_name, app_service_plan_name=asp, sku=sku_def, reserved=(is_linux or None)) client.app_service_plans.create_or_update(rg_name, asp, plan_def) logger.warning("App service plan creation complete") create_new_asp = True elif not check_if_asp_exists(cmd, rg_name, asp, location): logger.warning("Creating App service plan '%s' ...", asp) sku_def = SkuDescription(tier=full_sku, name=sku, capacity=(1 if is_linux else None)) plan_def = AppServicePlan(location=loc_name, app_service_plan_name=asp, sku=sku_def, reserved=(is_linux or None)) client.app_service_plans.create_or_update(rg_name, asp, plan_def) create_new_asp = True logger.warning("App service plan creation complete") else: logger.warning("App service plan '%s' already exists.", asp) create_new_asp = False # create the app, skip checks for if app exists if a New RG or New ASP is created if create_new_rg or create_new_asp: logger.warning("Creating app '%s' ....", name) create_webapp(cmd, rg_name, name, asp, runtime_version if is_linux else None) logger.warning("Webapp creation complete") set_build_appSetting = True elif not check_app_exists(cmd, rg_name, name): logger.warning("Creating app '%s' ....", name) create_webapp(cmd, rg_name, name, asp, runtime_version if is_linux else None) logger.warning("Webapp creation complete") set_build_appSetting = True else: logger.warning("App '%s' already exists", name) if do_deployment: # setting the appsettings causes a app restart so we avoid if not needed set_build_appSetting = False _app_settings = get_app_settings(cmd, rg_name, name) if all(not d for d in _app_settings): set_build_appSetting = True elif '"name": "SCM_DO_BUILD_DURING_DEPLOYMENT", "value": "true"' not in json.dumps( _app_settings[0]): set_build_appSetting = True else: set_build_appSetting = False # update create_json to include the app_url url = _get_app_url( cmd, rg_name, name) # picks the custom domain URL incase a domain is assigned if do_deployment: if not is_skip_build and set_build_appSetting: # setting to build after deployment logger.warning( "Updating app settings to enable build after deployment") update_app_settings(cmd, rg_name, name, ["SCM_DO_BUILD_DURING_DEPLOYMENT=true"]) # work around until the timeout limits issue for linux is investigated & fixed # wakeup kudu, by making an SCM call # TODO: replace this with a call to check if AppSettings, was set before calling zip deployment import time time.sleep(5) _ping_scm_site(cmd, rg_name, name) logger.warning("Creating zip with contents of dir %s ...", src_dir) # zip contents & deploy zip_file_path = zip_contents_from_dir(src_dir, language) logger.warning("Preparing to deploy %s contents to app.", '' if is_skip_build else 'and build') enable_zip_deploy(cmd, rg_name, name, zip_file_path) # Remove the file afer deployment, handling exception if user removed the file manually try: os.remove(zip_file_path) except OSError: pass else: logger.warning( 'No known package (Node, ASP.NET, .NETCORE, or Static Html) ' 'found skipping zip and deploy process') create_json.update({'app_url': url}) logger.warning("All done.") return create_json