mirror of
https://github.com/ansible/awx.git
synced 2026-02-11 06:34:42 -03:30
Merge pull request #9584 from shanemcd/explicit-is_container_group
Explicit db field for is_container_group Reviewed-by: Jake McDermott <yo@jakemcdermott.me> Reviewed-by: Ryan Petrello <None>
This commit is contained in:
@@ -4776,8 +4776,7 @@ class InstanceGroupSerializer(BaseSerializer):
|
|||||||
)
|
)
|
||||||
is_container_group = serializers.BooleanField(
|
is_container_group = serializers.BooleanField(
|
||||||
help_text=_('Indicates whether instances in this group are containerized.'
|
help_text=_('Indicates whether instances in this group are containerized.'
|
||||||
'Containerized groups have a designated Openshift or Kubernetes cluster.'),
|
'Containerized groups have a designated Openshift or Kubernetes cluster.')
|
||||||
read_only=True
|
|
||||||
)
|
)
|
||||||
# NOTE: help_text is duplicated from field definitions, no obvious way of
|
# NOTE: help_text is duplicated from field definitions, no obvious way of
|
||||||
# both defining field details here and also getting the field's help_text
|
# both defining field details here and also getting the field's help_text
|
||||||
@@ -4853,6 +4852,15 @@ class InstanceGroupSerializer(BaseSerializer):
|
|||||||
raise serializers.ValidationError(_('Only Kubernetes credentials can be associated with an Instance Group'))
|
raise serializers.ValidationError(_('Only Kubernetes credentials can be associated with an Instance Group'))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
attrs = super(InstanceGroupSerializer, self).validate(attrs)
|
||||||
|
|
||||||
|
if attrs.get('credential') and not attrs.get('is_container_group'):
|
||||||
|
raise serializers.ValidationError({'is_container_group': _(
|
||||||
|
'is_container_group must be True when associating a credential to an Instance Group')})
|
||||||
|
|
||||||
|
return attrs
|
||||||
|
|
||||||
def get_capacity_dict(self):
|
def get_capacity_dict(self):
|
||||||
# Store capacity values (globally computed) in the context
|
# Store capacity values (globally computed) in the context
|
||||||
if 'capacity_map' not in self.context:
|
if 'capacity_map' not in self.context:
|
||||||
|
|||||||
@@ -17,13 +17,14 @@ class InstanceNotFound(Exception):
|
|||||||
|
|
||||||
|
|
||||||
class RegisterQueue:
|
class RegisterQueue:
|
||||||
def __init__(self, queuename, controller, instance_percent, inst_min, hostname_list):
|
def __init__(self, queuename, controller, instance_percent, inst_min, hostname_list, is_container_group=None):
|
||||||
self.instance_not_found_err = None
|
self.instance_not_found_err = None
|
||||||
self.queuename = queuename
|
self.queuename = queuename
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.instance_percent = instance_percent
|
self.instance_percent = instance_percent
|
||||||
self.instance_min = inst_min
|
self.instance_min = inst_min
|
||||||
self.hostname_list = hostname_list
|
self.hostname_list = hostname_list
|
||||||
|
self.is_container_group = is_container_group
|
||||||
|
|
||||||
def get_create_update_instance_group(self):
|
def get_create_update_instance_group(self):
|
||||||
created = False
|
created = False
|
||||||
@@ -36,6 +37,10 @@ class RegisterQueue:
|
|||||||
ig.policy_instance_minimum = self.instance_min
|
ig.policy_instance_minimum = self.instance_min
|
||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
|
if self.is_container_group:
|
||||||
|
ig.is_container_group = self.is_container_group
|
||||||
|
changed = True
|
||||||
|
|
||||||
if changed:
|
if changed:
|
||||||
ig.save()
|
ig.save()
|
||||||
|
|
||||||
|
|||||||
@@ -144,7 +144,8 @@ class InstanceManager(models.Manager):
|
|||||||
from awx.main.management.commands.register_queue import RegisterQueue
|
from awx.main.management.commands.register_queue import RegisterQueue
|
||||||
pod_ip = os.environ.get('MY_POD_IP')
|
pod_ip = os.environ.get('MY_POD_IP')
|
||||||
registered = self.register(ip_address=pod_ip)
|
registered = self.register(ip_address=pod_ip)
|
||||||
RegisterQueue('tower', None, 100, 0, []).register()
|
is_container_group = settings.IS_K8S
|
||||||
|
RegisterQueue('tower', None, 100, 0, [], is_container_group).register()
|
||||||
return registered
|
return registered
|
||||||
else:
|
else:
|
||||||
return (False, self.me())
|
return (False, self.me())
|
||||||
|
|||||||
27
awx/main/migrations/0132_instancegroup_is_container_group.py
Normal file
27
awx/main/migrations/0132_instancegroup_is_container_group.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Generated by Django 2.2.16 on 2021-03-13 14:53
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_existing_container_groups(apps, schema_editor):
|
||||||
|
InstanceGroup = apps.get_model('main', 'InstanceGroup')
|
||||||
|
|
||||||
|
for group in InstanceGroup.objects.filter(credential__isnull=False).iterator():
|
||||||
|
group.is_container_group = True
|
||||||
|
group.save(update_fields=['is_container_group'])
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0131_undo_org_polymorphic_ee'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='instancegroup',
|
||||||
|
name='is_container_group',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.RunPython(migrate_existing_container_groups, migrations.RunPython.noop),
|
||||||
|
]
|
||||||
@@ -199,6 +199,9 @@ class InstanceGroup(HasPolicyEditsMixin, BaseModel, RelatedJobsMixin):
|
|||||||
null=True,
|
null=True,
|
||||||
on_delete=models.CASCADE
|
on_delete=models.CASCADE
|
||||||
)
|
)
|
||||||
|
is_container_group = models.BooleanField(
|
||||||
|
default=False
|
||||||
|
)
|
||||||
credential = models.ForeignKey(
|
credential = models.ForeignKey(
|
||||||
'Credential',
|
'Credential',
|
||||||
related_name='%(class)ss',
|
related_name='%(class)ss',
|
||||||
@@ -253,13 +256,6 @@ class InstanceGroup(HasPolicyEditsMixin, BaseModel, RelatedJobsMixin):
|
|||||||
def is_isolated(self):
|
def is_isolated(self):
|
||||||
return bool(self.controller)
|
return bool(self.controller)
|
||||||
|
|
||||||
@property
|
|
||||||
def is_container_group(self):
|
|
||||||
if settings.IS_K8S:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return bool(self.credential and self.credential.kubernetes)
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
RelatedJobsMixin
|
RelatedJobsMixin
|
||||||
'''
|
'''
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ def isolated_instance_group(instance_group, instance):
|
|||||||
def containerized_instance_group(instance_group, kube_credential):
|
def containerized_instance_group(instance_group, kube_credential):
|
||||||
ig = InstanceGroup(name="container")
|
ig = InstanceGroup(name="container")
|
||||||
ig.credential = kube_credential
|
ig.credential = kube_credential
|
||||||
|
ig.is_container_group = True
|
||||||
ig.save()
|
ig.save()
|
||||||
return ig
|
return ig
|
||||||
|
|
||||||
@@ -287,6 +288,7 @@ def test_containerized_group_default_fields(instance_group, kube_credential):
|
|||||||
assert ig.policy_instance_minimum == 5
|
assert ig.policy_instance_minimum == 5
|
||||||
assert ig.policy_instance_percentage == 5
|
assert ig.policy_instance_percentage == 5
|
||||||
ig.credential = kube_credential
|
ig.credential = kube_credential
|
||||||
|
ig.is_container_group = True
|
||||||
ig.save()
|
ig.save()
|
||||||
assert ig.policy_instance_list == []
|
assert ig.policy_instance_list == []
|
||||||
assert ig.policy_instance_minimum == 0
|
assert ig.policy_instance_minimum == 0
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from awx.main.utils import (
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def containerized_job(default_instance_group, kube_credential, job_template_factory):
|
def containerized_job(default_instance_group, kube_credential, job_template_factory):
|
||||||
default_instance_group.credential = kube_credential
|
default_instance_group.credential = kube_credential
|
||||||
|
default_instance_group.is_container_group = True
|
||||||
default_instance_group.save()
|
default_instance_group.save()
|
||||||
objects = job_template_factory('jt', organization='org1', project='proj',
|
objects = job_template_factory('jt', organization='org1', project='proj',
|
||||||
inventory='inv', credential='cred',
|
inventory='inv', credential='cred',
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ function ContainerGroupAdd() {
|
|||||||
pod_spec_override: values.override
|
pod_spec_override: values.override
|
||||||
? getPodSpecValue(values.pod_spec_override)
|
? getPodSpecValue(values.pod_spec_override)
|
||||||
: null,
|
: null,
|
||||||
|
is_container_group: true,
|
||||||
});
|
});
|
||||||
history.push(`/instance_groups/container_group/${response.id}/details`);
|
history.push(`/instance_groups/container_group/${response.id}/details`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ const initialPodSpec = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
is_container_group: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,6 +81,7 @@ describe('<ContainerGroupAdd/>', () => {
|
|||||||
expect(InstanceGroupsAPI.create).toHaveBeenCalledWith({
|
expect(InstanceGroupsAPI.create).toHaveBeenCalledWith({
|
||||||
...instanceGroupCreateData,
|
...instanceGroupCreateData,
|
||||||
credential: 71,
|
credential: 71,
|
||||||
|
is_container_group: true,
|
||||||
});
|
});
|
||||||
expect(wrapper.find('FormSubmitError').length).toBe(0);
|
expect(wrapper.find('FormSubmitError').length).toBe(0);
|
||||||
expect(history.location.pathname).toBe(
|
expect(history.location.pathname).toBe(
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ function ContainerGroupEdit({ instanceGroup }) {
|
|||||||
name: values.name,
|
name: values.name,
|
||||||
credential: values.credential ? values.credential.id : null,
|
credential: values.credential ? values.credential.id : null,
|
||||||
pod_spec_override: values.override ? values.pod_spec_override : null,
|
pod_spec_override: values.override ? values.pod_spec_override : null,
|
||||||
|
is_container_group: true,
|
||||||
});
|
});
|
||||||
history.push(detailsIUrl);
|
history.push(detailsIUrl);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ describe('<ContainerGroupEdit/>', () => {
|
|||||||
...updatedInstanceGroup,
|
...updatedInstanceGroup,
|
||||||
credential: 12,
|
credential: 12,
|
||||||
pod_spec_override: null,
|
pod_spec_override: null,
|
||||||
|
is_container_group: true,
|
||||||
});
|
});
|
||||||
expect(history.location.pathname).toEqual(
|
expect(history.location.pathname).toEqual(
|
||||||
'/instance_groups/container_group/123/details'
|
'/instance_groups/container_group/123/details'
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ options:
|
|||||||
- Credential to authenticate with Kubernetes or OpenShift. Must be of type "Kubernetes/OpenShift API Bearer Token".
|
- Credential to authenticate with Kubernetes or OpenShift. Must be of type "Kubernetes/OpenShift API Bearer Token".
|
||||||
required: False
|
required: False
|
||||||
type: str
|
type: str
|
||||||
|
is_container_group:
|
||||||
|
description:
|
||||||
|
- Signifies that this InstanceGroup should act as a ContainerGroup. If no credential is specified, the underlying Pod's ServiceAccount will be used.
|
||||||
|
required: False
|
||||||
|
type: bool
|
||||||
policy_instance_percentage:
|
policy_instance_percentage:
|
||||||
description:
|
description:
|
||||||
- Minimum percentage of all instances that will be automatically assigned to this group when new instances come online.
|
- Minimum percentage of all instances that will be automatically assigned to this group when new instances come online.
|
||||||
@@ -85,6 +90,7 @@ def main():
|
|||||||
name=dict(required=True),
|
name=dict(required=True),
|
||||||
new_name=dict(),
|
new_name=dict(),
|
||||||
credential=dict(),
|
credential=dict(),
|
||||||
|
is_container_group=dict(type='bool', default=False),
|
||||||
policy_instance_percentage=dict(type='int', default='0'),
|
policy_instance_percentage=dict(type='int', default='0'),
|
||||||
policy_instance_minimum=dict(type='int', default='0'),
|
policy_instance_minimum=dict(type='int', default='0'),
|
||||||
policy_instance_list=dict(type='list'),
|
policy_instance_list=dict(type='list'),
|
||||||
@@ -100,6 +106,7 @@ def main():
|
|||||||
name = module.params.get('name')
|
name = module.params.get('name')
|
||||||
new_name = module.params.get("new_name")
|
new_name = module.params.get("new_name")
|
||||||
credential = module.params.get('credential')
|
credential = module.params.get('credential')
|
||||||
|
is_container_group = module.params.get('is_container_group')
|
||||||
policy_instance_percentage = module.params.get('policy_instance_percentage')
|
policy_instance_percentage = module.params.get('policy_instance_percentage')
|
||||||
policy_instance_minimum = module.params.get('policy_instance_minimum')
|
policy_instance_minimum = module.params.get('policy_instance_minimum')
|
||||||
policy_instance_list = module.params.get('policy_instance_list')
|
policy_instance_list = module.params.get('policy_instance_list')
|
||||||
@@ -129,6 +136,8 @@ def main():
|
|||||||
new_fields['name'] = new_name if new_name else (module.get_item_name(existing_item) if existing_item else name)
|
new_fields['name'] = new_name if new_name else (module.get_item_name(existing_item) if existing_item else name)
|
||||||
if credential is not None:
|
if credential is not None:
|
||||||
new_fields['credential'] = credential_id
|
new_fields['credential'] = credential_id
|
||||||
|
if is_container_group is not None:
|
||||||
|
new_fields['is_container_group'] = is_container_group
|
||||||
if policy_instance_percentage is not None:
|
if policy_instance_percentage is not None:
|
||||||
new_fields['policy_instance_percentage'] = policy_instance_percentage
|
new_fields['policy_instance_percentage'] = policy_instance_percentage
|
||||||
if policy_instance_minimum is not None:
|
if policy_instance_minimum is not None:
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ def test_container_group_create(run_module, admin_user, kube_credential):
|
|||||||
result = run_module('tower_instance_group', {
|
result = run_module('tower_instance_group', {
|
||||||
'name': 'foo-c-group',
|
'name': 'foo-c-group',
|
||||||
'credential': kube_credential.id,
|
'credential': kube_credential.id,
|
||||||
|
'is_container_group': True,
|
||||||
'state': 'present'
|
'state': 'present'
|
||||||
}, admin_user)
|
}, admin_user)
|
||||||
assert not result.get('failed', False), result['msg']
|
assert not result.get('failed', False), result['msg']
|
||||||
@@ -61,6 +62,7 @@ def test_container_group_create(run_module, admin_user, kube_credential):
|
|||||||
result = run_module('tower_instance_group', {
|
result = run_module('tower_instance_group', {
|
||||||
'name': 'foo-c-group',
|
'name': 'foo-c-group',
|
||||||
'credential': kube_credential.id,
|
'credential': kube_credential.id,
|
||||||
|
'is_container_group': True,
|
||||||
'pod_spec_override': pod_spec,
|
'pod_spec_override': pod_spec,
|
||||||
'state': 'present'
|
'state': 'present'
|
||||||
}, admin_user)
|
}, admin_user)
|
||||||
|
|||||||
@@ -13,29 +13,4 @@ if [ -n "${AWX_KUBE_DEVEL}" ]; then
|
|||||||
export SDB_NOTIFY_HOST=$MY_POD_IP
|
export SDB_NOTIFY_HOST=$MY_POD_IP
|
||||||
fi
|
fi
|
||||||
|
|
||||||
source /etc/tower/conf.d/environment.sh
|
|
||||||
|
|
||||||
ANSIBLE_REMOTE_TEMP=/tmp ANSIBLE_LOCAL_TEMP=/tmp ansible -i "127.0.0.1," -c local -v -m wait_for -a "host=$DATABASE_HOST port=$DATABASE_PORT" all
|
|
||||||
ANSIBLE_REMOTE_TEMP=/tmp ANSIBLE_LOCAL_TEMP=/tmp ansible -i "127.0.0.1," -c local -v -m postgresql_db --become-user $DATABASE_USER -a "name=$DATABASE_NAME owner=$DATABASE_USER login_user=$DATABASE_USER login_host=$DATABASE_HOST login_password=$DATABASE_PASSWORD port=$DATABASE_PORT" all
|
|
||||||
|
|
||||||
if [ -z "$AWX_SKIP_MIGRATIONS" ]; then
|
|
||||||
echo "Running migrations..."
|
|
||||||
awx-manage migrate --noinput
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$AWX_SKIP_PROVISION_INSTANCE" ]; then
|
|
||||||
awx-manage provision_instance --hostname=$(hostname)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$AWX_SKIP_REGISTERQUEUE" ]; then
|
|
||||||
awx-manage register_queue --queuename=tower --instance_percent=100
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -z "$AWX_ADMIN_USER" ]&&[ ! -z "$AWX_ADMIN_PASSWORD" ]; then
|
|
||||||
echo "from django.contrib.auth.models import User; User.objects.create_superuser('$AWX_ADMIN_USER', 'root@localhost', '$AWX_ADMIN_PASSWORD')" | awx-manage shell
|
|
||||||
fi
|
|
||||||
echo 'from django.conf import settings; x = settings.AWX_TASK_ENV; x["HOME"] = "/var/lib/awx"; settings.AWX_TASK_ENV = x' | awx-manage shell
|
|
||||||
|
|
||||||
unset $(cut -d = -f -1 /etc/tower/conf.d/environment.sh)
|
|
||||||
|
|
||||||
supervisord -c /etc/supervisord_task.conf
|
supervisord -c /etc/supervisord_task.conf
|
||||||
|
|||||||
Reference in New Issue
Block a user