Restore implementations for policies and management group creation
These were accidentally stripped out during a rebase.
This commit is contained in:
parent
f5e4b603cb
commit
1b1a20cf52
@ -5,9 +5,11 @@ from uuid import uuid4
|
|||||||
from pydantic import BaseModel, validator
|
from pydantic import BaseModel, validator
|
||||||
|
|
||||||
from atst.models.user import User
|
from atst.models.user import User
|
||||||
|
from atst.models.application import Application
|
||||||
from atst.models.environment import Environment
|
from atst.models.environment import Environment
|
||||||
from atst.models.environment_role import EnvironmentRole
|
from atst.models.environment_role import EnvironmentRole
|
||||||
from atst.utils import snake_to_camel
|
from atst.utils import snake_to_camel
|
||||||
|
from .policy import AzurePolicyManager
|
||||||
|
|
||||||
|
|
||||||
class GeneralCSPException(Exception):
|
class GeneralCSPException(Exception):
|
||||||
@ -718,11 +720,12 @@ SUBSCRIPTION_ID_REGEX = re.compile(
|
|||||||
|
|
||||||
# This needs to be a fully pathed role definition identifier, not just a UUID
|
# This needs to be a fully pathed role definition identifier, not just a UUID
|
||||||
REMOTE_ROOT_ROLE_DEF_ID = "/providers/Microsoft.Authorization/roleDefinitions/00000000-0000-4000-8000-000000000000"
|
REMOTE_ROOT_ROLE_DEF_ID = "/providers/Microsoft.Authorization/roleDefinitions/00000000-0000-4000-8000-000000000000"
|
||||||
|
AZURE_MANAGEMENT_API = "https://management.azure.com"
|
||||||
|
|
||||||
class AzureSDKProvider(object):
|
class AzureSDKProvider(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
from azure.mgmt import subscription, authorization
|
from azure.mgmt import subscription, authorization, managementgroups
|
||||||
|
from azure.mgmt.resource import policy
|
||||||
import azure.graphrbac as graphrbac
|
import azure.graphrbac as graphrbac
|
||||||
import azure.common.credentials as credentials
|
import azure.common.credentials as credentials
|
||||||
import azure.identity as identity
|
import azure.identity as identity
|
||||||
@ -733,6 +736,8 @@ class AzureSDKProvider(object):
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
self.subscription = subscription
|
self.subscription = subscription
|
||||||
|
self.policy = policy
|
||||||
|
self.managementgroups = managementgroups
|
||||||
self.authorization = authorization
|
self.authorization = authorization
|
||||||
self.adal = adal
|
self.adal = adal
|
||||||
self.graphrbac = graphrbac
|
self.graphrbac = graphrbac
|
||||||
@ -758,6 +763,8 @@ class AzureCloudProvider(CloudProviderInterface):
|
|||||||
else:
|
else:
|
||||||
self.sdk = azure_sdk_provider
|
self.sdk = azure_sdk_provider
|
||||||
|
|
||||||
|
self.policy_manager = AzurePolicyManager(config["AZURE_POLICY_LOCATION"])
|
||||||
|
|
||||||
def set_secret(secret_key, secret_value):
|
def set_secret(secret_key, secret_value):
|
||||||
credential = self._get_client_secret_credential_obj()
|
credential = self._get_client_secret_credential_obj()
|
||||||
secret_client = self.secrets.SecretClient(
|
secret_client = self.secrets.SecretClient(
|
||||||
@ -777,42 +784,23 @@ class AzureCloudProvider(CloudProviderInterface):
|
|||||||
def create_environment(
|
def create_environment(
|
||||||
self, auth_credentials: Dict, user: User, environment: Environment
|
self, auth_credentials: Dict, user: User, environment: Environment
|
||||||
):
|
):
|
||||||
|
# since this operation would only occur within a tenant, should we source the tenant
|
||||||
|
# via lookup from environment once we've created the portfolio csp data schema
|
||||||
|
# something like this:
|
||||||
|
# environment_tenant = environment.application.portfolio.csp_data.get('tenant_id', None)
|
||||||
|
# though we'd probably source the whole credentials for these calls from the portfolio csp
|
||||||
|
# data, as it would have to be where we store the creds for the at-at user within the portfolio tenant
|
||||||
|
# credentials = self._get_credential_obj(environment.application.portfolio.csp_data.get_creds())
|
||||||
credentials = self._get_credential_obj(self._root_creds)
|
credentials = self._get_credential_obj(self._root_creds)
|
||||||
sub_client = self.sdk.subscription.SubscriptionClient(credentials)
|
|
||||||
|
|
||||||
display_name = f"{environment.application.name}_{environment.name}_{environment.id}" # proposed format
|
display_name = f"{environment.application.name}_{environment.name}_{environment.id}" # proposed format
|
||||||
|
management_group_id = "?" # management group id chained from environment
|
||||||
|
parent_id = "?" # from environment.application
|
||||||
|
|
||||||
billing_profile_id = "?" # something chained from environment?
|
management_group = self._create_management_group(
|
||||||
sku_id = AZURE_SKU_ID
|
credentials, management_group_id, display_name, parent_id,
|
||||||
# we want to set AT-AT as an owner here
|
|
||||||
# we could potentially associate subscriptions with "management groups" per DOD component
|
|
||||||
body = self.sdk.subscription.models.ModernSubscriptionCreationParameters(
|
|
||||||
display_name,
|
|
||||||
billing_profile_id,
|
|
||||||
sku_id,
|
|
||||||
# owner=<AdPrincipal: for AT-AT user>
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# These 2 seem like something that might be worthwhile to allow tiebacks to
|
return management_group
|
||||||
# TOs filed for the environment
|
|
||||||
billing_account_name = "?"
|
|
||||||
invoice_section_name = "?"
|
|
||||||
# We may also want to create billing sections in the enrollment account
|
|
||||||
sub_creation_operation = sub_client.subscription_factory.create_subscription(
|
|
||||||
billing_account_name, invoice_section_name, body
|
|
||||||
)
|
|
||||||
|
|
||||||
# the resulting object from this process is a link to the new subscription
|
|
||||||
# not a subscription model, so we'll have to unpack the ID
|
|
||||||
new_sub = sub_creation_operation.result()
|
|
||||||
|
|
||||||
subscription_id = self._extract_subscription_id(new_sub.subscription_link)
|
|
||||||
if subscription_id:
|
|
||||||
return subscription_id
|
|
||||||
else:
|
|
||||||
# troublesome error, subscription should exist at this point
|
|
||||||
# but we just don't have a valid ID
|
|
||||||
pass
|
|
||||||
|
|
||||||
def create_atat_admin_user(
|
def create_atat_admin_user(
|
||||||
self, auth_credentials: Dict, csp_environment_id: str
|
self, auth_credentials: Dict, csp_environment_id: str
|
||||||
@ -851,6 +839,125 @@ class AzureCloudProvider(CloudProviderInterface):
|
|||||||
"role_name": role_assignment_id,
|
"role_name": role_assignment_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _create_application(self, auth_credentials: Dict, application: Application):
|
||||||
|
management_group_name = str(uuid4()) # can be anything, not just uuid
|
||||||
|
display_name = application.name # Does this need to be unique?
|
||||||
|
credentials = self._get_credential_obj(auth_credentials)
|
||||||
|
parent_id = "?" # application.portfolio.csp_details.management_group_id
|
||||||
|
|
||||||
|
return self._create_management_group(
|
||||||
|
credentials, management_group_name, display_name, parent_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _create_management_group(
|
||||||
|
self, credentials, management_group_id, display_name, parent_id=None,
|
||||||
|
):
|
||||||
|
mgmgt_group_client = self.sdk.managementgroups.ManagementGroupsAPI(credentials)
|
||||||
|
create_parent_grp_info = self.sdk.managementgroups.models.CreateParentGroupInfo(
|
||||||
|
id=parent_id
|
||||||
|
)
|
||||||
|
create_mgmt_grp_details = self.sdk.managementgroups.models.CreateManagementGroupDetails(
|
||||||
|
parent=create_parent_grp_info
|
||||||
|
)
|
||||||
|
mgmt_grp_create = self.sdk.managementgroups.models.CreateManagementGroupRequest(
|
||||||
|
name=management_group_id,
|
||||||
|
display_name=display_name,
|
||||||
|
details=create_mgmt_grp_details,
|
||||||
|
)
|
||||||
|
create_request = mgmgt_group_client.management_groups.create_or_update(
|
||||||
|
management_group_id, mgmt_grp_create
|
||||||
|
)
|
||||||
|
|
||||||
|
# result is a synchronous wait, might need to do a poll instead to handle first mgmt group create
|
||||||
|
# since we were told it could take 10+ minutes to complete, unless this handles that polling internally
|
||||||
|
return create_request.result()
|
||||||
|
|
||||||
|
def _create_subscription(
|
||||||
|
self,
|
||||||
|
credentials,
|
||||||
|
display_name,
|
||||||
|
billing_profile_id,
|
||||||
|
sku_id,
|
||||||
|
management_group_id,
|
||||||
|
billing_account_name,
|
||||||
|
invoice_section_name,
|
||||||
|
):
|
||||||
|
sub_client = self.sdk.subscription.SubscriptionClient(credentials)
|
||||||
|
|
||||||
|
billing_profile_id = "?" # where do we source this?
|
||||||
|
sku_id = AZURE_SKU_ID
|
||||||
|
# These 2 seem like something that might be worthwhile to allow tiebacks to
|
||||||
|
# TOs filed for the environment
|
||||||
|
billing_account_name = "?" # from TO?
|
||||||
|
invoice_section_name = "?" # from TO?
|
||||||
|
|
||||||
|
body = self.sdk.subscription.models.ModernSubscriptionCreationParameters(
|
||||||
|
display_name=display_name,
|
||||||
|
billing_profile_id=billing_profile_id,
|
||||||
|
sku_id=sku_id,
|
||||||
|
management_group_id=management_group_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
# We may also want to create billing sections in the enrollment account
|
||||||
|
sub_creation_operation = sub_client.subscription_factory.create_subscription(
|
||||||
|
billing_account_name, invoice_section_name, body
|
||||||
|
)
|
||||||
|
|
||||||
|
# the resulting object from this process is a link to the new subscription
|
||||||
|
# not a subscription model, so we'll have to unpack the ID
|
||||||
|
new_sub = sub_creation_operation.result()
|
||||||
|
|
||||||
|
subscription_id = self._extract_subscription_id(new_sub.subscription_link)
|
||||||
|
if subscription_id:
|
||||||
|
return subscription_id
|
||||||
|
else:
|
||||||
|
# troublesome error, subscription should exist at this point
|
||||||
|
# but we just don't have a valid ID
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _create_policy_definition(
|
||||||
|
self, credentials, subscription_id, management_group_id, properties,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Requires credentials that have AZURE_MANAGEMENT_API
|
||||||
|
specified as the resource. The Service Principal
|
||||||
|
specified in the credentials must have the "Resource
|
||||||
|
Policy Contributor" role assigned with a scope at least
|
||||||
|
as high as the management group specified by
|
||||||
|
management_group_id.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
credentials -- ServicePrincipalCredentials
|
||||||
|
subscription_id -- str, ID of the subscription (just the UUID, not the path)
|
||||||
|
management_group_id -- str, ID of the management group (just the UUID, not the path)
|
||||||
|
properties -- dictionary, the "properties" section of a valid Azure policy definition document
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
azure.mgmt.resource.policy.[api version].models.PolicyDefinition: the PolicyDefinition object provided to Azure
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
TBD
|
||||||
|
"""
|
||||||
|
# TODO: which subscription would this be?
|
||||||
|
client = self.sdk.policy.PolicyClient(credentials, subscription_id)
|
||||||
|
|
||||||
|
definition = client.policy_definitions.models.PolicyDefinition(
|
||||||
|
policy_type=properties.get("policyType"),
|
||||||
|
mode=properties.get("mode"),
|
||||||
|
display_name=properties.get("displayName"),
|
||||||
|
description=properties.get("description"),
|
||||||
|
policy_rule=properties.get("policyRule"),
|
||||||
|
parameters=properties.get("parameters"),
|
||||||
|
)
|
||||||
|
|
||||||
|
name = properties.get("displayName")
|
||||||
|
|
||||||
|
return client.policy_definitions.create_or_update_at_management_group(
|
||||||
|
policy_definition_name=name,
|
||||||
|
parameters=definition,
|
||||||
|
management_group_id=management_group_id,
|
||||||
|
)
|
||||||
|
|
||||||
def create_tenant(self, payload: TenantCSPPayload):
|
def create_tenant(self, payload: TenantCSPPayload):
|
||||||
sp_token = self._get_sp_token(payload.creds)
|
sp_token = self._get_sp_token(payload.creds)
|
||||||
if sp_token is None:
|
if sp_token is None:
|
||||||
@ -1112,9 +1219,7 @@ class AzureCloudProvider(CloudProviderInterface):
|
|||||||
return sub_id_match.group(1)
|
return sub_id_match.group(1)
|
||||||
|
|
||||||
def _get_sp_token(self, creds):
|
def _get_sp_token(self, creds):
|
||||||
home_tenant_id = creds.get(
|
home_tenant_id = creds.get("home_tenant_id")
|
||||||
"home_tenant_id"
|
|
||||||
)
|
|
||||||
client_id = creds.get("client_id")
|
client_id = creds.get("client_id")
|
||||||
secret_key = creds.get("secret_key")
|
secret_key = creds.get("secret_key")
|
||||||
|
|
||||||
@ -1141,7 +1246,8 @@ class AzureCloudProvider(CloudProviderInterface):
|
|||||||
resource=resource,
|
resource=resource,
|
||||||
cloud_environment=self.sdk.cloud,
|
cloud_environment=self.sdk.cloud,
|
||||||
)
|
)
|
||||||
def _get_client_secret_credential_obj():
|
|
||||||
|
def _get_client_secret_credential_obj(self, creds):
|
||||||
return self.sdk.identity.ClientSecretCredential(
|
return self.sdk.identity.ClientSecretCredential(
|
||||||
tenant_id=creds.get("tenant_id"),
|
tenant_id=creds.get("tenant_id"),
|
||||||
client_id =creds.get("client_id"),
|
client_id =creds.get("client_id"),
|
||||||
|
@ -26,14 +26,13 @@ from tests.factories import EnvironmentFactory, ApplicationFactory
|
|||||||
|
|
||||||
|
|
||||||
creds = {
|
creds = {
|
||||||
"home_tenant_id": "",
|
"home_tenant_id": "tenant_id",
|
||||||
"client_id": "",
|
"client_id": "client_id",
|
||||||
"secret_key": "",
|
"secret_key": "secret_key",
|
||||||
}
|
}
|
||||||
BILLING_ACCOUNT_NAME = "52865e4c-52e8-5a6c-da6b-c58f0814f06f:7ea5de9d-b8ce-4901-b1c5-d864320c7b03_2019-05-31"
|
BILLING_ACCOUNT_NAME = "52865e4c-52e8-5a6c-da6b-c58f0814f06f:7ea5de9d-b8ce-4901-b1c5-d864320c7b03_2019-05-31"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip("Skipping legacy azure integration tests")
|
|
||||||
def test_create_subscription_succeeds(mock_azure: AzureCloudProvider):
|
def test_create_subscription_succeeds(mock_azure: AzureCloudProvider):
|
||||||
environment = EnvironmentFactory.create()
|
environment = EnvironmentFactory.create()
|
||||||
|
|
||||||
@ -74,7 +73,6 @@ def mock_management_group_create(mock_azure, spec_dict):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip("Skipping legacy azure integration tests")
|
|
||||||
def test_create_environment_succeeds(mock_azure: AzureCloudProvider):
|
def test_create_environment_succeeds(mock_azure: AzureCloudProvider):
|
||||||
environment = EnvironmentFactory.create()
|
environment = EnvironmentFactory.create()
|
||||||
|
|
||||||
@ -87,7 +85,6 @@ def test_create_environment_succeeds(mock_azure: AzureCloudProvider):
|
|||||||
assert result.id == "Test Id"
|
assert result.id == "Test Id"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip("Skipping legacy azure integration tests")
|
|
||||||
def test_create_application_succeeds(mock_azure: AzureCloudProvider):
|
def test_create_application_succeeds(mock_azure: AzureCloudProvider):
|
||||||
application = ApplicationFactory.create()
|
application = ApplicationFactory.create()
|
||||||
|
|
||||||
@ -98,7 +95,6 @@ def test_create_application_succeeds(mock_azure: AzureCloudProvider):
|
|||||||
assert result.id == "Test Id"
|
assert result.id == "Test Id"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip("Skipping legacy azure integration tests")
|
|
||||||
def test_create_atat_admin_user_succeeds(mock_azure: AzureCloudProvider):
|
def test_create_atat_admin_user_succeeds(mock_azure: AzureCloudProvider):
|
||||||
environment_id = str(uuid4())
|
environment_id = str(uuid4())
|
||||||
|
|
||||||
@ -113,7 +109,6 @@ def test_create_atat_admin_user_succeeds(mock_azure: AzureCloudProvider):
|
|||||||
assert result.get("csp_user_id") == csp_user_id
|
assert result.get("csp_user_id") == csp_user_id
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip("Skipping legacy azure integration tests")
|
|
||||||
def test_create_policy_definition_succeeds(mock_azure: AzureCloudProvider):
|
def test_create_policy_definition_succeeds(mock_azure: AzureCloudProvider):
|
||||||
subscription_id = str(uuid4())
|
subscription_id = str(uuid4())
|
||||||
management_group_id = str(uuid4())
|
management_group_id = str(uuid4())
|
||||||
@ -191,7 +186,7 @@ def test_create_billing_profile_creation(mock_azure: AzureCloudProvider):
|
|||||||
country="US",
|
country="US",
|
||||||
postal_code="19109",
|
postal_code="19109",
|
||||||
),
|
),
|
||||||
creds={"username": "mock-cloud", "password": "shh"},
|
creds=creds,
|
||||||
tenant_id="60ff9d34-82bf-4f21-b565-308ef0533435",
|
tenant_id="60ff9d34-82bf-4f21-b565-308ef0533435",
|
||||||
billing_profile_display_name="Test Billing Profile",
|
billing_profile_display_name="Test Billing Profile",
|
||||||
billing_account_name=BILLING_ACCOUNT_NAME,
|
billing_account_name=BILLING_ACCOUNT_NAME,
|
||||||
@ -242,11 +237,7 @@ def test_validate_billing_profile_creation(mock_azure: AzureCloudProvider):
|
|||||||
|
|
||||||
payload = BillingProfileVerificationCSPPayload(
|
payload = BillingProfileVerificationCSPPayload(
|
||||||
**dict(
|
**dict(
|
||||||
creds={
|
creds=creds,
|
||||||
"username": "username",
|
|
||||||
"password": "password",
|
|
||||||
"tenant_id": "tenant_id",
|
|
||||||
},
|
|
||||||
billing_profile_verify_url="https://management.azure.com/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/operationResults/createBillingProfile_478d5706-71f9-4a8b-8d4e-2cbaca27a668?api-version=2019-10-01-preview",
|
billing_profile_verify_url="https://management.azure.com/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/operationResults/createBillingProfile_478d5706-71f9-4a8b-8d4e-2cbaca27a668?api-version=2019-10-01-preview",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -285,11 +276,7 @@ def test_create_billing_profile_tenant_access(mock_azure: AzureCloudProvider):
|
|||||||
|
|
||||||
payload = BillingProfileTenantAccessCSPPayload(
|
payload = BillingProfileTenantAccessCSPPayload(
|
||||||
**dict(
|
**dict(
|
||||||
creds={
|
creds=creds,
|
||||||
"username": "username",
|
|
||||||
"password": "password",
|
|
||||||
"tenant_id": "tenant_id",
|
|
||||||
},
|
|
||||||
tenant_id="60ff9d34-82bf-4f21-b565-308ef0533435",
|
tenant_id="60ff9d34-82bf-4f21-b565-308ef0533435",
|
||||||
user_object_id="0a5f4926-e3ee-4f47-a6e3-8b0a30a40e3d",
|
user_object_id="0a5f4926-e3ee-4f47-a6e3-8b0a30a40e3d",
|
||||||
billing_account_name="7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31",
|
billing_account_name="7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31",
|
||||||
@ -321,11 +308,7 @@ def test_create_task_order_billing_creation(mock_azure: AzureCloudProvider):
|
|||||||
|
|
||||||
payload = TaskOrderBillingCreationCSPPayload(
|
payload = TaskOrderBillingCreationCSPPayload(
|
||||||
**dict(
|
**dict(
|
||||||
creds={
|
creds=creds,
|
||||||
"username": "username",
|
|
||||||
"password": "password",
|
|
||||||
"tenant_id": "tenant_id",
|
|
||||||
},
|
|
||||||
billing_account_name="7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31",
|
billing_account_name="7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31",
|
||||||
billing_profile_name="KQWI-W2SU-BG7-TGB",
|
billing_profile_name="KQWI-W2SU-BG7-TGB",
|
||||||
)
|
)
|
||||||
@ -385,11 +368,7 @@ def test_create_task_order_billing_verification(mock_azure):
|
|||||||
|
|
||||||
payload = TaskOrderBillingVerificationCSPPayload(
|
payload = TaskOrderBillingVerificationCSPPayload(
|
||||||
**dict(
|
**dict(
|
||||||
creds={
|
creds=creds,
|
||||||
"username": "username",
|
|
||||||
"password": "password",
|
|
||||||
"tenant_id": "tenant_id",
|
|
||||||
},
|
|
||||||
task_order_billing_verify_url="https://management.azure.com/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/operationResults/createBillingProfile_478d5706-71f9-4a8b-8d4e-2cbaca27a668?api-version=2019-10-01-preview",
|
task_order_billing_verify_url="https://management.azure.com/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/operationResults/createBillingProfile_478d5706-71f9-4a8b-8d4e-2cbaca27a668?api-version=2019-10-01-preview",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -424,7 +403,7 @@ def test_create_billing_instruction(mock_azure: AzureCloudProvider):
|
|||||||
|
|
||||||
payload = BillingInstructionCSPPayload(
|
payload = BillingInstructionCSPPayload(
|
||||||
**dict(
|
**dict(
|
||||||
creds={},
|
creds=creds,
|
||||||
amount=1000.00,
|
amount=1000.00,
|
||||||
start_date="2020/1/1",
|
start_date="2020/1/1",
|
||||||
end_date="2020/3/1",
|
end_date="2020/3/1",
|
||||||
|
@ -72,6 +72,7 @@ class MockAzureSDK(object):
|
|||||||
|
|
||||||
self.subscription = mock_subscription()
|
self.subscription = mock_subscription()
|
||||||
self.authorization = mock_authorization()
|
self.authorization = mock_authorization()
|
||||||
|
self.policy = mock_policy()
|
||||||
self.adal = mock_adal()
|
self.adal = mock_adal()
|
||||||
self.managementgroups = mock_managementgroups()
|
self.managementgroups = mock_managementgroups()
|
||||||
self.graphrbac = mock_graphrbac()
|
self.graphrbac = mock_graphrbac()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user