1# -------------------------------------------------------------------------------------------- 2# Copyright (c) Microsoft Corporation. All rights reserved. 3# Licensed under the MIT License. See License.txt in the project root for license information. 4# -------------------------------------------------------------------------------------------- 5 6from azure.cli.core.commands.client_factory import get_mgmt_service_client 7from azure.cli.core.util import sdk_no_wait 8from knack.util import CLIError 9from knack.log import get_logger 10 11from .utils import normalize_sku_for_staticapp, raise_missing_token_suggestion 12 13logger = get_logger(__name__) 14 15 16def list_staticsites(cmd, resource_group_name=None): 17 client = _get_staticsites_client_factory(cmd.cli_ctx) 18 if resource_group_name: 19 result = list(client.get_static_sites_by_resource_group(resource_group_name)) 20 else: 21 result = list(client.list()) 22 return result 23 24 25def show_staticsite(cmd, name, resource_group_name=None): 26 client = _get_staticsites_client_factory(cmd.cli_ctx) 27 if not resource_group_name: 28 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 29 30 return client.get_static_site(resource_group_name, name) 31 32 33def disconnect_staticsite(cmd, name, resource_group_name=None, no_wait=False): 34 client = _get_staticsites_client_factory(cmd.cli_ctx) 35 if not resource_group_name: 36 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 37 38 return sdk_no_wait(no_wait, client.begin_detach_static_site, 39 resource_group_name=resource_group_name, name=name) 40 41 42def reconnect_staticsite(cmd, name, source, branch, token=None, resource_group_name=None, login_with_github=False, 43 no_wait=False): 44 client = _get_staticsites_client_factory(cmd.cli_ctx) 45 if not resource_group_name: 46 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 47 48 location = _get_staticsite_location(client, name, resource_group_name) 49 50 return create_staticsites(cmd, resource_group_name, name, location, 51 source, branch, token, login_with_github=login_with_github, no_wait=no_wait) 52 53 54def list_staticsite_environments(cmd, name, resource_group_name=None): 55 client = _get_staticsites_client_factory(cmd.cli_ctx) 56 if not resource_group_name: 57 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 58 59 return client.get_static_site_builds(resource_group_name, name) 60 61 62def delete_staticsite_environment(cmd, name, environment_name='default', resource_group_name=None, no_wait=False): 63 client = _get_staticsites_client_factory(cmd.cli_ctx) 64 if not resource_group_name: 65 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 66 67 return sdk_no_wait(no_wait, client.begin_delete_static_site_build, 68 resource_group_name, name, environment_name) 69 70 71def show_staticsite_environment(cmd, name, environment_name='default', resource_group_name=None): 72 client = _get_staticsites_client_factory(cmd.cli_ctx) 73 if not resource_group_name: 74 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 75 76 return client.get_static_site_build(resource_group_name, name, environment_name) 77 78 79def list_staticsite_domains(cmd, name, resource_group_name=None): 80 client = _get_staticsites_client_factory(cmd.cli_ctx) 81 if not resource_group_name: 82 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 83 84 return client.list_static_site_custom_domains(resource_group_name, name) 85 86 87def set_staticsite_domain(cmd, name, hostname, resource_group_name=None, no_wait=False): 88 client = _get_staticsites_client_factory(cmd.cli_ctx) 89 if not resource_group_name: 90 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 91 92 client.begin_validate_custom_domain_can_be_added_to_static_site(resource_group_name, name, hostname) 93 94 return sdk_no_wait(no_wait, client.create_or_update_static_site_custom_domain, 95 resource_group_name=resource_group_name, name=name, domain_name=hostname) 96 97 98def delete_staticsite_domain(cmd, name, hostname, resource_group_name=None, no_wait=False): 99 client = _get_staticsites_client_factory(cmd.cli_ctx) 100 if not resource_group_name: 101 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 102 103 logger.warning("After deleting a custom domain, there can be a 15 minute delay for the change to propagate.") 104 return sdk_no_wait(no_wait, client.begin_delete_static_site_custom_domain, 105 resource_group_name=resource_group_name, name=name, domain_name=hostname) 106 107 108def list_staticsite_functions(cmd, name, resource_group_name=None, environment_name='default'): 109 client = _get_staticsites_client_factory(cmd.cli_ctx) 110 if not resource_group_name: 111 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 112 113 return client.list_static_site_build_functions(resource_group_name, name, environment_name) 114 115 116def list_staticsite_function_app_settings(cmd, name, resource_group_name=None): 117 client = _get_staticsites_client_factory(cmd.cli_ctx) 118 if not resource_group_name: 119 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 120 121 return client.list_static_site_function_app_settings(resource_group_name, name) 122 123 124def set_staticsite_function_app_settings(cmd, name, setting_pairs, resource_group_name=None): 125 client = _get_staticsites_client_factory(cmd.cli_ctx) 126 if not resource_group_name: 127 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 128 129 setting_dict = {} 130 for pair in setting_pairs: 131 key, value = _parse_pair(pair, "=") 132 setting_dict[key] = value 133 134 return client.create_or_update_static_site_function_app_settings( 135 resource_group_name, name, app_settings=setting_dict) 136 137 138def delete_staticsite_function_app_settings(cmd, name, setting_names, resource_group_name=None): 139 client = _get_staticsites_client_factory(cmd.cli_ctx) 140 if not resource_group_name: 141 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 142 143 app_settings = client.list_static_site_function_app_settings(resource_group_name, name).properties 144 145 for key in setting_names: 146 if key in app_settings: 147 app_settings.pop(key) 148 else: 149 logger.warning("key '%s' not found in app settings", key) 150 151 return client.create_or_update_static_site_function_app_settings( 152 resource_group_name, name, app_settings=app_settings) 153 154 155def list_staticsite_users(cmd, name, resource_group_name=None, authentication_provider='all'): 156 client = _get_staticsites_client_factory(cmd.cli_ctx) 157 if not resource_group_name: 158 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 159 160 return client.list_static_site_users(resource_group_name, name, authentication_provider) 161 162 163def invite_staticsite_users(cmd, name, authentication_provider, user_details, domain, 164 roles, invitation_expiration_in_hours, resource_group_name=None): 165 client = _get_staticsites_client_factory(cmd.cli_ctx) 166 if not resource_group_name: 167 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 168 169 StaticSiteUserInvitationRequestResource = cmd.get_models('StaticSiteUserInvitationRequestResource') 170 171 invite_request = StaticSiteUserInvitationRequestResource( 172 domain=domain, 173 provider=authentication_provider, 174 user_details=user_details, 175 roles=roles, 176 num_hours_to_expiration=invitation_expiration_in_hours 177 ) 178 179 return client.create_user_roles_invitation_link(resource_group_name, name, invite_request) 180 181 182def update_staticsite_users(cmd, name, roles, authentication_provider=None, user_details=None, user_id=None, 183 resource_group_name=None): 184 client = _get_staticsites_client_factory(cmd.cli_ctx) 185 if not resource_group_name: 186 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 187 188 if not authentication_provider and user_id: 189 authentication_provider = _find_authentication_provider( 190 client, resource_group_name, name, user_id, authentication_provider) 191 192 if not user_id and user_details: 193 user_id, authentication_provider = _find_user_id_and_authentication_provider( 194 client, resource_group_name, name, user_id, authentication_provider, user_details) 195 196 if not authentication_provider or not user_id: 197 raise CLIError("Either user id or user details is required.") 198 199 return client.update_static_site_user(resource_group_name, name, authentication_provider, user_id, roles=roles) 200 201 202def create_staticsites(cmd, resource_group_name, name, location, 203 source, branch, token=None, 204 app_location='.', api_location='.', output_location='.github/workflows', 205 tags=None, no_wait=False, sku='Free', login_with_github=False): 206 if not token and not login_with_github: 207 raise_missing_token_suggestion() 208 elif not token: 209 from ._github_oauth import get_github_access_token 210 scopes = ["admin:repo_hook", "repo", "workflow"] 211 token = get_github_access_token(cmd, scopes) 212 elif token and login_with_github: 213 logger.warning("Both token and --login-with-github flag are provided. Will use provided token") 214 215 StaticSiteARMResource, StaticSiteBuildProperties, SkuDescription = cmd.get_models( 216 'StaticSiteARMResource', 'StaticSiteBuildProperties', 'SkuDescription') 217 218 build = StaticSiteBuildProperties( 219 app_location=app_location, 220 api_location=api_location, 221 app_artifact_location=output_location) 222 223 sku_def = SkuDescription(name=normalize_sku_for_staticapp(sku), tier=normalize_sku_for_staticapp(sku)) 224 225 staticsite_deployment_properties = StaticSiteARMResource( 226 location=location, 227 tags=tags, 228 repository_url=source, 229 branch=branch, 230 repository_token=token, 231 build_properties=build, 232 sku=sku_def) 233 234 client = _get_staticsites_client_factory(cmd.cli_ctx) 235 return sdk_no_wait(no_wait, client.begin_create_or_update_static_site, 236 resource_group_name=resource_group_name, name=name, 237 static_site_envelope=staticsite_deployment_properties) 238 239 240def update_staticsite(cmd, name, source=None, branch=None, token=None, 241 tags=None, sku=None, no_wait=False): 242 existing_staticsite = show_staticsite(cmd, name) 243 if not existing_staticsite: 244 raise CLIError("No static web app found with name {0}".format(name)) 245 246 if tags is not None: 247 existing_staticsite.tags = tags 248 249 StaticSiteARMResource, SkuDescription = cmd.get_models('StaticSiteARMResource', 'SkuDescription') 250 251 sku_def = None 252 if sku is not None: 253 sku_def = SkuDescription(name=normalize_sku_for_staticapp(sku), tier=normalize_sku_for_staticapp(sku)) 254 255 staticsite_deployment_properties = StaticSiteARMResource( 256 location=existing_staticsite.location, 257 tags=existing_staticsite.tags, 258 repository_url=source or existing_staticsite.repository_url, 259 branch=branch or existing_staticsite.branch, 260 repository_token=token or existing_staticsite.repository_token, 261 build_properties=existing_staticsite.build_properties, 262 sku=sku_def or existing_staticsite.sku) 263 264 client = _get_staticsites_client_factory(cmd.cli_ctx) 265 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 266 return sdk_no_wait(no_wait, client.update_static_site, 267 resource_group_name=resource_group_name, name=name, 268 static_site_envelope=staticsite_deployment_properties) 269 270 271def delete_staticsite(cmd, name, resource_group_name=None, no_wait=False): 272 client = _get_staticsites_client_factory(cmd.cli_ctx) 273 if not resource_group_name: 274 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 275 276 return sdk_no_wait(no_wait, client.begin_delete_static_site, 277 resource_group_name=resource_group_name, name=name) 278 279 280def _parse_pair(pair, delimiter): 281 if delimiter not in pair: 282 CLIError("invalid format of pair {0}".format(pair)) 283 284 index = pair.index(delimiter) 285 return pair[:index], pair[1 + index:] 286 287 288def _get_staticsite_location(client, static_site_name, resource_group_name): 289 static_sites = client.list() 290 for static_site in static_sites: 291 if static_site.name.lower() == static_site_name.lower(): 292 found_rg = _parse_resource_group_from_arm_id(static_site.id) 293 if found_rg: 294 if found_rg.lower() == resource_group_name.lower(): 295 return static_site.location 296 297 raise CLIError("Static site was '{}' not found in subscription and resource group '{}'." 298 .format(static_site_name, resource_group_name)) 299 300 301def _get_resource_group_name_of_staticsite(client, static_site_name): 302 static_sites = client.list() 303 for static_site in static_sites: 304 if static_site.name.lower() == static_site_name.lower(): 305 resource_group = _parse_resource_group_from_arm_id(static_site.id) 306 if resource_group: 307 return resource_group 308 309 raise CLIError("Static site was '{}' not found in subscription.".format(static_site_name)) 310 311 312def _parse_resource_group_from_arm_id(arm_id): 313 from msrestazure.tools import parse_resource_id 314 components = parse_resource_id(arm_id) 315 rg_key = 'resource_group' 316 if rg_key not in components: 317 return None 318 319 return components['resource_group'] 320 321 322def _get_staticsites_client_factory(cli_ctx, api_version=None): 323 from azure.mgmt.web import WebSiteManagementClient 324 client = get_mgmt_service_client(cli_ctx, WebSiteManagementClient).static_sites 325 if api_version: 326 client.api_version = api_version 327 return client 328 329 330def _find_authentication_provider(client, resource_group_name, name, user_id, authentication_provider): 331 users = client.list_static_site_users(resource_group_name, name, 'all') 332 for user in users: 333 if user.name.lower() == user_id.lower(): 334 authentication_provider = user.provider 335 336 if not authentication_provider: 337 raise CLIError("user id was not found.") 338 339 return authentication_provider 340 341 342def _find_user_id_and_authentication_provider(client, resource_group_name, name, 343 user_id, authentication_provider, user_details): 344 users = client.list_static_site_users(resource_group_name, name, 'all') 345 for user in users: 346 if user.display_name.lower() == user_details.lower(): 347 if not authentication_provider: 348 authentication_provider = user.provider 349 user_id = user.name 350 else: 351 if user.provider.lower() == authentication_provider.lower(): 352 user_id = user.name 353 354 if not user_id or not authentication_provider: 355 raise CLIError("user details and authentication provider was not found.") 356 357 return user_id, authentication_provider 358 359 360def list_staticsite_secrets(cmd, name, resource_group_name=None): 361 client = _get_staticsites_client_factory(cmd.cli_ctx) 362 if not resource_group_name: 363 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 364 365 return client.list_static_site_secrets(resource_group_name=resource_group_name, name=name) 366 367 368def reset_staticsite_api_key(cmd, name, resource_group_name=None): 369 client = _get_staticsites_client_factory(cmd.cli_ctx) 370 if not resource_group_name: 371 resource_group_name = _get_resource_group_name_of_staticsite(client, name) 372 373 existing_staticsite = show_staticsite(cmd, name, resource_group_name) 374 ResetPropertiesEnvelope = cmd.get_models('StaticSiteResetPropertiesARMResource') 375 reset_envelope = ResetPropertiesEnvelope(repository_token=existing_staticsite.repository_token) 376 return client.reset_static_site_api_key(resource_group_name=resource_group_name, 377 name=name, 378 reset_properties_envelope=reset_envelope) 379