Transition all Cloud Interface Methods to use Dataclasses
This commit is contained in:
parent
02ec54a310
commit
f08d53d7a0
@ -529,8 +529,8 @@ class MockCloudProvider(CloudProviderInterface):
|
|||||||
def set_secret(self, secret_key: str, secret_value: str):
|
def set_secret(self, secret_key: str, secret_value: str):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_secret(self, secret_key: str):
|
def get_secret(self, secret_key: str, default=dict()):
|
||||||
return {}
|
return default
|
||||||
|
|
||||||
def create_environment(self, auth_credentials, user, environment):
|
def create_environment(self, auth_credentials, user, environment):
|
||||||
self._authorize(auth_credentials)
|
self._authorize(auth_credentials)
|
||||||
@ -598,7 +598,7 @@ class MockCloudProvider(CloudProviderInterface):
|
|||||||
"tenant_admin_username": "test",
|
"tenant_admin_username": "test",
|
||||||
"tenant_admin_password": "test",
|
"tenant_admin_password": "test",
|
||||||
}
|
}
|
||||||
).dict()
|
)
|
||||||
|
|
||||||
def create_billing_profile_creation(
|
def create_billing_profile_creation(
|
||||||
self, payload: BillingProfileCreationCSPPayload
|
self, payload: BillingProfileCreationCSPPayload
|
||||||
@ -613,7 +613,7 @@ class MockCloudProvider(CloudProviderInterface):
|
|||||||
billing_profile_verify_url="https://zombo.com",
|
billing_profile_verify_url="https://zombo.com",
|
||||||
billing_profile_retry_after=10,
|
billing_profile_retry_after=10,
|
||||||
)
|
)
|
||||||
).dict()
|
)
|
||||||
|
|
||||||
def create_billing_profile_verification(
|
def create_billing_profile_verification(
|
||||||
self, payload: BillingProfileVerificationCSPPayload
|
self, payload: BillingProfileVerificationCSPPayload
|
||||||
@ -651,7 +651,7 @@ class MockCloudProvider(CloudProviderInterface):
|
|||||||
},
|
},
|
||||||
"type": "Microsoft.Billing/billingAccounts/billingProfiles",
|
"type": "Microsoft.Billing/billingAccounts/billingProfiles",
|
||||||
}
|
}
|
||||||
).dict()
|
)
|
||||||
|
|
||||||
def create_billing_profile_tenant_access(self, payload):
|
def create_billing_profile_tenant_access(self, payload):
|
||||||
self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION)
|
self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION)
|
||||||
@ -672,7 +672,7 @@ class MockCloudProvider(CloudProviderInterface):
|
|||||||
},
|
},
|
||||||
"type": "Microsoft.Billing/billingRoleAssignments",
|
"type": "Microsoft.Billing/billingRoleAssignments",
|
||||||
}
|
}
|
||||||
).dict()
|
)
|
||||||
|
|
||||||
def create_task_order_billing_creation(
|
def create_task_order_billing_creation(
|
||||||
self, payload: TaskOrderBillingCreationCSPPayload
|
self, payload: TaskOrderBillingCreationCSPPayload
|
||||||
@ -683,7 +683,7 @@ class MockCloudProvider(CloudProviderInterface):
|
|||||||
|
|
||||||
return TaskOrderBillingCreationCSPResult(
|
return TaskOrderBillingCreationCSPResult(
|
||||||
**{"Location": "https://somelocation", "Retry-After": "10"}
|
**{"Location": "https://somelocation", "Retry-After": "10"}
|
||||||
).dict()
|
)
|
||||||
|
|
||||||
def create_task_order_billing_verification(
|
def create_task_order_billing_verification(
|
||||||
self, payload: TaskOrderBillingVerificationCSPPayload
|
self, payload: TaskOrderBillingVerificationCSPPayload
|
||||||
@ -720,7 +720,7 @@ class MockCloudProvider(CloudProviderInterface):
|
|||||||
},
|
},
|
||||||
"type": "Microsoft.Billing/billingAccounts/billingProfiles",
|
"type": "Microsoft.Billing/billingAccounts/billingProfiles",
|
||||||
}
|
}
|
||||||
).dict()
|
)
|
||||||
|
|
||||||
def create_billing_instruction(self, payload: BillingInstructionCSPPayload):
|
def create_billing_instruction(self, payload: BillingInstructionCSPPayload):
|
||||||
self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION)
|
self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION)
|
||||||
@ -737,7 +737,7 @@ class MockCloudProvider(CloudProviderInterface):
|
|||||||
},
|
},
|
||||||
"type": "Microsoft.Billing/billingAccounts/billingProfiles/billingInstructions",
|
"type": "Microsoft.Billing/billingAccounts/billingProfiles/billingInstructions",
|
||||||
}
|
}
|
||||||
).dict()
|
)
|
||||||
|
|
||||||
def create_or_update_user(self, auth_credentials, user_info, csp_role_id):
|
def create_or_update_user(self, auth_credentials, user_info, csp_role_id):
|
||||||
self._authorize(auth_credentials)
|
self._authorize(auth_credentials)
|
||||||
|
@ -144,70 +144,51 @@ class PortfolioStateMachine(
|
|||||||
else:
|
else:
|
||||||
self.csp = MockCSP(app).cloud
|
self.csp = MockCSP(app).cloud
|
||||||
|
|
||||||
attempts_count = 5
|
|
||||||
for attempt in range(attempts_count):
|
|
||||||
try:
|
try:
|
||||||
func_name = f"create_{stage}"
|
func_name = f"create_{stage}"
|
||||||
response = getattr(self.csp, func_name)(payload_data)
|
response = getattr(self.csp, func_name)(payload_data)
|
||||||
except (ConnectionException, UnknownServerException) as exc:
|
|
||||||
app.logger.error(
|
|
||||||
f"CSP api call. Caught exception for {self.__repr__()}. Retry attempt {attempt}",
|
|
||||||
exc_info=1,
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# failed all attempts
|
|
||||||
logger.info(f"CSP api call failed after {attempts_count} attempts.")
|
|
||||||
self.fail_stage(stage)
|
|
||||||
|
|
||||||
if self.portfolio.csp_data is None:
|
if self.portfolio.csp_data is None:
|
||||||
self.portfolio.csp_data = {}
|
self.portfolio.csp_data = {}
|
||||||
self.portfolio.csp_data.update(response)
|
self.portfolio.csp_data.update(response.dict())
|
||||||
db.session.add(self.portfolio)
|
db.session.add(self.portfolio)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
# store any updated creds, if necessary
|
if getattr(response, "get_creds", None) is not None:
|
||||||
|
new_creds = response.get_creds()
|
||||||
|
# TODO: one way salted hash of tenant_id to use as kv key name?
|
||||||
|
tenant_id = new_creds.get("tenant_id")
|
||||||
|
secret = self.csp.get_secret(tenant_id, new_creds)
|
||||||
|
secret.update(new_creds)
|
||||||
|
self.csp.set_secret(tenant_id, secret)
|
||||||
|
except PydanticValidationError as exc:
|
||||||
|
app.logger.error(
|
||||||
|
f"Failed to cast response to valid result class {self.__repr__()}:",
|
||||||
|
exc_info=1,
|
||||||
|
)
|
||||||
|
app.logger.info(exc.json())
|
||||||
|
print(exc.json())
|
||||||
|
app.logger.info(payload_data)
|
||||||
|
self.fail_stage(stage)
|
||||||
|
except (ConnectionException, UnknownServerException) as exc:
|
||||||
|
app.logger.error(
|
||||||
|
f"CSP api call. Caught exception for {self.__repr__()}.", exc_info=1,
|
||||||
|
)
|
||||||
|
self.fail_stage(stage)
|
||||||
|
|
||||||
self.finish_stage(stage)
|
self.finish_stage(stage)
|
||||||
|
|
||||||
def is_csp_data_valid(self, event):
|
def is_csp_data_valid(self, event):
|
||||||
# check portfolio csp details json field for fields
|
"""
|
||||||
|
This function guards advancing states from *_IN_PROGRESS to *_COMPLETED.
|
||||||
|
"""
|
||||||
if self.portfolio.csp_data is None or not isinstance(
|
if self.portfolio.csp_data is None or not isinstance(
|
||||||
self.portfolio.csp_data, dict
|
self.portfolio.csp_data, dict
|
||||||
):
|
):
|
||||||
print("no csp data")
|
print("no csp data")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
stage = self.current_state.name.split("_IN_PROGRESS")[0].lower()
|
|
||||||
stage_data = self.portfolio.csp_data
|
|
||||||
cls = get_stage_csp_class(stage, "result")
|
|
||||||
if not cls:
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
|
||||||
dc = cls(**stage_data)
|
|
||||||
if getattr(dc, "get_creds", None) is not None:
|
|
||||||
new_creds = dc.get_creds()
|
|
||||||
tenant_id = new_creds.get("tenant_id")
|
|
||||||
secret = self.csp.get_secret(tenant_id)
|
|
||||||
secret.update(new_creds)
|
|
||||||
self.csp.set_secret(tenant_id, secret)
|
|
||||||
|
|
||||||
except PydanticValidationError as exc:
|
|
||||||
app.logger.error(
|
|
||||||
f"Payload Validation Error in {self.__repr__()}:", exc_info=1
|
|
||||||
)
|
|
||||||
app.logger.info(exc.json())
|
|
||||||
app.logger.info(payload)
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# print('failed condition', self.portfolio.csp_data)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def application_id(self):
|
def application_id(self):
|
||||||
return None
|
return None
|
||||||
|
@ -11,6 +11,8 @@ from atst.models.mixins.state_machines import AzureStages, StageStates, compose_
|
|||||||
from atst.models.portfolio import Portfolio
|
from atst.models.portfolio import Portfolio
|
||||||
from atst.domain.csp import get_stage_csp_class
|
from atst.domain.csp import get_stage_csp_class
|
||||||
|
|
||||||
|
# TODO: Write failure case tests
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
def portfolio():
|
def portfolio():
|
||||||
@ -122,7 +124,7 @@ def test_fsm_transition_start(portfolio: Portfolio):
|
|||||||
"last_name": ppoc.last_name,
|
"last_name": ppoc.last_name,
|
||||||
"country_code": "US",
|
"country_code": "US",
|
||||||
"password_recovery_email_address": ppoc.email,
|
"password_recovery_email_address": ppoc.email,
|
||||||
"address": {
|
"address": { # TODO: TBD if we're sourcing this from data or config
|
||||||
"company_name": "",
|
"company_name": "",
|
||||||
"address_line_1": "",
|
"address_line_1": "",
|
||||||
"city": "",
|
"city": "",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user