diff options
| author | ckonstanski <kostcarl@isu.edu> | 2026-07-30 18:17:14 -0600 |
|---|---|---|
| committer | ckonstanski <kostcarl@isu.edu> | 2026-07-30 18:17:14 -0600 |
| commit | 640ff61422bc0ee3966941b93d9889ddbbd38d77 (patch) | |
| tree | abf1c08f5d38ee53ec8b29dc4f425722517505e6 /src/automationstatus | |
| parent | 22dae02a86c1fce71091bfa5289cf99abba1b217 (diff) | |
Diffstat (limited to 'src/automationstatus')
20 files changed, 549 insertions, 0 deletions
diff --git a/src/automationstatus/README.md b/src/automationstatus/README.md new file mode 100644 index 0000000..3adf86a --- /dev/null +++ b/src/automationstatus/README.md @@ -0,0 +1,26 @@ +## How to use the automation status API + +The automation status API is a REST api for playbooks to report startus as they are running. + +URL: /automationstatus/playbook/ + +## Sending a status updates + +POST: /automationstatus/playbook/ + +Body: +{ + "ilo_host_address": "2001:4888:2a10:30c2:101:40a:0:e001", + "playbook_name": "test_playbook123", + "status": "test_status223" +} + +## Retrieve updates + +GET: /automationstatus/playbook/ + +GET: /automationstatus/playbook/1 + + + + diff --git a/src/automationstatus/__init__.py b/src/automationstatus/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/automationstatus/__init__.py diff --git a/src/automationstatus/admin.py b/src/automationstatus/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/src/automationstatus/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/src/automationstatus/apps.py b/src/automationstatus/apps.py new file mode 100644 index 0000000..0df5294 --- /dev/null +++ b/src/automationstatus/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class AutomationStatusConfig(AppConfig): + name = 'automationstatus' diff --git a/src/automationstatus/crons.py b/src/automationstatus/crons.py new file mode 100644 index 0000000..da1d59d --- /dev/null +++ b/src/automationstatus/crons.py @@ -0,0 +1,151 @@ +from .models import DeploymentWorkflow, Summary +from .models import OrchestrationWorkflow +from datetime import datetime +from django.apps import apps +from django.db import connection +from django.core import serializers +from django.utils import timezone + + +def count(): + queryset = DeploymentWorkflow.objects.all() + + in_progress_clusters = 0 + failed_clusters = 0 + completed_clusters = 0 + ingested = 0 + online = 0 + bmc = 0 + firmware_scheduled = 0 + firmware_upgraded = 0 + wr_scheduled = 0 + wr_installed = 0 + + for workflow in queryset: + if workflow.wr_installed: + completed_clusters = completed_clusters + 1 + else: + in_progress_clusters = in_progress_clusters + 1 + # summary.failed = failed_clusters + + if workflow.ingested: + ingested = ingested + 1 + + if workflow.online: + online = online + 1 + + if workflow.bmc: + bmc = bmc + 1 + + if workflow.firmware_scheduled and not workflow.firmware_upgraded: + firmware_scheduled = firmware_scheduled + 1 + + if workflow.firmware_upgraded: + firmware_upgraded = firmware_upgraded + 1 + + if workflow.wr_scheduled and not workflow.wr_installed: + wr_scheduled = wr_scheduled + 1 + + if workflow.wr_installed: + wr_installed = wr_installed + 1 + + + summary = Summary() + summary.clusters = len(queryset) + summary.in_progress = in_progress_clusters + summary.completed = completed_clusters + summary.ingested = ingested + summary.online = online + summary.bmc = bmc + summary.firmware_scheduled = firmware_scheduled + summary.firmware_upgraded = firmware_upgraded + summary.wr_scheduled = wr_scheduled + summary.wr_installed = wr_installed + summary.created_at = timezone.now() + print(summary) + try: + summary.save() + except Exception as e: + print(e) + + +def summary(): + print("**** running cron: summary **** : {}".format(datetime.now())) + servers = apps.get_model('caas', 'Server') + query_set = servers.objects.select_related('cluster').select_related('blade') + for server in query_set: + # Set server id and date + status = DeploymentWorkflow() + status.cluster = server.cluster + status.created_at = timezone.now() + # CIQ ingestion + status.ingested = True + # Server online check + status.online = True if server.blade_id else False + #BMC done check + if server.pxe_mac_address and server.intel_nic_firmware_version: + status.bmc = True + # Check Firmware schedule and installation status + # Get server list from + Server = apps.get_model('caas', 'Server') + server = Server.objects.get(cluster=server.cluster) + FirmwareUpgradeSchedule = apps.get_model('caas', 'FirmwareUpgradeSchedule') + try: + firmware_schedule = FirmwareUpgradeSchedule.objects.get(server=server) + # Firmware installation Scheduled and completiong check + status.firmware_scheduled = True if firmware_schedule.date_scheduled else False + status.firmware_upgraded = True if firmware_schedule.date_completed else False + except FirmwareUpgradeSchedule.DoesNotExist: + status.firmware_schedule = False + status.firmware_upgraded = False + except Exception as e: + print(e) + + # Check WindRiver schedule and installation status + WrInstallSchedule = apps.get_model('caas', 'WrInstallSchedule') + try: + wr_schedule = WrInstallSchedule.objects.select_related('cluster').get(cluster=server.cluster) + # WindRiver installation Scheduled and completiong check + status.wr_scheduled = True if wr_schedule.date_scheduled else False + status.wr_installed = True if wr_schedule.date_completed else False + except WrInstallSchedule.DoesNotExist: + status.wr_scheduled = False + status.wr_installed = False + except Exception as e: + print(e) + # Save status object + status.save() + count() + +def orchestration_summary(): + print("**** running cron: orchestration_summary **** : {}".format(datetime.now())) + regions = apps.get_model('orchestration', 'remoteregionsetup') + status = OrchestrationWorkflow() + + # Namespace count and Timestamp + status.namespaces = regions.objects.count() + status.created_at = timezone.now() + + # Service accounts + status.orch_service_account = regions.objects.filter(serviceaccount__in=['orchestration-sa', 'SVC-FE-Atlas']).count() + status.edge_eng_service_account = regions.objects.filter(serviceaccount='SVC-Edge-Eng').count() + regions.objects.filter(serviceaccount__contains='application-sa-').count() + status.samsung_service_account = regions.objects.filter(serviceaccount='samsung-sa').count() + + # Orchestration Kubeconfigs + status.orch_kubeconfig = regions.objects.filter(serviceaccount__in=['orchestration-sa', 'SVC-FE-Atlas']).exclude(kubeconfig='').count() + + # Edge engineering Kubeconfigs + status.edge_eng_kubeconfig = regions.objects.filter(serviceaccount='SVC-Edge-Eng').exclude(kubeconfig='').count() + status.edge_eng_kubeconfig += regions.objects.filter(serviceaccount__contains='application-sa-').exclude(kubeconfig='').count() + + # Samsung Kubeconfigs + status.samsung_kubeconfig= regions.objects.filter(serviceaccount__in=['orchestration-sa', 'SVC-FE-Atlas']).exclude(kubeconfig='').count() + + # Uncomment and use once Dev completes tracking on his side + # Setting to 0 for now + status.data_network_setup = 0 + + status.save() + + + diff --git a/src/automationstatus/migrations/0001_initial.py b/src/automationstatus/migrations/0001_initial.py new file mode 100644 index 0000000..fe2cd95 --- /dev/null +++ b/src/automationstatus/migrations/0001_initial.py @@ -0,0 +1,25 @@ +# Generated by Django 3.1.1 on 2020-09-08 04:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='AutomationStatus', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('playbook_name', models.CharField(blank=True, max_length=255)), + ('status', models.CharField(blank=True, max_length=50)), + ('ilo_host_address', models.CharField(blank=True, max_length=255)), + ('cluster_name', models.CharField(blank=True, max_length=255)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + ), + ] diff --git a/src/automationstatus/migrations/0002_auto_20200908_1720.py b/src/automationstatus/migrations/0002_auto_20200908_1720.py new file mode 100644 index 0000000..12a4044 --- /dev/null +++ b/src/automationstatus/migrations/0002_auto_20200908_1720.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.1 on 2020-09-08 17:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('automationstatus', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='automationstatus', + name='fuze_spm_site_id', + field=models.CharField(blank=True, max_length=255), + ), + migrations.AddField( + model_name='automationstatus', + name='fuze_spm_site_name', + field=models.CharField(blank=True, max_length=255), + ), + ] diff --git a/src/automationstatus/migrations/0003_deploymentworkflow_summary.py b/src/automationstatus/migrations/0003_deploymentworkflow_summary.py new file mode 100644 index 0000000..1fc490f --- /dev/null +++ b/src/automationstatus/migrations/0003_deploymentworkflow_summary.py @@ -0,0 +1,39 @@ +# Generated by Django 3.1.1 on 2020-10-20 01:53 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('caas', '0022_auto_20201001_1232'), + ('automationstatus', '0002_auto_20200908_1720'), + ] + + operations = [ + migrations.CreateModel( + name='DeploymentWorkflow', + fields=[ + ('cluster', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='caas.cluster')), + ('ingested', models.BooleanField(blank=True, default=False, null=True)), + ('online', models.BooleanField(blank=True, default=False, null=True)), + ('bmc', models.BooleanField(blank=True, default=False, null=True)), + ('firmware_wr_scheduling', models.BooleanField(blank=True, default=False, null=True)), + ('firmware_upgraded', models.BooleanField(blank=True, default=False, null=True)), + ('wr_installed', models.BooleanField(blank=True, default=False, null=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='Summary', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('servers', models.PositiveIntegerField()), + ('in_progress', models.PositiveIntegerField()), + ('completed', models.PositiveIntegerField()), + ('failed', models.PositiveIntegerField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + ), + ] diff --git a/src/automationstatus/migrations/0004_auto_20201020_0232.py b/src/automationstatus/migrations/0004_auto_20201020_0232.py new file mode 100644 index 0000000..410f8ac --- /dev/null +++ b/src/automationstatus/migrations/0004_auto_20201020_0232.py @@ -0,0 +1,20 @@ +# Generated by Django 3.1.1 on 2020-10-20 02:32 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('caas', '0022_auto_20201001_1232'), + ('automationstatus', '0003_deploymentworkflow_summary'), + ] + + operations = [ + migrations.AlterField( + model_name='deploymentworkflow', + name='cluster', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='caas.cluster'), + ), + ] diff --git a/src/automationstatus/migrations/0005_auto_20201020_0253.py b/src/automationstatus/migrations/0005_auto_20201020_0253.py new file mode 100644 index 0000000..0ca406f --- /dev/null +++ b/src/automationstatus/migrations/0005_auto_20201020_0253.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.1 on 2020-10-20 02:53 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('automationstatus', '0004_auto_20201020_0232'), + ] + + operations = [ + migrations.RenameField( + model_name='summary', + old_name='servers', + new_name='clusters', + ), + ] diff --git a/src/automationstatus/migrations/0006_auto_20201020_1416.py b/src/automationstatus/migrations/0006_auto_20201020_1416.py new file mode 100644 index 0000000..2e4804b --- /dev/null +++ b/src/automationstatus/migrations/0006_auto_20201020_1416.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.1 on 2020-10-20 14:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('automationstatus', '0005_auto_20201020_0253'), + ] + + operations = [ + migrations.AlterField( + model_name='deploymentworkflow', + name='created_at', + field=models.DateTimeField(blank=True, null=True), + ), + ] diff --git a/src/automationstatus/migrations/0007_auto_20201026_0129.py b/src/automationstatus/migrations/0007_auto_20201026_0129.py new file mode 100644 index 0000000..dd7f547 --- /dev/null +++ b/src/automationstatus/migrations/0007_auto_20201026_0129.py @@ -0,0 +1,33 @@ +# Generated by Django 3.1.1 on 2020-10-26 01:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('automationstatus', '0006_auto_20201020_1416'), + ] + + operations = [ + migrations.RenameField( + model_name='deploymentworkflow', + old_name='firmware_wr_scheduling', + new_name='firmware_scheduled', + ), + migrations.AddField( + model_name='deploymentworkflow', + name='wr_scheduled', + field=models.BooleanField(blank=True, default=False, null=True), + ), + migrations.AlterField( + model_name='summary', + name='created_at', + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AlterField( + model_name='summary', + name='failed', + field=models.PositiveIntegerField(default=0, null=True), + ), + ] diff --git a/src/automationstatus/migrations/0008_auto_20201030_1654.py b/src/automationstatus/migrations/0008_auto_20201030_1654.py new file mode 100644 index 0000000..d775f5d --- /dev/null +++ b/src/automationstatus/migrations/0008_auto_20201030_1654.py @@ -0,0 +1,48 @@ +# Generated by Django 3.1.1 on 2020-10-30 16:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('automationstatus', '0007_auto_20201026_0129'), + ] + + operations = [ + migrations.AddField( + model_name='summary', + name='bmc', + field=models.PositiveIntegerField(default=0, null=True), + ), + migrations.AddField( + model_name='summary', + name='firmware_scheduled', + field=models.PositiveIntegerField(default=0, null=True), + ), + migrations.AddField( + model_name='summary', + name='firmware_upgraded', + field=models.PositiveIntegerField(default=0, null=True), + ), + migrations.AddField( + model_name='summary', + name='ingested', + field=models.PositiveIntegerField(default=0, null=True), + ), + migrations.AddField( + model_name='summary', + name='online', + field=models.PositiveIntegerField(default=0, null=True), + ), + migrations.AddField( + model_name='summary', + name='wr_installed', + field=models.PositiveIntegerField(default=0, null=True), + ), + migrations.AddField( + model_name='summary', + name='wr_scheduled', + field=models.PositiveIntegerField(default=0, null=True), + ), + ] diff --git a/src/automationstatus/migrations/0009_orchestrationworkflow.py b/src/automationstatus/migrations/0009_orchestrationworkflow.py new file mode 100644 index 0000000..78aa2b4 --- /dev/null +++ b/src/automationstatus/migrations/0009_orchestrationworkflow.py @@ -0,0 +1,28 @@ +# Generated by Django 3.1.2 on 2020-12-09 19:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('automationstatus', '0008_auto_20201030_1654'), + ] + + operations = [ + migrations.CreateModel( + name='OrchestrationWorkflow', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('namespaces', models.PositiveIntegerField()), + ('orch_service_account', models.PositiveIntegerField()), + ('edge_eng_service_account', models.PositiveIntegerField()), + ('samsung_service_account', models.PositiveIntegerField()), + ('orch_kubeconfig', models.PositiveIntegerField()), + ('edge_eng_kubeconfig', models.PositiveIntegerField()), + ('samsung_kubeconfig', models.PositiveIntegerField()), + ('data_network_setup', models.PositiveIntegerField()), + ('created_at', models.DateTimeField(blank=True, null=True)), + ], + ), + ] diff --git a/src/automationstatus/migrations/__init__.py b/src/automationstatus/migrations/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/automationstatus/migrations/__init__.py diff --git a/src/automationstatus/models.py b/src/automationstatus/models.py new file mode 100644 index 0000000..9e249c6 --- /dev/null +++ b/src/automationstatus/models.py @@ -0,0 +1,67 @@ +from django.db import models +from caas.models import Cluster + +class AutomationStatus(models.Model): + playbook_name = models.CharField(max_length=255, blank=True, null=False) + status = models.CharField(max_length=50, blank=True, null=False) + ilo_host_address = models.CharField(max_length=255, blank=True, null=False) + cluster_name = models.CharField(max_length=255, blank=True, null=False) + fuze_spm_site_name = models.CharField(max_length=255, blank=True, null=False) + fuze_spm_site_id = models.CharField(max_length=255, blank=True, null=False) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + str = "pk: %s, playbook_name: %s, status: %s, cluster_name: %s, cluster_name: %s, fuze_spm_site_name: %s, fuze_spm_site_id: %s" + return str % (self.pk, self.playbook_name, self.status, self.cluster_name, self.fuze_spm_site_name, self.fuze_spm_site_id, self.created_at) + + +class Summary(models.Model): + clusters = models.PositiveIntegerField(null=False) + in_progress = models.PositiveIntegerField(null=False) + completed = models.PositiveIntegerField(null=False) + ingested = models.PositiveIntegerField(default=0, null=True) + online = models.PositiveIntegerField(default=0, null=True) + bmc = models.PositiveIntegerField(default=0, null=True) + firmware_scheduled = models.PositiveIntegerField(default=0, null=True) + firmware_upgraded = models.PositiveIntegerField(default=0, null=True) + wr_scheduled = models.PositiveIntegerField(default=0, null=True) + wr_installed = models.PositiveIntegerField(default=0, null=True) + failed = models.PositiveIntegerField(default=0, null=True) + created_at = models.DateTimeField(blank=True, null=True) + + def __str__(self): + str = "pk: %s, clusters: %s, in_progress: %s, completed: %s, failed: %s, created_at: %s" + return str % (self.pk, self.clusters, self.in_progress, self.completed, self.failed, self.created_at) + + +class DeploymentWorkflow(models.Model): + cluster = models.OneToOneField("caas.Cluster", on_delete=models.CASCADE, primary_key=True) + ingested = models.BooleanField(blank=True, default=False, null=True) + online = models.BooleanField(blank=True, default=False, null=True) + bmc = models.BooleanField(blank=True, default=False, null=True) + firmware_scheduled = models.BooleanField(blank=True, default=False, null=True) + firmware_upgraded = models.BooleanField(blank=True, default=False, null=True) + wr_scheduled = models.BooleanField(blank=True, default=False, null=True) + wr_installed = models.BooleanField(blank=True, default=False, null=True) + created_at = models.DateTimeField(blank=True, null=True) + + def __str__(self): + str = "pk: %s, cluster: %s, ingested: %s, online: %s, bmc: %s, firmware_upgraded: %s, wr_installed: %s, created_at: %s" + return str % (self.pk, self.cluster, self.ingested, self.online, self.bmc, self.firmware_upgraded, self.wr_installed, self.created_at) + + +class OrchestrationWorkflow(models.Model): + # cluster = models.OneToOneField("caas.Cluster", on_delete=models.CASCADE, primary_key=True) + namespaces = models.PositiveIntegerField(null=False) + orch_service_account = models.PositiveIntegerField(null=False) + edge_eng_service_account = models.PositiveIntegerField(null=False) + samsung_service_account = models.PositiveIntegerField(null=False) + orch_kubeconfig = models.PositiveIntegerField(null=False) + edge_eng_kubeconfig = models.PositiveIntegerField(null=False) + samsung_kubeconfig= models.PositiveIntegerField(null=False) + data_network_setup = models.PositiveIntegerField(null=False) # Update once Dev completes tracking + created_at = models.DateTimeField(blank=True, null=True) + + def __str__(self): + str = "pk: %s, namespaces: %s, created_at: %s" + return str % (self.pk, self.namespaces, self.created_at)
\ No newline at end of file diff --git a/src/automationstatus/serializers.py b/src/automationstatus/serializers.py new file mode 100644 index 0000000..0afdf8c --- /dev/null +++ b/src/automationstatus/serializers.py @@ -0,0 +1,9 @@ +from rest_framework import serializers + +from .models import AutomationStatus + +class AutomationStatusSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = AutomationStatus + fields = ('pk', 'ilo_host_address', 'playbook_name', 'status', 'cluster_name', 'fuze_spm_site_name', 'fuze_spm_site_id', 'created_at') + diff --git a/src/automationstatus/tests.py b/src/automationstatus/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/src/automationstatus/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/src/automationstatus/urls.py b/src/automationstatus/urls.py new file mode 100644 index 0000000..5976610 --- /dev/null +++ b/src/automationstatus/urls.py @@ -0,0 +1,14 @@ +from django.urls import include, path +from rest_framework import routers +from . import views + +router = routers.DefaultRouter() +router.register(r'playbook', views.AutomationStatusViewSet) +router.register(r'playbook/(?P<playbook_name>\d+)', views.AutomationStatusViewSet) + +# Wire up our API using automatic URL routing. +# Additionally, we include login URLs for the browsable API. +urlpatterns = [ + path('', include(router.urls)), + path('', include('rest_framework.urls', namespace='rest_framework')) +]
\ No newline at end of file diff --git a/src/automationstatus/views.py b/src/automationstatus/views.py new file mode 100644 index 0000000..df75868 --- /dev/null +++ b/src/automationstatus/views.py @@ -0,0 +1,19 @@ +from rest_framework import viewsets +from caas.models import Cluster, Location, Server +from .models import AutomationStatus +from .serializers import AutomationStatusSerializer + +class AutomationStatusViewSet(viewsets.ModelViewSet): + queryset = AutomationStatus.objects.all().order_by('created_at') + serializer_class = AutomationStatusSerializer + + def perform_create(self, serializer): + # Lookup cluster name based on the ilo_host_address + server = Server.objects.get(ilo_host_address=self.request.data['ilo_host_address']) + cluster = Cluster.objects.get(id=server.cluster_id) + fuze_id = cluster.location_id + location = Location.objects.get(id=fuze_id) + serializer.save( + cluster_name=cluster.cluster_name, + fuze_spm_site_name=location.fuze_spm_site_name, + fuze_spm_site_id=location.fuze_spm_site_id) |
