diff --git a/Pipfile b/Pipfile index 810da811..8e5dc976 100644 --- a/Pipfile +++ b/Pipfile @@ -54,6 +54,7 @@ selenium = "*" honcho = "*" blinker = "*" pytest-mock = "*" +requests-mock = "*" detect-secrets = "*" beautifulsoup4 = "*" mypy = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 391f766d..d6032259 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "44296f145fcb42cff5fadf14a706ec9598f4436ccbdf05e1d69fcd8316c89e8d" + "sha256": "dcc985866bfecd1e2abcd40722a657f0da223c3c9c11aee32fd4b532eca31cb8" }, "pipfile-spec": 6, "requires": { @@ -26,10 +26,10 @@ }, "alembic": { "hashes": [ - "sha256:d412982920653db6e5a44bfd13b1d0db5685cbaaccaf226195749c706e1e862a" + "sha256:2df2519a5b002f881517693b95626905a39c5faf4b5a1f94de4f1441095d1d26" ], "index": "pypi", - "version": "==1.3.3" + "version": "==1.4.0" }, "amqp": { "hashes": [ @@ -47,10 +47,10 @@ }, "azure-core": { "hashes": [ - "sha256:b8ccbd901d085048e4e3e72627b066923c5bd3780e4c43cf9cf9948aee9bdf9e", - "sha256:e2cd99f0c0aef12c168d498cb5bc47a3a45c8ab08112183e3ec97e4dcb33ceb9" + "sha256:8bdb12b8e937c5bdf495faadf7741ea1958436e2d24c9c5ca7bd7a5ca7a9e42f", + "sha256:bcfc4502c4cfbdcbe82301119439f52542fa4a42dfc1dadd647bba8b01819823" ], - "version": "==1.2.1" + "version": "==1.2.2" }, "azure-graphrbac": { "hashes": [ @@ -116,11 +116,11 @@ }, "azure-mgmt-resource": { "hashes": [ - "sha256:455a10bbae15673c7879d7515b38e1548cb1a8982dd35029ab3192565262c573", - "sha256:c2ad10cab63999c0a88ee498bc36200ee7f6e6e5d4bf82712bde882eda11146f" + "sha256:a77707bad5551bd558da450045cd2f7097fb8cbaf68610a510a9e413f8a9cf3e", + "sha256:d90b7d8f237b71b54cfd06480dc1ecd7dac81b22301bf2f4ead98a53cf269b6a" ], "index": "pypi", - "version": "==8.0.0" + "version": "==8.0.1" }, "azure-mgmt-subscription": { "hashes": [ @@ -186,41 +186,36 @@ }, "cffi": { "hashes": [ - "sha256:0b49274afc941c626b605fb59b59c3485c17dc776dc3cc7cc14aca74cc19cc42", - "sha256:0e3ea92942cb1168e38c05c1d56b0527ce31f1a370f6117f1d490b8dcd6b3a04", - "sha256:135f69aecbf4517d5b3d6429207b2dff49c876be724ac0c8bf8e1ea99df3d7e5", - "sha256:19db0cdd6e516f13329cba4903368bff9bb5a9331d3410b1b448daaadc495e54", - "sha256:2781e9ad0e9d47173c0093321bb5435a9dfae0ed6a762aabafa13108f5f7b2ba", - "sha256:291f7c42e21d72144bb1c1b2e825ec60f46d0a7468f5346841860454c7aa8f57", - "sha256:2c5e309ec482556397cb21ede0350c5e82f0eb2621de04b2633588d118da4396", - "sha256:2e9c80a8c3344a92cb04661115898a9129c074f7ab82011ef4b612f645939f12", - "sha256:32a262e2b90ffcfdd97c7a5e24a6012a43c61f1f5a57789ad80af1d26c6acd97", - "sha256:3c9fff570f13480b201e9ab69453108f6d98244a7f495e91b6c654a47486ba43", - "sha256:415bdc7ca8c1c634a6d7163d43fb0ea885a07e9618a64bda407e04b04333b7db", - "sha256:42194f54c11abc8583417a7cf4eaff544ce0de8187abaf5d29029c91b1725ad3", - "sha256:4424e42199e86b21fc4db83bd76909a6fc2a2aefb352cb5414833c030f6ed71b", - "sha256:4a43c91840bda5f55249413037b7a9b79c90b1184ed504883b72c4df70778579", - "sha256:599a1e8ff057ac530c9ad1778293c665cb81a791421f46922d80a86473c13346", - "sha256:5c4fae4e9cdd18c82ba3a134be256e98dc0596af1e7285a3d2602c97dcfa5159", - "sha256:5ecfa867dea6fabe2a58f03ac9186ea64da1386af2159196da51c4904e11d652", - "sha256:62f2578358d3a92e4ab2d830cd1c2049c9c0d0e6d3c58322993cc341bdeac22e", - "sha256:6471a82d5abea994e38d2c2abc77164b4f7fbaaf80261cb98394d5793f11b12a", - "sha256:6d4f18483d040e18546108eb13b1dfa1000a089bcf8529e30346116ea6240506", - "sha256:71a608532ab3bd26223c8d841dde43f3516aa5d2bf37b50ac410bb5e99053e8f", - "sha256:74a1d8c85fb6ff0b30fbfa8ad0ac23cd601a138f7509dc617ebc65ef305bb98d", - "sha256:7b93a885bb13073afb0aa73ad82059a4c41f4b7d8eb8368980448b52d4c7dc2c", - "sha256:7d4751da932caaec419d514eaa4215eaf14b612cff66398dd51129ac22680b20", - "sha256:7f627141a26b551bdebbc4855c1157feeef18241b4b8366ed22a5c7d672ef858", - "sha256:8169cf44dd8f9071b2b9248c35fc35e8677451c52f795daa2bb4643f32a540bc", - "sha256:aa00d66c0fab27373ae44ae26a66a9e43ff2a678bf63a9c7c1a9a4d61172827a", - "sha256:ccb032fda0873254380aa2bfad2582aedc2959186cce61e3a17abc1a55ff89c3", - "sha256:d754f39e0d1603b5b24a7f8484b22d2904fa551fe865fd0d4c3332f078d20d4e", - "sha256:d75c461e20e29afc0aee7172a0950157c704ff0dd51613506bd7d82b718e7410", - "sha256:dcd65317dd15bc0451f3e01c80da2216a31916bdcffd6221ca1202d96584aa25", - "sha256:e570d3ab32e2c2861c4ebe6ffcad6a8abf9347432a37608fe1fbd157b3f0036b", - "sha256:fd43a88e045cf992ed09fa724b5315b790525f2676883a6ea64e3263bae6549d" + "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff", + "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b", + "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac", + "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0", + "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384", + "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26", + "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6", + "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b", + "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e", + "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd", + "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2", + "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66", + "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc", + "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8", + "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55", + "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4", + "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5", + "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d", + "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78", + "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa", + "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793", + "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f", + "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a", + "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f", + "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30", + "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f", + "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3", + "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c" ], - "version": "==1.13.2" + "version": "==1.14.0" }, "chardet": { "hashes": [ @@ -296,11 +291,11 @@ }, "flask-wtf": { "hashes": [ - "sha256:5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36", - "sha256:d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac" + "sha256:57b3faf6fe5d6168bda0c36b0df1d05770f8e205e18332d0376ddb954d17aef2", + "sha256:d417e3a0008b5ba583da1763e4db0f55a1269d9dd91dcc3eb3c026d3c5dbd720" ], "index": "pypi", - "version": "==0.14.2" + "version": "==0.14.3" }, "idna": { "hashes": [ @@ -333,10 +328,10 @@ }, "jinja2": { "hashes": [ - "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250", - "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49" + "sha256:c10142f819c2d22bdcd17548c46fa9b77cf4fda45097854c689666bf425e7484", + "sha256:c922560ac46888d47384de1dbdc3daaa2ea993af4b26a436dec31fa2c19ec668" ], - "version": "==2.11.1" + "version": "==3.0.0a1" }, "kombu": { "hashes": [ @@ -685,10 +680,10 @@ }, "zipp": { "hashes": [ - "sha256:ccc94ed0909b58ffe34430ea5451f07bc0c76467d7081619a454bf5c98b89e28", - "sha256:feae2f18633c32fc71f2de629bfb3bd3c9325cd4419642b1f1da42ee488d9b98" + "sha256:5c56e330306215cd3553342cfafc73dda2c60792384117893f3a83f8a1209f50", + "sha256:d65287feb793213ffe11c0f31b81602be31448f38aeb8ffc2eb286c4f6f6657e" ], - "version": "==2.1.0" + "version": "==2.2.0" } }, "develop": { @@ -699,14 +694,6 @@ ], "version": "==1.4.3" }, - "appnope": { - "hashes": [ - "sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0", - "sha256:8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71" - ], - "markers": "sys_platform == 'darwin'", - "version": "==0.1.0" - }, "astroid": { "hashes": [ "sha256:71ea07f44df9568a75d0f354c49143a4575d90645e9fead6dfb52c26a85ed13a", @@ -871,10 +858,10 @@ }, "gitpython": { "hashes": [ - "sha256:9c2398ffc3dcb3c40b27324b316f08a4f93ad646d5a6328cafbb871aa79f5e42", - "sha256:c155c6a2653593ccb300462f6ef533583a913e17857cfef8fc617c246b6dc245" + "sha256:99c77677f31f255e130f3fed4c8e0eebb35f1a09df98ff965fff6774f71688cf", + "sha256:99cd0403cecd8a13b95d2e045b9fcaa7837137fcc5ec3105f2c413305d82c143" ], - "version": "==3.0.5" + "version": "==3.0.7" }, "honcho": { "hashes": [ @@ -944,10 +931,10 @@ }, "jinja2": { "hashes": [ - "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250", - "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49" + "sha256:c10142f819c2d22bdcd17548c46fa9b77cf4fda45097854c689666bf425e7484", + "sha256:c922560ac46888d47384de1dbdc3daaa2ea993af4b26a436dec31fa2c19ec668" ], - "version": "==2.11.1" + "version": "==3.0.0a1" }, "lazy-object-proxy": { "hashes": [ @@ -1056,10 +1043,10 @@ }, "parso": { "hashes": [ - "sha256:1376bdc8cb81377ca481976933773295218a2df47d3e1182ba76d372b1acb128", - "sha256:597f36de5102a8db05ffdf7ecdc761838b86565a4a111604c6e78beaedf1b045" + "sha256:56b2105a80e9c4df49de85e125feb6be69f49920e121406f15e7acde6c9dfc57", + "sha256:951af01f61e6dccd04159042a0706a31ad437864ec6e25d0d7a96a9fbb9b0095" ], - "version": "==0.6.0" + "version": "==0.6.1" }, "pathspec": { "hashes": [ @@ -1158,11 +1145,11 @@ }, "pytest-flask": { "hashes": [ - "sha256:283730b469604ecb94caac28df99a40b7c785b828dd8d3323596718b51dfaeb2", - "sha256:d874781b622210d8c5d8061cdb091cb059fcb12203125110bd8e6f9256ccbf49" + "sha256:9001f6128c5c4a0d243ce46c117f3691052828d2faf39ac151b8388657dce447", + "sha256:cbd8c5b9f8f1b83e9c159ac4294964807c4934317a5fba181739ac15e1b823e6" ], "index": "pypi", - "version": "==0.15.0" + "version": "==0.15.1" }, "pytest-mock": { "hashes": [ @@ -1230,6 +1217,14 @@ "index": "pypi", "version": "==2.22.0" }, + "requests-mock": { + "hashes": [ + "sha256:510df890afe08d36eca5bb16b4aa6308a6f85e3159ad3013bac8b9de7bd5a010", + "sha256:88d3402dd8b3c69a9e4f9d3a73ad11b15920c6efd36bc27bf1f701cf4a8e4646" + ], + "index": "pypi", + "version": "==1.7.0" + }, "rope": { "hashes": [ "sha256:52423a7eebb5306a6d63bdc91a7c657db51ac9babfb8341c9a1440831ecf3203", @@ -1270,10 +1265,10 @@ }, "stevedore": { "hashes": [ - "sha256:01d9f4beecf0fbd070ddb18e5efb10567801ba7ef3ddab0074f54e3cd4e91730", - "sha256:e0739f9739a681c7a1fda76a102b65295e96a144ccdb552f2ae03c5f0abe8a14" + "sha256:18afaf1d623af5950cc0f7e75e70f917784c73b652a34a12d90b309451b5500b", + "sha256:a4e7dc759fb0f2e3e2f7d8ffe2358c19d45b9b8297f393ef1256858d82f69c9b" ], - "version": "==1.31.0" + "version": "==1.32.0" }, "text-unidecode": { "hashes": [ @@ -1361,10 +1356,10 @@ }, "zipp": { "hashes": [ - "sha256:ccc94ed0909b58ffe34430ea5451f07bc0c76467d7081619a454bf5c98b89e28", - "sha256:feae2f18633c32fc71f2de629bfb3bd3c9325cd4419642b1f1da42ee488d9b98" + "sha256:5c56e330306215cd3553342cfafc73dda2c60792384117893f3a83f8a1209f50", + "sha256:d65287feb793213ffe11c0f31b81602be31448f38aeb8ffc2eb286c4f6f6657e" ], - "version": "==2.1.0" + "version": "==2.2.0" } } } diff --git a/atst/domain/csp/cloud/azure_cloud_provider.py b/atst/domain/csp/cloud/azure_cloud_provider.py index 9328d704..aa5022e9 100644 --- a/atst/domain/csp/cloud/azure_cloud_provider.py +++ b/atst/domain/csp/cloud/azure_cloud_provider.py @@ -2,6 +2,7 @@ import json from secrets import token_urlsafe from typing import Any, Dict from uuid import uuid4 +import pydantic from atst.utils import sha256_hex @@ -274,31 +275,17 @@ class AzureCloudProvider(CloudProviderInterface): try: result = self.sdk.requests.post( - f"{self.sdk.cloud.endpoints.resource_manager}/providers/Microsoft.SignUp/createTenant?api-version=2020-01-01-preview", + f"{self.sdk.cloud.endpoints.resource_manager}providers/Microsoft.SignUp/createTenant?api-version=2020-01-01-preview", json=create_tenant_body, headers=create_tenant_headers, timeout=30, ) result.raise_for_status() - result_dict = result.json() - tenant_id = result_dict.get("tenantId") - tenant_admin_username = ( - f"{payload.user_id}@{payload.domain_name}.onmicrosoft.com" - ) - self.update_tenant_creds( - tenant_id, - KeyVaultCredentials( - tenant_id=tenant_id, - tenant_admin_username=tenant_admin_username, - tenant_admin_password=payload.password, - ), - ) - return TenantCSPResult(domain_name=payload.domain_name, **result_dict) except self.sdk.requests.ConnectionError: - app.logger.error( - f"Could not create tenant. Connection Error", exc_info=1, - ) + #app.logger.error( + # f"Could not create tenant. Connection Error", exc_info=1, + #) raise ConnectionException("connection error creating tenant") except self.sdk.requests.Timeout: app.logger.error( @@ -308,6 +295,27 @@ class AzureCloudProvider(CloudProviderInterface): except self.sdk.requests.HTTPError: raise UnknownServerException("azure application error creating tenant") + result_dict = result.json() + tenant_id = result_dict.get("tenantId") + tenant_admin_username = ( + f"{payload.user_id}@{payload.domain_name}.onmicrosoft.com" + ) + try: + creds = KeyVaultCredentials( + tenant_id=tenant_id, + tenant_admin_username=tenant_admin_username, + tenant_admin_password=payload.password, + ) + except pydantic.ValidationError as val_exc: + return + + self.update_tenant_creds( + tenant_id, + creds, + ) + return TenantCSPResult(domain_name=payload.domain_name, **result_dict) + + def create_billing_profile_creation( self, payload: BillingProfileCreationCSPPayload ): @@ -330,6 +338,7 @@ class AzureCloudProvider(CloudProviderInterface): billing_account_create_url, json=create_billing_account_body, headers=create_billing_account_headers, + timeout=30, ) result.raise_for_status() if result.status_code == 202: @@ -366,7 +375,9 @@ class AzureCloudProvider(CloudProviderInterface): } try: result = self.sdk.requests.get( - payload.billing_profile_verify_url, headers=auth_header + payload.billing_profile_verify_url, + headers=auth_header, + timeout=30, ) result.raise_for_status() @@ -407,7 +418,12 @@ class AzureCloudProvider(CloudProviderInterface): url = f"{self.sdk.cloud.endpoints.resource_manager}/providers/Microsoft.Billing/billingAccounts/{payload.billing_account_name}/billingProfiles/{payload.billing_profile_name}/createBillingRoleAssignment?api-version=2019-10-01-preview" try: - result = self.sdk.requests.post(url, headers=headers, json=request_body) + result = self.sdk.requests.post( + url, + headers=headers, + json=request_body, + timeout=30, + ) if result.status_code == 201: return BillingProfileTenantAccessCSPResult(**result.json()) @@ -444,7 +460,7 @@ class AzureCloudProvider(CloudProviderInterface): try: result = self.sdk.requests.patch( - url, headers=request_headers, json=request_body + url, headers=request_headers, json=request_body, timeout=30, ) result.raise_for_status() @@ -482,7 +498,7 @@ class AzureCloudProvider(CloudProviderInterface): try: result = self.sdk.requests.get( - payload.task_order_billing_verify_url, headers=auth_header + payload.task_order_billing_verify_url, headers=auth_header, timeout=30, ) result.raise_for_status() @@ -527,7 +543,7 @@ class AzureCloudProvider(CloudProviderInterface): } try: - result = self.sdk.requests.put(url, headers=auth_header, json=request_body) + result = self.sdk.requests.put(url, headers=auth_header, json=request_body, timeout=30) result.raise_for_status() return BillingInstructionCSPResult(**result.json()) @@ -564,7 +580,7 @@ class AzureCloudProvider(CloudProviderInterface): } try: - result = self.sdk.requests.put(url, headers=auth_header, json=request_body) + result = self.sdk.requests.put(url, headers=auth_header, json=request_body, timeout=30) if result.status_code in [200, 202]: # 202 has location/retry after headers return SubscriptionCreationCSPResult(**result.headers, **result.json()) @@ -600,7 +616,7 @@ class AzureCloudProvider(CloudProviderInterface): try: result = self.sdk.requests.get( - payload.subscription_verify_url, headers=auth_header + payload.subscription_verify_url, headers=auth_header, timeout=30 ) result.raise_for_status() @@ -643,6 +659,7 @@ class AzureCloudProvider(CloudProviderInterface): product_purchase_url, json=create_product_purchase_body, headers=create_product_purchase_headers, + timeout=30, ) result.raise_for_status() @@ -680,7 +697,7 @@ class AzureCloudProvider(CloudProviderInterface): } try: result = self.sdk.requests.get( - payload.product_purchase_verify_url, headers=auth_header + payload.product_purchase_verify_url, headers=auth_header, timeout=30 ) result.raise_for_status() @@ -728,7 +745,7 @@ class AzureCloudProvider(CloudProviderInterface): try: response = self.sdk.requests.put( - url, headers=auth_header, json=request_body + url, headers=auth_header, json=request_body, timeout=30 ) response.raise_for_status() @@ -772,7 +789,7 @@ class AzureCloudProvider(CloudProviderInterface): try: response = self.sdk.requests.put( - url, headers=auth_header, json=request_body + url, headers=auth_header, json=request_body, timeout=30, ) response.raise_for_status() return TenantPrincipalOwnershipCSPResult(**response.json()) @@ -809,7 +826,7 @@ class AzureCloudProvider(CloudProviderInterface): try: response = self.sdk.requests.post( - url, json=request_body, headers=auth_header + url, json=request_body, headers=auth_header, timeout=30 ) response.raise_for_status() return TenantPrincipalAppCSPResult(**response.json()) @@ -846,7 +863,7 @@ class AzureCloudProvider(CloudProviderInterface): try: response = self.sdk.requests.post( - url, json=request_body, headers=auth_header + url, json=request_body, headers=auth_header, timeout=30 ) response.raise_for_status() return TenantPrincipalCSPResult(**response.json()) @@ -887,7 +904,7 @@ class AzureCloudProvider(CloudProviderInterface): try: response = self.sdk.requests.post( - url, json=request_body, headers=auth_header + url, json=request_body, headers=auth_header, timeout=30 ) response.raise_for_status() result = response.json() @@ -932,7 +949,7 @@ class AzureCloudProvider(CloudProviderInterface): url = f"{self.graph_resource}/beta/roleManagement/directory/roleDefinitions" try: - response = self.sdk.requests.get(url, headers=auth_header) + response = self.sdk.requests.get(url, headers=auth_header, timeout=30) response.raise_for_status() result = response.json() @@ -986,7 +1003,7 @@ class AzureCloudProvider(CloudProviderInterface): try: response = self.sdk.requests.post( - url, headers=auth_header, json=request_body + url, headers=auth_header, json=request_body, timeout=30 ) response.raise_for_status() return PrincipalAdminRoleCSPResult(**response.json()) @@ -1104,7 +1121,7 @@ class AzureCloudProvider(CloudProviderInterface): try: response = self.sdk.requests.post( - url, headers=auth_header, json=request_body + url, headers=auth_header, json=request_body, timeout=30 ) response.raise_for_status() @@ -1138,7 +1155,7 @@ class AzureCloudProvider(CloudProviderInterface): try: response = self.sdk.requests.patch( - url, headers=auth_header, json=request_body + url, headers=auth_header, json=request_body, timeout=30 ) response.raise_for_status() @@ -1257,7 +1274,7 @@ class AzureCloudProvider(CloudProviderInterface): } url = f"{self.sdk.cloud.endpoints.resource_manager}/providers/Microsoft.Authorization/elevateAccess?api-version=2016-07-01" try: - result = self.sdk.requests.post(url, headers=auth_header) + result = self.sdk.requests.post(url, headers=auth_header, timeout=30) result.raise_for_status() if not result.ok: raise AuthenticationException("Failed to elevate access") @@ -1337,6 +1354,7 @@ class AzureCloudProvider(CloudProviderInterface): f"{self.sdk.cloud.endpoints.resource_manager}{payload.invoice_section_id}{cost_mgmt_url}", json=request_body, headers=headers, + timeout=30, ) result.raise_for_status() if result.ok: diff --git a/atst/domain/csp/cloud/mock_cloud_provider.py b/atst/domain/csp/cloud/mock_cloud_provider.py index 7ec0636f..2d646145 100644 --- a/atst/domain/csp/cloud/mock_cloud_provider.py +++ b/atst/domain/csp/cloud/mock_cloud_provider.py @@ -122,10 +122,6 @@ class MockCloudProvider(CloudProviderInterface): payload is an instance of TenantCSPPayload data class """ - self._authorize("admin") - - self._delay(1, 5) - 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) diff --git a/atst/models/mixins/state_machines.py b/atst/models/mixins/state_machines.py index 3ce5193f..5741476d 100644 --- a/atst/models/mixins/state_machines.py +++ b/atst/models/mixins/state_machines.py @@ -123,15 +123,21 @@ class FSMMixin: ] def fail_stage(self, stage): - fail_trigger = "fail" + stage + fail_trigger = f"fail_{stage}" + if fail_trigger in self.machine.get_triggers(self.current_state.name): self.trigger(fail_trigger) app.logger.info( f"calling fail trigger '{fail_trigger}' for '{self.__repr__()}'" ) + else: + app.logger.info( + f"could not locate fail trigger '{fail_trigger}' for '{self.__repr__()}'" + ) + def finish_stage(self, stage): - finish_trigger = "finish_" + stage + finish_trigger = f"finish_{stage}" if finish_trigger in self.machine.get_triggers(self.current_state.name): app.logger.info( f"calling finish trigger '{finish_trigger}' for '{self.__repr__()}'" diff --git a/atst/models/portfolio_state_machine.py b/atst/models/portfolio_state_machine.py index d8cc8ec8..d4fff482 100644 --- a/atst/models/portfolio_state_machine.py +++ b/atst/models/portfolio_state_machine.py @@ -15,13 +15,31 @@ from atst.database import db from atst.models.types import Id from atst.models.base import Base import atst.models.mixins as mixins -from atst.models.mixins.state_machines import FSMStates, AzureStages, _build_transitions +from atst.models.mixins.state_machines import ( + FSMStates, + AzureStages, + StageStates, + _build_transitions +) + + +class StateMachineMisconfiguredError(Exception): + def __init__(self, class_details): + self.class_details = class_details + + @property + def message(self): + return self.class_details def _stage_to_classname(stage): return "".join(map(lambda word: word.capitalize(), stage.split("_"))) +def _stage_state_to_stage_name(state, stage_state): + return state.name.split(f"_{stage_state.name}")[0].lower() + + def get_stage_csp_class(stage, class_type): """ given a stage name and class_type return the class @@ -34,7 +52,7 @@ def get_stage_csp_class(stage, class_type): importlib.import_module("atst.domain.csp.cloud.models"), cls_name ) except AttributeError: - print("could not import CSP Result class <%s>" % cls_name) + raise StateMachineMisconfiguredError(f"could not import CSP Payload/Result class {cls_name}") @add_state_features(Tags) @@ -74,7 +92,7 @@ class PortfolioStateMachine( return f"