Merge pull request #1062 from dod-ccpo/env-provisioning-task

Environment provisioning background jobs
This commit is contained in:
richard-dds
2019-09-16 09:58:18 -04:00
committed by GitHub
22 changed files with 613 additions and 31 deletions

View File

@@ -21,7 +21,7 @@ from tests.factories import (
def test_create_application_with_multiple_environments():
portfolio = PortfolioFactory.create()
application = Applications.create(
portfolio, "My Test Application", "Test", ["dev", "prod"]
portfolio.owner, portfolio, "My Test Application", "Test", ["dev", "prod"]
)
assert application.portfolio == portfolio

View File

@@ -1,4 +1,6 @@
import pytest
import pendulum
from uuid import uuid4
from atst.domain.environments import Environments
from atst.domain.environment_roles import EnvironmentRoles
@@ -7,7 +9,6 @@ from atst.models.environment_role import CSPRole
from tests.factories import (
ApplicationFactory,
UserFactory,
PortfolioFactory,
EnvironmentFactory,
EnvironmentRoleFactory,
@@ -15,12 +16,13 @@ from tests.factories import (
)
@pytest.mark.skip(reason="Reinstate and update once jobs api is up")
def test_create_environments():
application = ApplicationFactory.create()
environments = Environments.create_many(application, ["Staging", "Production"])
environments = Environments.create_many(
application.portfolio.owner, application, ["Staging", "Production"]
)
for env in environments:
assert env.cloud_id is not None
assert env.cloud_id is None
def test_update_env_role():
@@ -87,3 +89,125 @@ def test_update_environment():
assert environment.name is not "name 2"
Environments.update(environment, name="name 2")
assert environment.name == "name 2"
class EnvQueryTest:
@property
def NOW(self):
return pendulum.now()
@property
def YESTERDAY(self):
return self.NOW.subtract(days=1)
@property
def TOMORROW(self):
return self.NOW.add(days=1)
def create_portfolio_with_clins(self, start_and_end_dates, env_data=None):
env_data = env_data or {}
return PortfolioFactory.create(
applications=[
{
"name": "Mos Eisley",
"description": "Where Han shot first",
"environments": [{"name": "thebar", **env_data}],
}
],
task_orders=[
{
"create_clins": [
{"start_date": start_date, "end_date": end_date}
for (start_date, end_date) in start_and_end_dates
]
}
],
)
class TestGetEnvironmentsPendingCreate(EnvQueryTest):
def test_with_expired_clins(self, session):
self.create_portfolio_with_clins([(self.YESTERDAY, self.YESTERDAY)])
assert len(Environments.get_environments_pending_creation(self.NOW)) == 0
def test_with_active_clins(self, session):
portfolio = self.create_portfolio_with_clins([(self.YESTERDAY, self.TOMORROW)])
Environments.get_environments_pending_creation(self.NOW) == [
portfolio.applications[0].environments[0].id
]
def test_with_future_clins(self, session):
self.create_portfolio_with_clins([(self.TOMORROW, self.TOMORROW)])
assert len(Environments.get_environments_pending_creation(self.NOW)) == 0
def test_with_already_provisioned_env(self, session):
self.create_portfolio_with_clins(
[(self.YESTERDAY, self.TOMORROW)], env_data={"cloud_id": uuid4().hex}
)
assert len(Environments.get_environments_pending_creation(self.NOW)) == 0
class TestGetEnvironmentsPendingAtatUserCreation(EnvQueryTest):
def test_with_provisioned_environment(self):
self.create_portfolio_with_clins(
[(self.YESTERDAY, self.TOMORROW)],
{"cloud_id": uuid4().hex, "root_user_info": {}},
)
assert (
len(Environments.get_environments_pending_atat_user_creation(self.NOW)) == 0
)
def test_with_unprovisioned_environment(self):
self.create_portfolio_with_clins(
[(self.YESTERDAY, self.TOMORROW)],
{"cloud_id": uuid4().hex, "root_user_info": None},
)
assert (
len(Environments.get_environments_pending_atat_user_creation(self.NOW)) == 1
)
def test_with_unprovisioned_expired_clins_environment(self):
self.create_portfolio_with_clins(
[(self.YESTERDAY, self.YESTERDAY)],
{"cloud_id": uuid4().hex, "root_user_info": None},
)
assert (
len(Environments.get_environments_pending_atat_user_creation(self.NOW)) == 0
)
class TestGetEnvironmentsPendingBaselineCreation(EnvQueryTest):
def test_with_provisioned_environment(self):
self.create_portfolio_with_clins(
[(self.YESTERDAY, self.TOMORROW)],
{
"cloud_id": uuid4().hex,
"root_user_info": {"foo": "bar"},
"baseline_info": {"foo": "bar"},
},
)
assert (
len(Environments.get_environments_pending_baseline_creation(self.NOW)) == 0
)
def test_with_unprovisioned_environment(self):
self.create_portfolio_with_clins(
[(self.YESTERDAY, self.TOMORROW)],
{
"cloud_id": uuid4().hex,
"root_user_info": {"foo": "bar"},
"baseline_info": None,
},
)
assert (
len(Environments.get_environments_pending_baseline_creation(self.NOW)) == 1
)
def test_with_unprovisioned_expired_clins_environment(self):
self.create_portfolio_with_clins(
[(self.YESTERDAY, self.YESTERDAY)],
{"cloud_id": uuid4().hex, "root_user_info": {"foo": "bar"}},
)
assert (
len(Environments.get_environments_pending_baseline_creation(self.NOW)) == 0
)

View File

@@ -71,7 +71,11 @@ def test_update_portfolio_role_role(portfolio, portfolio_owner):
def test_scoped_portfolio_for_admin_missing_view_apps_perms(portfolio_owner, portfolio):
Applications.create(
portfolio, "My Application 2", "My application 2", ["dev", "staging", "prod"]
portfolio.owner,
portfolio,
"My Application 2",
"My application 2",
["dev", "staging", "prod"],
)
restricted_admin = UserFactory.create()
PortfolioRoleFactory.create(
@@ -90,7 +94,11 @@ def test_scoped_portfolio_returns_all_applications_for_portfolio_admin(
):
for _ in range(5):
Applications.create(
portfolio, "My Application", "My application", ["dev", "staging", "prod"]
portfolio.owner,
portfolio,
"My Application",
"My application",
["dev", "staging", "prod"],
)
admin = UserFactory.create()
@@ -109,7 +117,11 @@ def test_scoped_portfolio_returns_all_applications_for_portfolio_owner(
):
for _ in range(5):
Applications.create(
portfolio, "My Application", "My application", ["dev", "staging", "prod"]
portfolio.owner,
portfolio,
"My Application",
"My application",
["dev", "staging", "prod"],
)
scoped_portfolio = Portfolios.get(portfolio_owner, portfolio.id)

View File

@@ -139,7 +139,7 @@ def test_update_adds_clins():
def test_update_does_not_duplicate_clins():
task_order = TaskOrderFactory.create(
number="3453453456", create_clins=["123", "456"]
number="3453453456", create_clins=[{"number": "123"}, {"number": "456"}]
)
clins = [
{
@@ -171,7 +171,9 @@ def test_update_does_not_duplicate_clins():
def test_delete_task_order_with_clins(session):
task_order = TaskOrderFactory.create(create_clins=[1, 2, 3])
task_order = TaskOrderFactory.create(
create_clins=[{"number": 1}, {"number": 2}, {"number": 3}]
)
TaskOrders.delete(task_order.id)
assert not session.query(

View File

@@ -118,6 +118,7 @@ class PortfolioFactory(Base):
with_applications = kwargs.pop("applications", [])
owner = kwargs.pop("owner", UserFactory.create())
members = kwargs.pop("members", [])
with_task_orders = kwargs.pop("task_orders", [])
portfolio = super()._create(model_class, *args, **kwargs)
@@ -126,6 +127,11 @@ class PortfolioFactory(Base):
for p in with_applications
]
task_orders = [
TaskOrderFactory.create(portfolio=portfolio, **to)
for to in with_task_orders
]
PortfolioRoleFactory.create(
portfolio=portfolio,
user=owner,
@@ -154,6 +160,7 @@ class PortfolioFactory(Base):
)
portfolio.applications = applications
portfolio.task_orders = task_orders
return portfolio
@@ -185,6 +192,7 @@ class EnvironmentFactory(Base):
name = factory.Faker("domain_word")
application = factory.SubFactory(ApplicationFactory)
creator = factory.SubFactory(UserFactory)
@classmethod
def _create(cls, model_class, *args, **kwargs):
@@ -278,7 +286,7 @@ class TaskOrderFactory(Base):
task_order = super()._create(model_class, *args, **kwargs)
for clin in create_clins:
CLINFactory.create(task_order=task_order, number=clin)
CLINFactory.create(task_order=task_order, **clin)
return task_order

View File

@@ -1,6 +1,7 @@
import pytest
from atst.models import AuditEvent
from atst.models.environment_role import CSPRole
from atst.domain.environments import Environments
from atst.domain.applications import Applications
from tests.factories import *
@@ -12,7 +13,11 @@ def test_add_user_to_environment():
portfolio = PortfolioFactory.create(owner=owner)
application = Applications.create(
portfolio, "my test application", "It's mine.", ["dev", "staging", "prod"]
portfolio.owner,
portfolio,
"my test application",
"It's mine.",
["dev", "staging", "prod"],
)
dev_environment = application.environments[0]
@@ -42,3 +47,29 @@ def test_audit_event_for_environment_deletion(session):
before, after = update_event.changed_state["deleted"]
assert not before
assert after
@pytest.mark.parametrize(
"env_data,expected_status",
[
[
{"cloud_id": None, "root_user_info": None, "baseline_info": None},
Environment.ProvisioningStatus.PENDING,
],
[
{"cloud_id": 1, "root_user_info": None, "baseline_info": None},
Environment.ProvisioningStatus.PENDING,
],
[
{"cloud_id": 1, "root_user_info": {}, "baseline_info": None},
Environment.ProvisioningStatus.PENDING,
],
[
{"cloud_id": 1, "root_user_info": {}, "baseline_info": {}},
Environment.ProvisioningStatus.COMPLETED,
],
],
)
def test_environment_provisioning_status(env_data, expected_status):
environment = EnvironmentFactory.create(**env_data)
assert environment.provisioning_status == expected_status

View File

@@ -70,6 +70,7 @@ def test_update_environment_failure(client, user_session):
def test_application_settings(client, user_session):
portfolio = PortfolioFactory.create()
application = Applications.create(
portfolio.owner,
portfolio,
"Snazzy Application",
"A new application for me and my friends",
@@ -85,6 +86,7 @@ def test_application_settings(client, user_session):
def test_edit_application_environments_obj(app, client, user_session):
portfolio = PortfolioFactory.create()
application = Applications.create(
portfolio.owner,
portfolio,
"Snazzy Application",
"A new application for me and my friends",
@@ -125,6 +127,7 @@ def test_edit_application_environments_obj(app, client, user_session):
def test_data_for_app_env_roles_form(app, client, user_session):
portfolio = PortfolioFactory.create()
application = Applications.create(
portfolio.owner,
portfolio,
"Snazzy Application",
"A new application for me and my friends",

View File

@@ -29,7 +29,7 @@ def completed_task_order():
task_order = TaskOrderFactory.create(
creator=portfolio.owner,
portfolio=portfolio,
create_clins=["1234567890123456789012345678901234567890123"],
create_clins=[{"number": "1234567890123456789012345678901234567890123"}],
)
return task_order
@@ -334,7 +334,7 @@ def test_task_orders_submit_task_order(client, user_session, task_order):
({"_pdf": None, "number": "", "clins": []}, "step_1"),
({"number": "", "clins": []}, "step_2"),
({"number": "1234567890123", "clins": []}, "step_3"),
({"number": "1234567890123", "create_clins": [1]}, "step_4"),
({"number": "1234567890123", "create_clins": [{"number": 1}]}, "step_4"),
],
)
def test_task_orders_edit_redirects_to_latest_incomplete_step(

View File

@@ -504,7 +504,7 @@ def test_task_orders_new_get_routes(get_url_assert_status):
task_order = TaskOrderFactory.create(
creator=owner,
portfolio=portfolio,
create_clins=["1234567890123456789012345678901234567890123"],
create_clins=[{"number": "1234567890123456789012345678901234567890123"}],
)
for route in get_routes:

View File

@@ -1,8 +1,26 @@
import pendulum
import pytest
from uuid import uuid4
from unittest.mock import Mock
from atst.jobs import RecordEnvironmentFailure, RecordEnvironmentRoleFailure
from tests.factories import EnvironmentFactory, EnvironmentRoleFactory
from atst.models import Environment
from atst.domain.csp.cloud import MockCloudProvider
from atst.jobs import (
RecordEnvironmentFailure,
RecordEnvironmentRoleFailure,
do_create_environment,
do_create_atat_admin_user,
do_create_environment_baseline,
dispatch_create_environment,
dispatch_create_atat_admin_user,
dispatch_create_environment_baseline,
)
from tests.factories import (
EnvironmentFactory,
EnvironmentRoleFactory,
UserFactory,
PortfolioFactory,
)
def test_environment_job_failure(celery_app, celery_worker):
@@ -39,3 +57,142 @@ def test_environment_role_job_failure(celery_app, celery_worker):
assert role.job_failures
job_failure = role.job_failures[0]
assert job_failure.task == task
now = pendulum.now()
yesterday = now.subtract(days=1)
tomorrow = now.add(days=1)
from atst.domain.environments import Environments
@pytest.fixture(autouse=True, scope="function")
def csp():
return Mock(wraps=MockCloudProvider({}, with_delay=False, with_failure=False))
def test_create_environment_job(session, csp):
user = UserFactory.create()
environment = EnvironmentFactory.create()
do_create_environment(csp, environment.id, user.id)
environment_id = environment.id
del environment
updated_environment = session.query(Environment).get(environment_id)
assert updated_environment.cloud_id
def test_create_environment_job_is_idempotent(csp, session):
user = UserFactory.create()
environment = EnvironmentFactory.create(cloud_id=uuid4().hex)
do_create_environment(csp, environment.id, user.id)
csp.create_environment.assert_not_called()
def test_create_atat_admin_user(csp, session):
environment = EnvironmentFactory.create(cloud_id="something")
do_create_atat_admin_user(csp, environment.id)
environment_id = environment.id
del environment
updated_environment = session.query(Environment).get(environment_id)
assert updated_environment.root_user_info
def test_create_environment_baseline(csp, session):
environment = EnvironmentFactory.create(
root_user_info={"credentials": csp.root_creds()}
)
do_create_environment_baseline(csp, environment.id)
environment_id = environment.id
del environment
updated_environment = session.query(Environment).get(environment_id)
assert updated_environment.baseline_info
def test_dispatch_create_environment(session, monkeypatch):
portfolio = PortfolioFactory.create(
applications=[{"environments": [{}]}],
task_orders=[
{
"create_clins": [
{
"start_date": pendulum.now().subtract(days=1),
"end_date": pendulum.now().add(days=1),
}
]
}
],
)
mock = Mock()
monkeypatch.setattr("atst.jobs.create_environment", mock)
environment = portfolio.applications[0].environments[0]
dispatch_create_environment.run()
mock.delay.assert_called_once_with(
environment_id=environment.id, atat_user_id=environment.creator_id
)
def test_dispatch_create_atat_admin_user(session, monkeypatch):
portfolio = PortfolioFactory.create(
applications=[
{"environments": [{"cloud_id": uuid4().hex, "root_user_info": None}]}
],
task_orders=[
{
"create_clins": [
{
"start_date": pendulum.now().subtract(days=1),
"end_date": pendulum.now().add(days=1),
}
]
}
],
)
mock = Mock()
monkeypatch.setattr("atst.jobs.create_atat_admin_user", mock)
environment = portfolio.applications[0].environments[0]
dispatch_create_atat_admin_user.run()
mock.delay.assert_called_once_with(environment_id=environment.id)
def test_dispatch_create_environment_baseline(session, monkeypatch):
portfolio = PortfolioFactory.create(
applications=[
{
"environments": [
{
"cloud_id": uuid4().hex,
"root_user_info": {},
"baseline_info": None,
}
]
}
],
task_orders=[
{
"create_clins": [
{
"start_date": pendulum.now().subtract(days=1),
"end_date": pendulum.now().add(days=1),
}
]
}
],
)
mock = Mock()
monkeypatch.setattr("atst.jobs.create_environment_baseline", mock)
environment = portfolio.applications[0].environments[0]
dispatch_create_environment_baseline.run()
mock.delay.assert_called_once_with(environment_id=environment.id)