From 2fba3db48fd8b5a2950543f6abc9690c70dce0fe Mon Sep 17 00:00:00 2001 From: Jeff Bradberry Date: Mon, 18 Jul 2022 11:10:59 -0400 Subject: [PATCH] Add state fields to Instance and InstanceLink Also, listener_port to Instance. --- .../migrations/0170_node_and_link_state.py | 79 +++++++++++++++++++ awx/main/models/ha.py | 45 +++++++++-- 2 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 awx/main/migrations/0170_node_and_link_state.py diff --git a/awx/main/migrations/0170_node_and_link_state.py b/awx/main/migrations/0170_node_and_link_state.py new file mode 100644 index 0000000000..6fbc3dd12b --- /dev/null +++ b/awx/main/migrations/0170_node_and_link_state.py @@ -0,0 +1,79 @@ +# Generated by Django 3.2.13 on 2022-08-02 17:53 + +import django.core.validators +from django.db import migrations, models + + +def forwards(apps, schema_editor): + # All existing InstanceLink objects need to be in the state + # 'Established', which is the default, so nothing needs to be done + # for that. + + Instance = apps.get_model('main', 'Instance') + for instance in Instance.objects.all(): + instance.node_state = 'ready' if not instance.errors else 'unavailable' + instance.save(update_fields=['node_state']) + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0169_jt_prompt_everything_on_launch'), + ] + + operations = [ + migrations.AddField( + model_name='instance', + name='listener_port', + field=models.PositiveIntegerField( + blank=True, + default=27199, + help_text='Port that Receptor will listen for incoming connections on.', + validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(65535)], + ), + ), + migrations.AddField( + model_name='instance', + name='node_state', + field=models.CharField( + choices=[ + ('provisioning', 'Provisioning'), + ('provision-fail', 'Provisioning Failure'), + ('installed', 'Installed'), + ('ready', 'Ready'), + ('unavailable', 'Unavailable'), + ('deprovisioning', 'De-provisioning'), + ('deprovision-fail', 'De-provisioning Failure'), + ], + default='ready', + help_text='Indicates the current life cycle stage of this instance.', + max_length=16, + ), + ), + migrations.AddField( + model_name='instancelink', + name='link_state', + field=models.CharField( + choices=[('adding', 'Adding'), ('established', 'Established'), ('removing', 'Removing')], + default='established', + help_text='Indicates the current life cycle stage of this peer link.', + max_length=16, + ), + ), + migrations.AlterField( + model_name='instance', + name='node_type', + field=models.CharField( + choices=[ + ('control', 'Control plane node'), + ('execution', 'Execution plane node'), + ('hybrid', 'Controller and execution'), + ('hop', 'Message-passing node, no execution capability'), + ], + default='hybrid', + help_text='Role that this node plays in the mesh.', + max_length=16, + ), + ), + migrations.RunPython(forwards, reverse_code=migrations.RunPython.noop), + ] diff --git a/awx/main/models/ha.py b/awx/main/models/ha.py index eeed06bc60..f7388181f3 100644 --- a/awx/main/models/ha.py +++ b/awx/main/models/ha.py @@ -5,7 +5,7 @@ from decimal import Decimal import logging import os -from django.core.validators import MinValueValidator +from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models, connection from django.db.models.signals import post_save, post_delete from django.dispatch import receiver @@ -59,6 +59,15 @@ class InstanceLink(BaseModel): source = models.ForeignKey('Instance', on_delete=models.CASCADE, related_name='+') target = models.ForeignKey('Instance', on_delete=models.CASCADE, related_name='reverse_peers') + class States(models.TextChoices): + ADDING = 'adding', _('Adding') + ESTABLISHED = 'established', _('Established') + REMOVING = 'removing', _('Removing') + + link_state = models.CharField( + choices=States.choices, default=States.ESTABLISHED, max_length=16, help_text=_("Indicates the current life cycle stage of this peer link.") + ) + class Meta: unique_together = ('source', 'target') @@ -127,13 +136,33 @@ class Instance(HasPolicyEditsMixin, BaseModel): default=0, editable=False, ) - NODE_TYPE_CHOICES = [ - ("control", "Control plane node"), - ("execution", "Execution plane node"), - ("hybrid", "Controller and execution"), - ("hop", "Message-passing node, no execution capability"), - ] - node_type = models.CharField(default='hybrid', choices=NODE_TYPE_CHOICES, max_length=16) + + class Types(models.TextChoices): + CONTROL = 'control', _("Control plane node") + EXECUTION = 'execution', _("Execution plane node") + HYBRID = 'hybrid', _("Controller and execution") + HOP = 'hop', _("Message-passing node, no execution capability") + + node_type = models.CharField(default=Types.HYBRID, choices=Types.choices, max_length=16, help_text=_("Role that this node plays in the mesh.")) + + class States(models.TextChoices): + PROVISIONING = 'provisioning', _('Provisioning') + PROVISION_FAIL = 'provision-fail', _('Provisioning Failure') + INSTALLED = 'installed', _('Installed') + READY = 'ready', _('Ready') + UNAVAILABLE = 'unavailable', _('Unavailable') + DEPROVISIONING = 'deprovisioning', _('De-provisioning') + DEPROVISION_FAIL = 'deprovision-fail', _('De-provisioning Failure') + + node_state = models.CharField( + choices=States.choices, default=States.READY, max_length=16, help_text=_("Indicates the current life cycle stage of this instance.") + ) + listener_port = models.PositiveIntegerField( + blank=True, + default=27199, + validators=[MinValueValidator(1), MaxValueValidator(65535)], + help_text=_("Port that Receptor will listen for incoming connections on."), + ) peers = models.ManyToManyField('self', symmetrical=False, through=InstanceLink, through_fields=('source', 'target'))