Properly report initial clin information
Includes fixed up state machine test as well as adds some missing dependencies
This commit is contained in:
parent
81054b2ff0
commit
ea040a914e
1
Pipfile
1
Pipfile
@ -36,6 +36,7 @@ transitions = "*"
|
|||||||
azure-mgmt-consumption = "*"
|
azure-mgmt-consumption = "*"
|
||||||
adal = "*"
|
adal = "*"
|
||||||
azure-identity = "*"
|
azure-identity = "*"
|
||||||
|
azure-keyvault = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
bandit = "*"
|
bandit = "*"
|
||||||
|
82
Pipfile.lock
generated
82
Pipfile.lock
generated
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "3760f0b1df1156211d671afa2eb417b7bf980aa33d2f74d390e8eed6a3ce8c8b"
|
"sha256": "4dbb023bcb860eb6dc56e1c201c91f272e1e67ad03e5e5eeb3a7a7fdff350eed"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
@ -26,10 +26,10 @@
|
|||||||
},
|
},
|
||||||
"alembic": {
|
"alembic": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:3b0cb1948833e062f4048992fbc97ecfaaaac24aaa0d83a1202a99fb58af8c6d"
|
"sha256:d412982920653db6e5a44bfd13b1d0db5685cbaaccaf226195749c706e1e862a"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.3.2"
|
"version": "==1.3.3"
|
||||||
},
|
},
|
||||||
"amqp": {
|
"amqp": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -68,6 +68,28 @@
|
|||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.2.0"
|
"version": "==1.2.0"
|
||||||
},
|
},
|
||||||
|
"azure-keyvault": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:76f75cb83929f312a08616d426ad6f597f1beae180131cf445876fb88f2c8ef1",
|
||||||
|
"sha256:e85f5bd6cb4f10b3248b99bbf02e3acc6371d366846897027d4153f18025a2d7"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==4.0.0"
|
||||||
|
},
|
||||||
|
"azure-keyvault-keys": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2983fa42e20a0e6bf6b87976716129c108e613e0292d34c5b0f0c8dc1d488e89",
|
||||||
|
"sha256:38c27322637a2c52620a8b96da1942ad6a8d22d09b5a01f6fa257f7a51e52ed0"
|
||||||
|
],
|
||||||
|
"version": "==4.0.0"
|
||||||
|
},
|
||||||
|
"azure-keyvault-secrets": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2eae9264a8f6f59277e1a9bfdbc8b0a15969ee5a80d8efe403d7744805b4a481",
|
||||||
|
"sha256:97a602406a833e8f117c540c66059c818f4321a35168dd17365fab1e4527d718"
|
||||||
|
],
|
||||||
|
"version": "==4.0.0"
|
||||||
|
},
|
||||||
"azure-mgmt-authorization": {
|
"azure-mgmt-authorization": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:31e875a34ac2c5d6fefe77b4a8079a8b2bdbe9edb957e47e8b44222fb212d6a7",
|
"sha256:31e875a34ac2c5d6fefe77b4a8079a8b2bdbe9edb957e47e8b44222fb212d6a7",
|
||||||
@ -232,6 +254,14 @@
|
|||||||
],
|
],
|
||||||
"version": "==2.8"
|
"version": "==2.8"
|
||||||
},
|
},
|
||||||
|
"dataclasses": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3459118f7ede7c8bea0fe795bff7c6c2ce287d01dd226202f7c9ebc0610a7836",
|
||||||
|
"sha256:494a6dcae3b8bcf80848eea2ef64c0cc5cd307ffc263e17cdf42f3e5420808e6"
|
||||||
|
],
|
||||||
|
"markers": "python_version < '3.7'",
|
||||||
|
"version": "==0.7"
|
||||||
|
},
|
||||||
"flask": {
|
"flask": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52",
|
"sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52",
|
||||||
@ -325,9 +355,9 @@
|
|||||||
},
|
},
|
||||||
"mako": {
|
"mako": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:a36919599a9b7dc5d86a7a8988f23a9a3a3d083070023bab23d64f7f1d1e0a4b"
|
"sha256:2984a6733e1d472796ceef37ad48c26f4a984bb18119bb2dbc37a44d8f6e75a4"
|
||||||
],
|
],
|
||||||
"version": "==1.1.0"
|
"version": "==1.1.1"
|
||||||
},
|
},
|
||||||
"markupsafe": {
|
"markupsafe": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -584,10 +614,10 @@
|
|||||||
},
|
},
|
||||||
"sqlalchemy": {
|
"sqlalchemy": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:bfb8f464a5000b567ac1d350b9090cf081180ec1ab4aa87e7bca12dab25320ec"
|
"sha256:64a7b71846db6423807e96820993fa12a03b89127d278290ca25c0b11ed7b4fb"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.3.12"
|
"version": "==1.3.13"
|
||||||
},
|
},
|
||||||
"sqlalchemy-json": {
|
"sqlalchemy-json": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -620,10 +650,10 @@
|
|||||||
},
|
},
|
||||||
"urllib3": {
|
"urllib3": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293",
|
"sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc",
|
||||||
"sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745"
|
"sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"
|
||||||
],
|
],
|
||||||
"version": "==1.25.7"
|
"version": "==1.25.8"
|
||||||
},
|
},
|
||||||
"vine": {
|
"vine": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -657,10 +687,10 @@
|
|||||||
},
|
},
|
||||||
"zipp": {
|
"zipp": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:57147f6b0403b59f33fd357f169f860e031303415aeb7d04ede4839d23905ab8",
|
"sha256:b338014b9bc7102ca69e0fb96ed07215a8954d2989bc5d83658494ab2ba634af",
|
||||||
"sha256:7ae5ccaca427bafa9760ac3cd8f8c244bfc259794b5b6bb9db4dda2241575d09"
|
"sha256:e013e7800f60ec4dde789ebf4e9f7a54236e4bbf5df2a1a4e20ce9e1d9609d67"
|
||||||
],
|
],
|
||||||
"version": "==2.0.0"
|
"version": "==2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"develop": {
|
"develop": {
|
||||||
@ -671,6 +701,14 @@
|
|||||||
],
|
],
|
||||||
"version": "==1.4.3"
|
"version": "==1.4.3"
|
||||||
},
|
},
|
||||||
|
"appnope": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0",
|
||||||
|
"sha256:8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71"
|
||||||
|
],
|
||||||
|
"markers": "sys_platform == 'darwin'",
|
||||||
|
"version": "==0.1.0"
|
||||||
|
},
|
||||||
"argh": {
|
"argh": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3",
|
"sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3",
|
||||||
@ -1062,11 +1100,11 @@
|
|||||||
},
|
},
|
||||||
"pexpect": {
|
"pexpect": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:2094eefdfcf37a1fdbfb9aa090862c1a4878e5c7e0e7e7088bdb511c558e5cd1",
|
"sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937",
|
||||||
"sha256:9e2c1fd0e6ee3a49b28f95d4b33bc389c89b20af6a1255906e90ff1262ce62eb"
|
"sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"
|
||||||
],
|
],
|
||||||
"markers": "sys_platform != 'win32'",
|
"markers": "sys_platform != 'win32'",
|
||||||
"version": "==4.7.0"
|
"version": "==4.8.0"
|
||||||
},
|
},
|
||||||
"pickleshare": {
|
"pickleshare": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -1325,10 +1363,10 @@
|
|||||||
},
|
},
|
||||||
"urllib3": {
|
"urllib3": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293",
|
"sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc",
|
||||||
"sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745"
|
"sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"
|
||||||
],
|
],
|
||||||
"version": "==1.25.7"
|
"version": "==1.25.8"
|
||||||
},
|
},
|
||||||
"watchdog": {
|
"watchdog": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -1359,10 +1397,10 @@
|
|||||||
},
|
},
|
||||||
"zipp": {
|
"zipp": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:57147f6b0403b59f33fd357f169f860e031303415aeb7d04ede4839d23905ab8",
|
"sha256:b338014b9bc7102ca69e0fb96ed07215a8954d2989bc5d83658494ab2ba634af",
|
||||||
"sha256:7ae5ccaca427bafa9760ac3cd8f8c244bfc259794b5b6bb9db4dda2241575d09"
|
"sha256:e013e7800f60ec4dde789ebf4e9f7a54236e4bbf5df2a1a4e20ce9e1d9609d67"
|
||||||
],
|
],
|
||||||
"version": "==2.0.0"
|
"version": "==2.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,12 +327,12 @@ class TaskOrderBillingCreationCSPPayload(BaseCSPPayload):
|
|||||||
|
|
||||||
class TaskOrderBillingCreationCSPResult(AliasModel):
|
class TaskOrderBillingCreationCSPResult(AliasModel):
|
||||||
task_order_billing_verify_url: str
|
task_order_billing_verify_url: str
|
||||||
retry_after: int
|
task_order_retry_after: int
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
fields = {
|
fields = {
|
||||||
"task_order_billing_verify_url": "Location",
|
"task_order_billing_verify_url": "Location",
|
||||||
"retry_after": "Retry-After",
|
"task_order_retry_after": "Retry-After",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -358,11 +358,11 @@ class TaskOrderBillingVerificationCSPResult(AliasModel):
|
|||||||
|
|
||||||
|
|
||||||
class BillingInstructionCSPPayload(BaseCSPPayload):
|
class BillingInstructionCSPPayload(BaseCSPPayload):
|
||||||
amount: float
|
initial_clin_amount: float
|
||||||
start_date: str
|
initial_clin_start_date: str
|
||||||
end_date: str
|
initial_clin_end_date: str
|
||||||
clin_type: str
|
initial_clin_type: str
|
||||||
task_order_id: str
|
initial_task_order_id: str
|
||||||
billing_account_name: str
|
billing_account_name: str
|
||||||
billing_profile_name: str
|
billing_profile_name: str
|
||||||
|
|
||||||
@ -646,7 +646,8 @@ class MockCloudProvider(CloudProviderInterface):
|
|||||||
self._maybe_raise(self.SERVER_FAILURE_PCT, self.SERVER_EXCEPTION)
|
self._maybe_raise(self.SERVER_FAILURE_PCT, self.SERVER_EXCEPTION)
|
||||||
self._maybe_raise(self.UNAUTHORIZED_RATE, self.AUTHORIZATION_EXCEPTION)
|
self._maybe_raise(self.UNAUTHORIZED_RATE, self.AUTHORIZATION_EXCEPTION)
|
||||||
|
|
||||||
return {
|
return BillingProfileTenantAccessCSPResult(
|
||||||
|
**{
|
||||||
"id": "/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/billingProfiles/KQWI-W2SU-BG7-TGB/billingRoleAssignments/40000000-aaaa-bbbb-cccc-100000000000_0a5f4926-e3ee-4f47-a6e3-8b0a30a40e3d",
|
"id": "/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/billingProfiles/KQWI-W2SU-BG7-TGB/billingRoleAssignments/40000000-aaaa-bbbb-cccc-100000000000_0a5f4926-e3ee-4f47-a6e3-8b0a30a40e3d",
|
||||||
"name": "40000000-aaaa-bbbb-cccc-100000000000_0a5f4926-e3ee-4f47-a6e3-8b0a30a40e3d",
|
"name": "40000000-aaaa-bbbb-cccc-100000000000_0a5f4926-e3ee-4f47-a6e3-8b0a30a40e3d",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -659,6 +660,62 @@ class MockCloudProvider(CloudProviderInterface):
|
|||||||
},
|
},
|
||||||
"type": "Microsoft.Billing/billingRoleAssignments",
|
"type": "Microsoft.Billing/billingRoleAssignments",
|
||||||
}
|
}
|
||||||
|
).dict()
|
||||||
|
|
||||||
|
def create_task_order_billing_creation(self, payload: TaskOrderBillingCreationCSPPayload):
|
||||||
|
self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION)
|
||||||
|
self._maybe_raise(self.SERVER_FAILURE_PCT, self.SERVER_EXCEPTION)
|
||||||
|
self._maybe_raise(self.UNAUTHORIZED_RATE, self.AUTHORIZATION_EXCEPTION)
|
||||||
|
|
||||||
|
return TaskOrderBillingCreationCSPResult(**{"Location": "https://somelocation", "Retry-After": "10"}).dict()
|
||||||
|
|
||||||
|
def create_task_order_billing_verification(self, payload: TaskOrderBillingVerificationCSPPayload):
|
||||||
|
self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION)
|
||||||
|
self._maybe_raise(self.SERVER_FAILURE_PCT, self.SERVER_EXCEPTION)
|
||||||
|
self._maybe_raise(self.UNAUTHORIZED_RATE, self.AUTHORIZATION_EXCEPTION)
|
||||||
|
|
||||||
|
return TaskOrderBillingVerificationCSPResult(**{
|
||||||
|
"id": "/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/billingProfiles/XC36-GRNZ-BG7-TGB",
|
||||||
|
"name": "XC36-GRNZ-BG7-TGB",
|
||||||
|
"properties": {
|
||||||
|
"address": {
|
||||||
|
"addressLine1": "123 S Broad Street, Suite 2400",
|
||||||
|
"city": "Philadelphia",
|
||||||
|
"companyName": "Promptworks",
|
||||||
|
"country": "US",
|
||||||
|
"postalCode": "19109",
|
||||||
|
"region": "PA"
|
||||||
|
},
|
||||||
|
"currency": "USD",
|
||||||
|
"displayName": "First Portfolio Billing Profile",
|
||||||
|
"enabledAzurePlans": [
|
||||||
|
{
|
||||||
|
"productId": "DZH318Z0BPS6",
|
||||||
|
"skuId": "0001",
|
||||||
|
"skuDescription": "Microsoft Azure Plan"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hasReadAccess": True,
|
||||||
|
"invoiceDay": 5,
|
||||||
|
"invoiceEmailOptIn": False
|
||||||
|
},
|
||||||
|
"type": "Microsoft.Billing/billingAccounts/billingProfiles"
|
||||||
|
}).dict()
|
||||||
|
|
||||||
|
def create_billing_instruction(self, payload: BillingInstructionCSPPayload):
|
||||||
|
self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION)
|
||||||
|
self._maybe_raise(self.SERVER_FAILURE_PCT, self.SERVER_EXCEPTION)
|
||||||
|
self._maybe_raise(self.UNAUTHORIZED_RATE, self.AUTHORIZATION_EXCEPTION)
|
||||||
|
|
||||||
|
return BillingInstructionCSPResult(**{
|
||||||
|
"name": "TO1:CLIN001",
|
||||||
|
"properties": {
|
||||||
|
"amount": 1000.0,
|
||||||
|
"endDate": "2020-03-01T00:00:00+00:00",
|
||||||
|
"startDate": "2020-01-01T00:00:00+00:00"
|
||||||
|
},
|
||||||
|
"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)
|
||||||
@ -1150,13 +1207,13 @@ class AzureCloudProvider(CloudProviderInterface):
|
|||||||
|
|
||||||
request_body = {
|
request_body = {
|
||||||
"properties": {
|
"properties": {
|
||||||
"amount": payload.amount,
|
"amount": payload.initial_clin_amount,
|
||||||
"startDate": payload.start_date,
|
"startDate": payload.initial_clin_start_date,
|
||||||
"endDate": payload.end_date,
|
"endDate": payload.initial_clin_end_date,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
url = f"https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{payload.billing_account_name}/billingProfiles/{payload.billing_profile_name}/instructions/{payload.task_order_id}:CLIN00{payload.clin_type}?api-version=2019-10-01-preview"
|
url = f"https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{payload.billing_account_name}/billingProfiles/{payload.billing_profile_name}/instructions/{payload.initial_task_order_id}:CLIN00{payload.initial_clin_type}?api-version=2019-10-01-preview"
|
||||||
|
|
||||||
auth_header = {
|
auth_header = {
|
||||||
"Authorization": f"Bearer {sp_token}",
|
"Authorization": f"Bearer {sp_token}",
|
||||||
|
@ -67,7 +67,6 @@ class PortfolioStateMachine(
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<PortfolioStateMachine(state='{self.current_state.name}', portfolio='{self.portfolio.name}'"
|
return f"<PortfolioStateMachine(state='{self.current_state.name}', portfolio='{self.portfolio.name}'"
|
||||||
|
|
||||||
|
|
||||||
@reconstructor
|
@reconstructor
|
||||||
def attach_machine(self):
|
def attach_machine(self):
|
||||||
"""
|
"""
|
||||||
@ -112,7 +111,9 @@ class PortfolioStateMachine(
|
|||||||
if create_trigger:
|
if create_trigger:
|
||||||
self.trigger(create_trigger, **kwargs)
|
self.trigger(create_trigger, **kwargs)
|
||||||
else:
|
else:
|
||||||
app.logger.info(f"could not locate 'create trigger' for {self.__repr__()}")
|
app.logger.info(
|
||||||
|
f"could not locate 'create trigger' for {self.__repr__()}"
|
||||||
|
)
|
||||||
self.fail_stage(stage)
|
self.fail_stage(stage)
|
||||||
|
|
||||||
elif state_obj.is_CREATED:
|
elif state_obj.is_CREATED:
|
||||||
@ -143,8 +144,11 @@ class PortfolioStateMachine(
|
|||||||
try:
|
try:
|
||||||
payload_data = payload_data_cls(**payload)
|
payload_data = payload_data_cls(**payload)
|
||||||
except PydanticValidationError as exc:
|
except PydanticValidationError as exc:
|
||||||
app.logger.error(f"Payload Validation Error in {self.__repr__()}:", exc_info=1)
|
app.logger.error(
|
||||||
|
f"Payload Validation Error in {self.__repr__()}:", exc_info=1
|
||||||
|
)
|
||||||
app.logger.info(exc.json())
|
app.logger.info(exc.json())
|
||||||
|
print(exc.json())
|
||||||
app.logger.info(payload)
|
app.logger.info(payload)
|
||||||
self.fail_stage(stage)
|
self.fail_stage(stage)
|
||||||
|
|
||||||
@ -161,7 +165,10 @@ class PortfolioStateMachine(
|
|||||||
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:
|
except (ConnectionException, UnknownServerException) as exc:
|
||||||
app.logger.error(f"CSP api call. Caught exception for {self.__repr__()}. Retry attempt {attempt}", exc_info=1)
|
app.logger.error(
|
||||||
|
f"CSP api call. Caught exception for {self.__repr__()}. Retry attempt {attempt}",
|
||||||
|
exc_info=1,
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
@ -198,12 +205,16 @@ class PortfolioStateMachine(
|
|||||||
dc = cls(**stage_data)
|
dc = cls(**stage_data)
|
||||||
if getattr(dc, "get_creds", None) is not None:
|
if getattr(dc, "get_creds", None) is not None:
|
||||||
new_creds = dc.get_creds()
|
new_creds = dc.get_creds()
|
||||||
|
print("creds to report")
|
||||||
|
print(new_creds)
|
||||||
# TODO: how/where to store these
|
# TODO: how/where to store these
|
||||||
# TODO: credential schema
|
# TODO: credential schema
|
||||||
# self.store_creds(self.portfolio, new_creds)
|
# self.store_creds(self.portfolio, new_creds)
|
||||||
|
|
||||||
except PydanticValidationError as exc:
|
except PydanticValidationError as exc:
|
||||||
app.logger.error(f"Payload Validation Error in {self.__repr__()}:", exc_info=1)
|
app.logger.error(
|
||||||
|
f"Payload Validation Error in {self.__repr__()}:", exc_info=1
|
||||||
|
)
|
||||||
app.logger.info(exc.json())
|
app.logger.info(exc.json())
|
||||||
app.logger.info(payload)
|
app.logger.info(payload)
|
||||||
|
|
||||||
|
@ -404,11 +404,11 @@ def test_create_billing_instruction(mock_azure: AzureCloudProvider):
|
|||||||
payload = BillingInstructionCSPPayload(
|
payload = BillingInstructionCSPPayload(
|
||||||
**dict(
|
**dict(
|
||||||
creds=creds,
|
creds=creds,
|
||||||
amount=1000.00,
|
initial_clin_amount=1000.00,
|
||||||
start_date="2020/1/1",
|
initial_clin_start_date="2020/1/1",
|
||||||
end_date="2020/3/1",
|
initial_clin_end_date="2020/3/1",
|
||||||
clin_type="1",
|
initial_clin_type="1",
|
||||||
task_order_id="TO1",
|
initial_task_order_id="TO1",
|
||||||
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",
|
||||||
)
|
)
|
||||||
|
@ -4,16 +4,19 @@ import re
|
|||||||
from tests.factories import (
|
from tests.factories import (
|
||||||
PortfolioFactory,
|
PortfolioFactory,
|
||||||
PortfolioStateMachineFactory,
|
PortfolioStateMachineFactory,
|
||||||
|
TaskOrderFactory,
|
||||||
|
CLINFactory,
|
||||||
)
|
)
|
||||||
|
|
||||||
from atst.models import FSMStates, PortfolioStateMachine
|
from atst.models import FSMStates, PortfolioStateMachine, TaskOrder
|
||||||
from atst.models.mixins.state_machines import AzureStages, StageStates, compose_state
|
from atst.models.mixins.state_machines import AzureStages, StageStates, compose_state
|
||||||
|
from atst.models.portfolio import Portfolio
|
||||||
from atst.domain.csp import get_stage_csp_class
|
from atst.domain.csp import get_stage_csp_class
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
def portfolio():
|
def portfolio():
|
||||||
portfolio = PortfolioFactory.create()
|
portfolio = CLINFactory.create().task_order.portfolio
|
||||||
return portfolio
|
return portfolio
|
||||||
|
|
||||||
|
|
||||||
@ -77,7 +80,7 @@ def test_state_machine_initialization(portfolio):
|
|||||||
assert ["reset", "fail", create_trigger] == started_triggers
|
assert ["reset", "fail", create_trigger] == started_triggers
|
||||||
|
|
||||||
|
|
||||||
def test_fsm_transition_start(portfolio):
|
def test_fsm_transition_start(portfolio: Portfolio):
|
||||||
sm: PortfolioStateMachine = PortfolioStateMachineFactory.create(portfolio=portfolio)
|
sm: PortfolioStateMachine = PortfolioStateMachineFactory.create(portfolio=portfolio)
|
||||||
assert sm.portfolio
|
assert sm.portfolio
|
||||||
assert sm.state == FSMStates.UNSTARTED
|
assert sm.state == FSMStates.UNSTARTED
|
||||||
@ -88,6 +91,16 @@ def test_fsm_transition_start(portfolio):
|
|||||||
sm.start()
|
sm.start()
|
||||||
assert sm.state == FSMStates.STARTED
|
assert sm.state == FSMStates.STARTED
|
||||||
|
|
||||||
|
expected_states = [
|
||||||
|
FSMStates.TENANT_CREATED,
|
||||||
|
FSMStates.BILLING_PROFILE_CREATION_CREATED,
|
||||||
|
FSMStates.BILLING_PROFILE_VERIFICATION_CREATED,
|
||||||
|
FSMStates.BILLING_PROFILE_TENANT_ACCESS_CREATED,
|
||||||
|
FSMStates.TASK_ORDER_BILLING_CREATION_CREATED,
|
||||||
|
FSMStates.TASK_ORDER_BILLING_VERIFICATION_CREATED,
|
||||||
|
FSMStates.BILLING_INSTRUCTION_CREATED,
|
||||||
|
]
|
||||||
|
|
||||||
# Should source all creds for portfolio? might be easier to manage than per-step specific ones
|
# Should source all creds for portfolio? might be easier to manage than per-step specific ones
|
||||||
creds = {"username": "mock-cloud", "password": "shh"}
|
creds = {"username": "mock-cloud", "password": "shh"}
|
||||||
if portfolio.csp_data is not None:
|
if portfolio.csp_data is not None:
|
||||||
@ -95,19 +108,21 @@ def test_fsm_transition_start(portfolio):
|
|||||||
else:
|
else:
|
||||||
csp_data = {}
|
csp_data = {}
|
||||||
|
|
||||||
# ppoc = portfolio.owner
|
ppoc = portfolio.owner
|
||||||
# user_id = f"{ppoc.first_name[0]}{ppoc.last_name}".lower()
|
user_id = f"{ppoc.first_name[0]}{ppoc.last_name}".lower()
|
||||||
user_id = "abcdefg"
|
|
||||||
domain_name = re.sub("[^0-9a-zA-Z]+", "", portfolio.name).lower()
|
domain_name = re.sub("[^0-9a-zA-Z]+", "", portfolio.name).lower()
|
||||||
|
|
||||||
|
initial_task_order: TaskOrder = portfolio.task_orders[0]
|
||||||
|
initial_clin = initial_task_order.sorted_clins[0]
|
||||||
|
|
||||||
portfolio_data = {
|
portfolio_data = {
|
||||||
"user_id": user_id,
|
"user_id": user_id,
|
||||||
"password": "jklfsdNCVD83nklds2#202",
|
"password": "jklfsdNCVD83nklds2#202",
|
||||||
"domain_name": domain_name,
|
"domain_name": domain_name,
|
||||||
"first_name": "john", # ppoc.first_name,
|
"first_name": ppoc.first_name,
|
||||||
"last_name": "doe", # ppoc.last_name,
|
"last_name": ppoc.last_name,
|
||||||
"country_code": "US",
|
"country_code": "US",
|
||||||
"password_recovery_email_address": "email@example.com", # ppoc.email,
|
"password_recovery_email_address": ppoc.email,
|
||||||
"address": {
|
"address": {
|
||||||
"company_name": "",
|
"company_name": "",
|
||||||
"address_line_1": "",
|
"address_line_1": "",
|
||||||
@ -117,26 +132,24 @@ def test_fsm_transition_start(portfolio):
|
|||||||
"postal_code": "",
|
"postal_code": "",
|
||||||
},
|
},
|
||||||
"billing_profile_display_name": "My Billing Profile",
|
"billing_profile_display_name": "My Billing Profile",
|
||||||
|
"initial_clin_amount": initial_clin.obligated_amount,
|
||||||
|
"initial_clin_start_date": initial_clin.start_date.strftime("%Y/%m/%d"),
|
||||||
|
"initial_clin_end_date": initial_clin.end_date.strftime("%Y/%m/%d"),
|
||||||
|
"initial_clin_type": initial_clin.number,
|
||||||
|
"initial_task_order_id": initial_task_order.number,
|
||||||
}
|
}
|
||||||
|
|
||||||
config = {"billing_account_name": "billing_account_name"}
|
config = {"billing_account_name": "billing_account_name"}
|
||||||
|
|
||||||
|
for expected_state in expected_states:
|
||||||
|
print(expected_state)
|
||||||
collected_data = dict(
|
collected_data = dict(
|
||||||
list(csp_data.items()) + list(portfolio_data.items()) + list(config.items())
|
list(csp_data.items()) + list(portfolio_data.items()) + list(config.items())
|
||||||
)
|
)
|
||||||
sm.trigger_next_transition(creds=creds, csp_data=collected_data)
|
sm.trigger_next_transition(creds=creds, csp_data=collected_data)
|
||||||
|
assert sm.state == expected_state
|
||||||
assert sm.state == FSMStates.TENANT_CREATED
|
|
||||||
assert portfolio.csp_data.get("tenant_id", None) is not None
|
|
||||||
#print(portfolio.csp_data.keys())
|
|
||||||
if portfolio.csp_data is not None:
|
if portfolio.csp_data is not None:
|
||||||
csp_data = portfolio.csp_data
|
csp_data = portfolio.csp_data
|
||||||
else:
|
else:
|
||||||
csp_data = {}
|
csp_data = {}
|
||||||
collected_data = dict(
|
|
||||||
list(csp_data.items()) + list(portfolio_data.items()) + list(config.items())
|
|
||||||
)
|
|
||||||
sm.trigger_next_transition(creds=creds, csp_data=collected_data)
|
|
||||||
assert sm.state == FSMStates.BILLING_PROFILE_CREATION_CREATED
|
|
||||||
|
|
||||||
#print(portfolio.csp_data.keys())
|
|
||||||
|
@ -66,6 +66,12 @@ def mock_requests():
|
|||||||
return Mock(spec=requests)
|
return Mock(spec=requests)
|
||||||
|
|
||||||
|
|
||||||
|
def mock_secrets():
|
||||||
|
from azure.keyvault import secrets
|
||||||
|
|
||||||
|
return Mock(spec=secrets)
|
||||||
|
|
||||||
|
|
||||||
class MockAzureSDK(object):
|
class MockAzureSDK(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
from msrestazure.azure_cloud import AZURE_PUBLIC_CLOUD
|
from msrestazure.azure_cloud import AZURE_PUBLIC_CLOUD
|
||||||
@ -78,6 +84,7 @@ class MockAzureSDK(object):
|
|||||||
self.graphrbac = mock_graphrbac()
|
self.graphrbac = mock_graphrbac()
|
||||||
self.credentials = mock_credentials()
|
self.credentials = mock_credentials()
|
||||||
self.policy = mock_policy()
|
self.policy = mock_policy()
|
||||||
|
self.secrets = mock_secrets()
|
||||||
self.requests = mock_requests()
|
self.requests = mock_requests()
|
||||||
# may change to a JEDI cloud
|
# may change to a JEDI cloud
|
||||||
self.cloud = AZURE_PUBLIC_CLOUD
|
self.cloud = AZURE_PUBLIC_CLOUD
|
||||||
|
Loading…
x
Reference in New Issue
Block a user