portfolio provision process. add logging, __repr___ method, fix broken tests
This commit is contained in:
@@ -4,6 +4,8 @@ from uuid import uuid4
|
||||
|
||||
from pydantic import BaseModel, validator
|
||||
|
||||
from flask import current_app as app
|
||||
|
||||
from atst.models.user import User
|
||||
from atst.models.application import Application
|
||||
from atst.models.environment import Environment
|
||||
@@ -754,6 +756,7 @@ class AzureSDKProvider(object):
|
||||
self.graphrbac = graphrbac
|
||||
self.credentials = credentials
|
||||
self.identity = identity
|
||||
self.exceptions = exceptions
|
||||
self.secrets = secrets
|
||||
self.requests = requests
|
||||
# may change to a JEDI cloud
|
||||
@@ -781,14 +784,21 @@ class AzureCloudProvider(CloudProviderInterface):
|
||||
secret_client = self.secrets.SecretClient(
|
||||
vault_url=self.vault_url, credential=credential,
|
||||
)
|
||||
return secret_client.set_secret(secret_key, secret_value)
|
||||
try:
|
||||
return secret_client.set_secret(secret_key, secret_value)
|
||||
except self.exceptions.HttpResponseError as exc:
|
||||
app.logger.error(f"Could not SET secret in Azure keyvault for key {secret_key}.", exc_info=1)
|
||||
|
||||
|
||||
def get_secret(secret_key):
|
||||
credential = self._get_client_secret_credential_obj()
|
||||
secret_client = self.secrets.SecretClient(
|
||||
vault_url=self.vault_url, credential=credential,
|
||||
)
|
||||
return secret_client.get_secret(secret_key).value
|
||||
try:
|
||||
return secret_client.get_secret(secret_key).value
|
||||
except self.exceptions.HttpResponseError as exc:
|
||||
app.logger.error(f"Could not GET secret in Azure keyvault for key {secret_key}.", exc_info=1)
|
||||
|
||||
def create_environment(
|
||||
self, auth_credentials: Dict, user: User, environment: Environment
|
||||
|
@@ -1,5 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
from flask import current_app as app
|
||||
|
||||
|
||||
class StageStates(Enum):
|
||||
CREATED = "created"
|
||||
@@ -107,10 +109,12 @@ class FSMMixin:
|
||||
fail_trigger = "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__()}'")
|
||||
|
||||
def finish_stage(self, stage):
|
||||
finish_trigger = "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__()}'")
|
||||
self.trigger(finish_trigger)
|
||||
|
||||
def prepare_init(self, event):
|
||||
|
@@ -64,6 +64,10 @@ class PortfolioStateMachine(
|
||||
db.session.add(self)
|
||||
db.session.commit()
|
||||
|
||||
def __repr__(self):
|
||||
return f"<PortfolioStateMachine(state='{self.current_state.name}', portfolio='{self.portfolio.name}'"
|
||||
|
||||
|
||||
@reconstructor
|
||||
def attach_machine(self):
|
||||
"""
|
||||
@@ -108,6 +112,7 @@ class PortfolioStateMachine(
|
||||
if create_trigger:
|
||||
self.trigger(create_trigger, **kwargs)
|
||||
else:
|
||||
app.logger.info(f"could not locate 'create trigger' for {self.__repr__()}")
|
||||
self.fail_stage(stage)
|
||||
|
||||
elif state_obj.is_CREATED:
|
||||
@@ -133,15 +138,14 @@ class PortfolioStateMachine(
|
||||
|
||||
payload_data_cls = get_stage_csp_class(stage, "payload")
|
||||
if not payload_data_cls:
|
||||
print("could not resolve payload data class")
|
||||
app.logger.info(f"could not resolve payload data class for stage {stage}")
|
||||
self.fail_stage(stage)
|
||||
try:
|
||||
payload_data = payload_data_cls(**payload)
|
||||
except PydanticValidationError as exc:
|
||||
print("Payload Validation Error:")
|
||||
print(exc.json())
|
||||
print("got")
|
||||
print(payload)
|
||||
app.logger.error(f"Payload Validation Error in {self.__repr__()}:", exc_info=1)
|
||||
app.logger.info(exc.json())
|
||||
app.logger.info(payload)
|
||||
self.fail_stage(stage)
|
||||
|
||||
# TODO: Determine best place to do this, maybe @reconstructor
|
||||
@@ -151,18 +155,19 @@ class PortfolioStateMachine(
|
||||
else:
|
||||
self.csp = MockCSP(app).cloud
|
||||
|
||||
for attempt in range(5):
|
||||
attempts_count = 5
|
||||
for attempt in range(attempts_count):
|
||||
try:
|
||||
func_name = f"create_{stage}"
|
||||
response = getattr(self.csp, func_name)(payload_data)
|
||||
except (ConnectionException, UnknownServerException) as exc:
|
||||
print("caught exception. retry", attempt)
|
||||
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
|
||||
print("failed")
|
||||
logger.info(f"CSP api call failed after {attempts_count} attempts.")
|
||||
self.fail_stage(stage)
|
||||
|
||||
if self.portfolio.csp_data is None:
|
||||
@@ -177,7 +182,6 @@ class PortfolioStateMachine(
|
||||
|
||||
def is_csp_data_valid(self, event):
|
||||
# check portfolio csp details json field for fields
|
||||
|
||||
if self.portfolio.csp_data is None or not isinstance(
|
||||
self.portfolio.csp_data, dict
|
||||
):
|
||||
@@ -199,9 +203,10 @@ class PortfolioStateMachine(
|
||||
# self.store_creds(self.portfolio, new_creds)
|
||||
|
||||
except PydanticValidationError as exc:
|
||||
print("is_csp_data_valid: False")
|
||||
print(cls)
|
||||
print(exc.json())
|
||||
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
|
||||
|
Reference in New Issue
Block a user