From 27c7f1d87b7db7adafda6962c47d1aa4651a9ee4 Mon Sep 17 00:00:00 2001 From: Dave Arnold Date: Wed, 8 Jul 2026 13:40:19 -0400 Subject: [PATCH 1/7] feat: migrate CSVD patch4 module code from CSVD/terraform-csvd-patch4 - Add full module implementation: kms, lambda, logs, outputs, policies, rds, roles, sqs, locals, variables - Add lambda source code: dispatcher, worker, step-result, layer - Add schema/patch40.sql - Update data.tf with comprehensive VPC/SG/subnet lookups - Update versions.tf to require terraform >= 1.0.0 and include archive provider - Update variables.common.tf: remove duplicate 'tags' variable (now in variables.tf) - Remove locals.tf.initial stub (replaced by real locals.tf) --- data.tf | 48 +- kms.tf | 6 + lambda-dispatcher/src/lambda_function.py | 74 + lambda-layer/requirements.txt | 5 + lambda-step-result/src/lambda_function.py | 102 + lambda-worker/src/ec2.py | 120 + lambda-worker/src/lambda_function.py | 131 + lambda.tf | 146 + locals.tf | 50 + locals.tf.initial | 9 - logs.tf | 17 + outputs.tf | 69 + policies.tf | 195 + rds.tf | 43 + roles.tf | 38 + schema/patch40.sql | 4775 +++++++++++++++++++++ sqs.tf | 109 + variables.common.tf | 6 - variables.tf | 89 + versions.tf | 8 +- 20 files changed, 6020 insertions(+), 20 deletions(-) create mode 100644 kms.tf create mode 100644 lambda-dispatcher/src/lambda_function.py create mode 100644 lambda-layer/requirements.txt create mode 100644 lambda-step-result/src/lambda_function.py create mode 100644 lambda-worker/src/ec2.py create mode 100644 lambda-worker/src/lambda_function.py create mode 100644 lambda.tf create mode 100644 locals.tf delete mode 100644 locals.tf.initial create mode 100644 logs.tf create mode 100644 outputs.tf create mode 100644 policies.tf create mode 100644 rds.tf create mode 100644 roles.tf create mode 100644 schema/patch40.sql create mode 100644 sqs.tf create mode 100644 variables.tf diff --git a/data.tf b/data.tf index 16506e6..499adef 100644 --- a/data.tf +++ b/data.tf @@ -1,7 +1,49 @@ +data "aws_partition" "current" {} data "aws_caller_identity" "current" {} +data "aws_region" "current" {} +data "aws_organizations_organization" "org" {} -data "aws_arn" "current" { - arn = data.aws_caller_identity.current.arn +data "aws_db_subnet_group" "patch_db" { + name = var.db_subnet_group_name } -data "aws_region" "current" {} +data "aws_vpcs" "vpcs" { + filter { + name = "tag:Name" + values = [var.vpc_name] + } +} + +data "aws_vpc" "vpcs" { + for_each = toset(data.aws_vpcs.vpcs.ids) + id = each.value +} + +data "aws_security_group" "patch_db_sg" { + name = var.db_security_group_name + filter { + name = "vpc-id" + values = [one(data.aws_vpcs.vpcs.ids)] + } +} + +data "aws_security_group" "patch_lambda_sg" { + name = var.lambda_security_group_name + filter { + name = "vpc-id" + values = [one(data.aws_vpcs.vpcs.ids)] + } +} + +# Lambda functions must deploy into *-apps-* subnets +data "aws_subnets" "apps" { + for_each = data.aws_vpc.vpcs + filter { + name = "tag:Name" + values = ["*-apps-*"] + } + filter { + name = "vpc-id" + values = [each.value.id] + } +} diff --git a/kms.tf b/kms.tf new file mode 100644 index 0000000..3d5be3d --- /dev/null +++ b/kms.tf @@ -0,0 +1,6 @@ +module "patch4_key" { + source = "git@github.e.it.census.gov:terraform-modules/aws-s3.git//kms_key?ref=tf-upgrade" + key_name = var.name_prefix + + tags = merge(local.tags_kms, { Name = local.kms_alias_name }) +} diff --git a/lambda-dispatcher/src/lambda_function.py b/lambda-dispatcher/src/lambda_function.py new file mode 100644 index 0000000..0692d8d --- /dev/null +++ b/lambda-dispatcher/src/lambda_function.py @@ -0,0 +1,74 @@ +import json +import logging +import os +import boto3 +from botocore.exceptions import ClientError + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +# Load the two queue URLs into a hash (dictionary) +QUEUE_MAP = { + 1: os.environ.get('TARGET_SQS_QUEUE_LAMBDA_URL'), # Lambda Workers + 2: os.environ.get('TARGET_SQS_QUEUE_REMOTEEXECUTION_URL'), # Remote Execution +} + +# Validate that all queues are configured +for key, url in QUEUE_MAP.items(): + if not url: + raise ValueError(f"Environment variable for dispatch_type {key} is not set") + +sqs_client = boto3.client('sqs') + +def lambda_handler(event, context): + logger.debug(f"Passed event: {event}") + """ + Dispatches task to the correct SQS queue based on dispatch_type. + Expects a flattened payload from Aurora. + """ + try: + # Aurora sends the JSON directly as the event dict + payload = event if isinstance(event, dict) else json.loads(event) + + uid = payload.get('uid') + dispatch_type = payload.get('dispatch_type') + + if not uid: + raise ValueError("Missing required field: uid") + if dispatch_type not in QUEUE_MAP: + raise ValueError(f"Invalid dispatch_type: {dispatch_type}. Must be 1, 2, or 3.") + + queue_url = QUEUE_MAP[dispatch_type] + + logger.info(f"Dispatching task - uid={uid} | dispatch_type={dispatch_type} | queue={queue_url}") + + # ADJUSTMENT: Since the procedure is flattened, 'payload' IS the work data. + # We send the entire payload to SQS so the Worker sees all columns. + message_body = payload + + # Send to the correct SQS queue + response = sqs_client.send_message( + QueueUrl=queue_url, + MessageBody=json.dumps(message_body) + ) + + message_id = response.get('MessageId') + if not message_id: + raise ValueError("SQS returned no MessageId") + + logger.info(f"Successfully enqueued task uid={uid} to queue_url={queue_url} → MessageId={message_id}") + + return { + "success": True, + "messageId": message_id + } + + except ClientError as e: + error_msg = f"SQS ClientError: {e.response['Error']['Message']}" + logger.error(error_msg, exc_info=True) + return {"success": False, "error": error_msg} + + except Exception as e: + error_msg = f"Unexpected error dispatching task: {str(e)}" + logger.exception(error_msg) + return {"success": False, "error": error_msg} \ No newline at end of file diff --git a/lambda-layer/requirements.txt b/lambda-layer/requirements.txt new file mode 100644 index 0000000..f0ddc6b --- /dev/null +++ b/lambda-layer/requirements.txt @@ -0,0 +1,5 @@ +aws_advanced_python_wrapper==2.1.0 +psycopg==3.2.13 +psycopg-binary==3.2.13 +psycopg-pool==3.3.0 +typing_extensions \ No newline at end of file diff --git a/lambda-step-result/src/lambda_function.py b/lambda-step-result/src/lambda_function.py new file mode 100644 index 0000000..92b54e5 --- /dev/null +++ b/lambda-step-result/src/lambda_function.py @@ -0,0 +1,102 @@ +import boto3 +import logging +import json +import psycopg +import os +from psycopg import OperationalError, InterfaceError +import time + +# Enhanced Logging Setup +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) + +# Persistent connection variable +db_connection = None + +def get_iam_token(): + # RDS client to generate the auth token + client = boto3.client('rds', region_name=os.environ.get('AWS_REGION', os.getenv("dbRegion"))) + + return client.generate_db_auth_token( + DBHostname=os.getenv("dbEndpoint"), + Port=5432, + DBUsername=os.getenv("dbUsername"), + Region=os.getenv("dbRegion") + ) + +def get_connection(): + global db_connection + + # Check if existing connection is alive + if db_connection is not None: + if db_connection.closed or db_connection.broken: + db_connection = None + else: + try: + db_connection.execute("SELECT 1") + return db_connection + except (OperationalError, Exception): + db_connection = None + + # Retry Logic Configuration + max_retries = 3 + retry_delay = 0.5 # Initial delay in seconds + + for attempt in range(max_retries): + try: + print(f"Connection attempt {attempt + 1}...") + + db_connection = psycopg.connect( + host=os.getenv("dbEndpoint"), + dbname=os.getenv("dbDatabase"), + user=os.getenv("dbUsername"), + password=get_iam_token(), + sslmode='require', + connect_timeout=5 # How long to wait for the TCP handshake + ) + db_connection.autocommit = True + print("Connection established successfully.") + return db_connection + + except OperationalError as e: + print(f"Attempt {attempt + 1} failed: {e}") + if attempt < max_retries - 1: + time.sleep(retry_delay) + retry_delay *= 2 # Exponential backoff (0.5s, 1s, 2s) + else: + raise e # Exhausted retries +def executeSql(sql, sqldata = None): + conn = get_connection() + cursor = conn.cursor() + cursor.execute(sql, sqldata) + conn.commit() + cursor.close() + conn.close() + +def executeSqlWithReturn(sql, sqldata = None): + conn = get_connection() + cursor = conn.cursor() + cursor.execute(sql, sqldata) + columns = [i[0] for i in cursor.description] + result = [dict(zip(columns, row)) for row in cursor.fetchall()] + conn.commit() + cursor.close() + conn.close() + return result + +def lambda_handler(event, context): + logger.debug(json.dumps(event)) + body = json.loads(event['Records'][0]['body']) + #logger.debug(f"Processing body: {body}") + + try: + loggit = executeSql("CALL patch40.sp_step_update(%s::bigint, %s::integer)", + (int(body['uid']), int(body['status_code']))) + except Exception as e: + raise e + return { + 'statusCode': 200, + 'Payload': { + 'status': 'SUCCESS' + } + } diff --git a/lambda-worker/src/ec2.py b/lambda-worker/src/ec2.py new file mode 100644 index 0000000..a30b397 --- /dev/null +++ b/lambda-worker/src/ec2.py @@ -0,0 +1,120 @@ +import boto3 +import logging +from botocore.config import Config +from botocore.exceptions import ClientError + +logger = logging.getLogger(__name__) + +# Global session cache for warm-start reuse +_session_cache = {} + +class ec2: + @staticmethod + def assumedRoleSession(account, region): + cache_key = f"{account}-{region}" + if cache_key in _session_cache: + return _session_cache[cache_key] + + botoconf = Config(region_name=region, retries={'max_attempts': 5, 'mode': 'standard'}) + sts = boto3.client('sts', region_name=region, config=botoconf) + + sts_role_arn = f"arn:aws-us-gov:iam::{account}:role/r-inf-patch" + sts_session_name = f"patch_session_{account}" + + try: + # CHANGED: Ensure this variable name matches the one used below + sts_response = sts.assume_role( + RoleArn=sts_role_arn, + RoleSessionName=sts_session_name + ) + + new_session = boto3.Session( + region_name=region, + aws_access_key_id=sts_response['Credentials']['AccessKeyId'], + aws_secret_access_key=sts_response['Credentials']['SecretAccessKey'], + aws_session_token=sts_response['Credentials']['SessionToken'] + ) + + _session_cache[cache_key] = new_session + return new_session + except Exception as e: + logger.error(f"Error assuming role for {account}: {e}") + raise + + @staticmethod + def getStopProtection(event): + try: + session = ec2.assumedRoleSession(account=event['accountid'], region=event['region']) + client = session.client('ec2') + response = client.describe_instance_attribute( + Attribute='disableApiStop', + InstanceId=event['instanceid'] + ) + state = response['DisableApiStop']['Value'] + return 2925 if state else 2930 # 2925=Enabled, 2930=Disabled + except ClientError as e: + return 4920 if "does not exist" in str(e) else 4000 + except Exception: + return 4000 + + @staticmethod + def getRunState(event): + try: + session = ec2.assumedRoleSession(account=event['accountid'], region=event['region']) + client = session.client('ec2') + response = client.describe_instances(InstanceIds=[event['instanceid']]) + state = response['Reservations'][0]['Instances'][0]['State']['Name'] + return 2905 if state == "running" else 2910 + except ClientError as e: + return 4920 if "does not exist" in str(e) else 4000 + except Exception: + return 4000 + + @staticmethod + def startInstance(event): + try: + session = ec2.assumedRoleSession(account=event['accountid'], region=event['region']) + client = session.client('ec2') + client.start_instances(InstanceIds=[event['instanceid']]) + return 2000 # Success + except ClientError as e: + return 4920 if "does not exist" in str(e) else 4000 + except Exception: + return 4000 + + @staticmethod + def stopInstance(event): + try: + session = ec2.assumedRoleSession(account=event['accountid'], region=event['region']) + client = session.client('ec2') + client.stop_instances(InstanceIds=[event['instanceid']]) + return 2000 # Success + except ClientError as e: + return 4920 if "does not exist" in str(e) else 4000 + except Exception as e: + logger.exception("Exception: %s" % (str(e))) + return 4000 + + @staticmethod + def setStopProtection(event): + try: + session = ec2.assumedRoleSession(account=event['accountid'], region=event['region']) + client = session.client('ec2') + client.modify_instance_attribute(DisableApiStop={'Value': True}, InstanceId=event['instanceid']) + return 2000 # Success + except ClientError as e: + return 4920 if "does not exist" in str(e) else 4000 + except Exception: + return 4000 + + @staticmethod + def removeStopProtection(event): + try: + session = ec2.assumedRoleSession(account=event['accountid'], region=event['region']) + client = session.client('ec2') + client.modify_instance_attribute(DisableApiStop={'Value': False}, InstanceId=event['instanceid']) + return 2000 # Success + except ClientError as e: + return 4920 if "does not exist" in str(e) else 4000 + except Exception: + return 4000 \ No newline at end of file diff --git a/lambda-worker/src/lambda_function.py b/lambda-worker/src/lambda_function.py new file mode 100644 index 0000000..0032dd5 --- /dev/null +++ b/lambda-worker/src/lambda_function.py @@ -0,0 +1,131 @@ +import boto3 +from ec2 import ec2 +import logging +import json +import psycopg +import os +from psycopg import OperationalError, InterfaceError +import time + +# Logging Setup +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) # DEBUG is noisy in prod, INFO is usually better + +# Status constants +STATUS_QUEUED = 0 +STATUS_PROCESSING = 1010 +STATUS_ERROR = 4000 + +# Persistent connection variable +db_connection = None + +# SQS Client +sqs = boto3.client('sqs') + +def get_iam_token(): + # RDS client to generate the auth token + client = boto3.client('rds', region_name=os.environ.get('AWS_REGION', os.getenv("dbRegion"))) + + return client.generate_db_auth_token( + DBHostname=os.getenv("dbEndpoint"), + Port=5432, + DBUsername=os.getenv("dbUsername"), + Region=os.getenv("dbRegion") + ) + +def get_connection(): + global db_connection + + # Check if existing connection is alive + if db_connection is not None: + if db_connection.closed or db_connection.broken: + db_connection = None + else: + try: + db_connection.execute("SELECT 1") + return db_connection + except (OperationalError, Exception): + db_connection = None + + # Retry Logic Configuration + max_retries = 3 + retry_delay = 0.5 # Initial delay in seconds + + for attempt in range(max_retries): + try: + print(f"Connection attempt {attempt + 1}...") + + db_connection = psycopg.connect( + host=os.getenv("dbEndpoint"), + dbname=os.getenv("dbDatabase"), + user=os.getenv("dbUsername"), + password=get_iam_token(), + sslmode='require', + connect_timeout=5 # How long to wait for the TCP handshake + ) + db_connection.autocommit = True + print("Connection established successfully.") + return db_connection + + except OperationalError as e: + print(f"Attempt {attempt + 1} failed: {e}") + if attempt < max_retries - 1: + time.sleep(retry_delay) + retry_delay *= 2 # Exponential backoff (0.5s, 1s, 2s) + else: + raise e # Exhausted retries +def process_message(body: dict): + automation = body.get('automation', '') + if not automation: + return 4005 # NO_MATCHING_ACTION + + task_parts = automation.split("-") + if len(task_parts) >= 3 and task_parts[0] == 'lambda': + class_str = task_parts[1] + method_name = task_parts[2] + + # Pull class from globals + target_class = globals().get(class_str) + if not target_class: + logger.error(f"Class '{class_str}' not found in globals.") + return 4001 + + # Look for the static method + dynamic_method = getattr(target_class, method_name, None) + if not dynamic_method: + logger.error(f"Method '{method_name}' not found in class '{class_str}'.") + return 4002 + + return dynamic_method(body) + return 4005 + +def lambda_handler(event, context): + try: + body = json.loads(event.get('Records')[0]['body']) + logger.info(f"Incoming event: {event}") + conn = get_connection() + # In psycopg3, you can execute directly on the connection for simple queries + # or use the context manager for cursors. + with conn.cursor() as cur: + cur.execute("UPDATE patch40.executions SET statusid = %s WHERE uid = %s;",(STATUS_PROCESSING, body['uid'])) + sqs.delete_message( + QueueUrl = os.getenv("input_queue_url"), + ReceiptHandle = event['Records'][0]['receiptHandle'] + ) + my_status = process_message(body) + with conn.cursor() as cur: + cur.execute("CALL patch40.sp_step_update(%s,%s)", (body['uid'], my_status)) + return { + "statusCode": 200, + "body": f"Put something here" + } + except Exception as e: + print(f"Connection or Query failed: {e}") + global db_connection + if db_connection: + try: + db_connection.close() + except: + pass + db_connection = None + raise e \ No newline at end of file diff --git a/lambda.tf b/lambda.tf new file mode 100644 index 0000000..8438faa --- /dev/null +++ b/lambda.tf @@ -0,0 +1,146 @@ +data "archive_file" "dispatcher" { + type = "zip" + source_dir = "${path.module}/lambda-dispatcher" + output_path = "${path.module}/builds/dispatcher.zip" +} + +data "archive_file" "step_result" { + type = "zip" + source_dir = "${path.module}/lambda-step-result" + output_path = "${path.module}/builds/step-result.zip" +} + +data "archive_file" "worker" { + type = "zip" + source_dir = "${path.module}/lambda-worker" + output_path = "${path.module}/builds/worker.zip" +} + +module "lambda_layer" { + source = "terraform-aws-modules/lambda/aws" + version = "~> 7.0" + + create_function = false + create_layer = true + layer_name = local.lambda_layer_name + + runtime = "python" + compatible_architectures = ["arm64"] + compatible_runtimes = [var.lambda_runtime] + + source_path = [ + { + path = "${path.module}/lambda-layer" + pip_requirements = true + prefix_in_zip = "python" + } + ] +} + +resource "aws_lambda_function" "dispatcher" { + function_name = local.lambda_dispatcher_name + role = module.patch_execution_role.role_arn + handler = "lambda_function.lambda_handler" + runtime = var.lambda_runtime + architectures = ["arm64"] + package_type = "Zip" + + filename = data.archive_file.dispatcher.output_path + source_code_hash = data.archive_file.dispatcher.output_base64sha256 + + timeout = 20 + memory_size = 256 + + vpc_config { + subnet_ids = flatten([for s in data.aws_subnets.apps : s.ids]) + security_group_ids = [data.aws_security_group.patch_lambda_sg.id] + ipv6_allowed_for_dual_stack = false + } + + environment { + variables = { + TARGET_SQS_QUEUE_LAMBDA_URL = aws_sqs_queue.dispatch_lambda.url + TARGET_SQS_QUEUE_REMOTEEXECUTION_URL = aws_sqs_queue.dispatch_remote_execution.url + } + } + + ephemeral_storage { size = 512 } + tracing_config { mode = "PassThrough" } + + logging_config { + log_format = "Text" + log_group = aws_cloudwatch_log_group.dispatcher.name + } + + tags = local.tags_lambda +} + +resource "aws_lambda_function" "step_result" { + function_name = local.lambda_step_result_name + role = module.patch_execution_role.role_arn + handler = "lambda_function.lambda_handler" + runtime = var.lambda_runtime + architectures = ["arm64"] + package_type = "Zip" + + filename = data.archive_file.step_result.output_path + source_code_hash = data.archive_file.step_result.output_base64sha256 + + timeout = 20 + memory_size = 128 + layers = [module.lambda_layer.lambda_layer_arn] + + vpc_config { + subnet_ids = flatten([for s in data.aws_subnets.apps : s.ids]) + security_group_ids = [data.aws_security_group.patch_lambda_sg.id] + ipv6_allowed_for_dual_stack = false + } + + ephemeral_storage { size = 512 } + tracing_config { mode = "PassThrough" } + + logging_config { + log_format = "Text" + log_group = aws_cloudwatch_log_group.step_result.name + } + + tags = local.tags_lambda +} + +resource "aws_lambda_function" "worker" { + function_name = local.lambda_worker_name + role = module.patch_execution_role.role_arn + handler = "lambda_function.lambda_handler" + runtime = var.lambda_runtime + architectures = ["arm64"] + package_type = "Zip" + + filename = data.archive_file.worker.output_path + source_code_hash = data.archive_file.worker.output_base64sha256 + + timeout = 180 + memory_size = 128 + layers = [module.lambda_layer.lambda_layer_arn] + + vpc_config { + subnet_ids = flatten([for s in data.aws_subnets.apps : s.ids]) + security_group_ids = [data.aws_security_group.patch_lambda_sg.id] + ipv6_allowed_for_dual_stack = false + } + + environment { + variables = { + RESULTS_QUEUE_URL = aws_sqs_queue.results.url + } + } + + ephemeral_storage { size = 512 } + tracing_config { mode = "PassThrough" } + + logging_config { + log_format = "Text" + log_group = aws_cloudwatch_log_group.worker_lambda.name + } + + tags = local.tags_lambda +} diff --git a/locals.tf b/locals.tf new file mode 100644 index 0000000..dc8f1d2 --- /dev/null +++ b/locals.tf @@ -0,0 +1,50 @@ +locals { + # ─── Tagging ──────────────────────────────────────────────────────────────── + finops_tags = { + finops_project_name = var.finops_project_name + finops_project_number = var.finops_project_number + } + + base_tags = merge({ "boc:created_by" = "terraform" }, var.tags) + + tags_rds = merge(local.base_tags, local.finops_tags, { finops_project_role = "${var.name_prefix}_rds" }) + tags_kms = merge(local.base_tags, local.finops_tags, { finops_project_role = "${var.name_prefix}_kms" }) + tags_sqs = merge(local.base_tags, local.finops_tags, { finops_project_role = "${var.name_prefix}_sqs" }) + tags_lambda = merge(local.base_tags, local.finops_tags, { finops_project_role = "${var.name_prefix}_lambda" }) + tags_cloudwatch = merge(local.base_tags, local.finops_tags, { finops_project_role = "${var.name_prefix}_cloudwatch" }) + tags_iam = merge(local.base_tags, local.finops_tags, { finops_project_role = "${var.name_prefix}_iam" }) + + # ─── Resource Names ───────────────────────────────────────────────────────── + lambda_dispatcher_name = "${var.name_prefix}-dispatcher" + lambda_step_result_name = "${var.name_prefix}-step-result" + lambda_worker_name = "${var.name_prefix}-worker-lambda" + lambda_layer_name = "${var.name_prefix}-layer-v1" + + sqs_dispatch_lambda_name = "${var.name_prefix}-dispatch-lambda" + sqs_dispatch_remote_execution_name = "${var.name_prefix}-dispatch-remote-execution" + sqs_results_name = "${var.name_prefix}-results" + + db_cluster_name = var.name_prefix + db_instance_name = "${var.name_prefix}-instance-1" + db_name = replace("${var.name_prefix}_db", "-", "_") + db_user_name = "${replace(var.name_prefix, "-", "")}lambda_iam" + + kms_alias_name = "k-kms-${var.name_prefix}" + + patch_role_name = "r-${var.name_prefix}" + patch_execution_role_name = "r-${var.name_prefix}-execution" + patch_execproxy_role_name = "r-${var.name_prefix}-execproxy" + + patch_policy_name = "p-${var.name_prefix}" + patch_execution_policy_name = "p-${var.name_prefix}-execution" + patch_execproxy_policy_name = "p-${var.name_prefix}-execproxy" + + log_group_dispatcher = "/aws/lambda/${local.lambda_dispatcher_name}" + log_group_step_result = "/aws/lambda/${local.lambda_step_result_name}" + log_group_worker = "/aws/lambda/${local.lambda_worker_name}" + + # ─── ARN helpers ──────────────────────────────────────────────────────────── + partition = data.aws_partition.current.partition + account_id = data.aws_caller_identity.current.account_id + region = data.aws_region.current.name +} diff --git a/locals.tf.initial b/locals.tf.initial deleted file mode 100644 index 2bd4d7f..0000000 --- a/locals.tf.initial +++ /dev/null @@ -1,9 +0,0 @@ -locals { - account_id = var.account_id != "" ? var.account_id : data.aws_caller_identity.current.account_id - account_environment = data.aws_arn.current.partition == "aws-us-gov" ? "gov" : "ew" - - base_tags = { - "boc:tf_module_version" = local._module_version - "boc:created_by" = "terraform" - } -} diff --git a/logs.tf b/logs.tf new file mode 100644 index 0000000..5fdf2e4 --- /dev/null +++ b/logs.tf @@ -0,0 +1,17 @@ +resource "aws_cloudwatch_log_group" "dispatcher" { + name = local.log_group_dispatcher + retention_in_days = var.log_retention_days + tags = local.tags_cloudwatch +} + +resource "aws_cloudwatch_log_group" "step_result" { + name = local.log_group_step_result + retention_in_days = var.log_retention_days + tags = local.tags_cloudwatch +} + +resource "aws_cloudwatch_log_group" "worker_lambda" { + name = local.log_group_worker + retention_in_days = var.log_retention_days + tags = local.tags_cloudwatch +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..4d6f089 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,69 @@ +output "rds_cluster_endpoint" { + description = "Writer endpoint for the Aurora PostgreSQL cluster" + value = aws_rds_cluster.patch4.endpoint +} + +output "rds_cluster_id" { + description = "Cluster identifier" + value = aws_rds_cluster.patch4.id +} + +output "rds_cluster_arn" { + description = "Cluster ARN" + value = aws_rds_cluster.patch4.arn +} + +output "db_user_name" { + description = "IAM DB auth username used by Lambda to connect to RDS" + value = local.db_user_name +} + +output "kms_key_arn" { + description = "ARN of the KMS key used to encrypt RDS and other resources" + value = module.patch4_key.kms_key_arn +} + +output "lambda_dispatcher_arn" { + description = "ARN of the dispatcher Lambda function" + value = aws_lambda_function.dispatcher.arn +} + +output "lambda_worker_arn" { + description = "ARN of the worker Lambda function" + value = aws_lambda_function.worker.arn +} + +output "lambda_step_result_arn" { + description = "ARN of the step-result Lambda function" + value = aws_lambda_function.step_result.arn +} + +output "sqs_dispatch_lambda_url" { + description = "URL of the Lambda dispatch SQS queue" + value = aws_sqs_queue.dispatch_lambda.url +} + +output "sqs_dispatch_remote_execution_url" { + description = "URL of the remote-execution dispatch SQS queue" + value = aws_sqs_queue.dispatch_remote_execution.url +} + +output "sqs_results_url" { + description = "URL of the results SQS queue" + value = aws_sqs_queue.results.url +} + +output "patch_role_arn" { + description = "ARN of the patch role assumed in target accounts" + value = module.patch_role.role_arn +} + +output "patch_execution_role_arn" { + description = "ARN of the patch execution role assumed by Lambda" + value = module.patch_execution_role.role_arn +} + +output "patch_execproxy_instance_profile_name" { + description = "Name of the EC2 instance profile for the p4proxy host" + value = module.patch_execproxy_role.instance_profile_name +} diff --git a/policies.tf b/policies.tf new file mode 100644 index 0000000..4c317f8 --- /dev/null +++ b/policies.tf @@ -0,0 +1,195 @@ +# ─── Assume-role policy documents ──────────────────────────────────────────── + +data "aws_iam_policy_document" "patch_role_assume" { + statement { + sid = "AllowAssumeRoleFromPatchAcct" + effect = "Allow" + actions = ["sts:AssumeRole"] + principals { + type = "AWS" + identifiers = ["arn:${local.partition}:iam::${local.account_id}:root"] + } + condition { + test = "ArnLike" + variable = "aws:PrincipalArn" + values = ["arn:${local.partition}:iam::${local.account_id}:role/${local.patch_execution_role_name}"] + } + condition { + test = "ForAnyValue:StringLike" + variable = "aws:PrincipalOrgPaths" + values = ["${data.aws_organizations_organization.org.id}/*"] + } + } +} + +data "aws_iam_policy_document" "patch_execution_role_assume" { + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + } + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + principals { + type = "AWS" + identifiers = ["arn:${local.partition}:iam::${local.account_id}:role/${local.patch_execproxy_role_name}"] + } + } +} + +data "aws_iam_policy_document" "patch_execproxy_role_assume" { + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + principals { + type = "Service" + identifiers = ["ec2.amazonaws.com"] + } + } + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + principals { + type = "Service" + identifiers = ["ssm.amazonaws.com"] + } + } +} + +# ─── IAM policy documents ───────────────────────────────────────────────────── + +data "aws_iam_policy_document" "patch_role" { + statement { + sid = "DescribeRunStateAndStopProtection" + effect = "Allow" + actions = [ + "ec2:DescribeInstances", + "ec2:DescribeInstanceAttribute", + "ec2:DescribeTags", + "ec2:StartInstances", + "ec2:StopInstances", + ] + resources = ["*"] + } + statement { + sid = "ModifyOnlyStopProtection" + effect = "Allow" + actions = ["ec2:ModifyInstanceAttribute"] + resources = ["*"] + condition { + test = "StringEquals" + variable = "ec2:Attribute/disableApiStop" + values = ["true", "false"] + } + } +} + +data "aws_iam_policy_document" "patch_execution_role" { + statement { + sid = "AllowInvokePatchFunctions" + effect = "Allow" + actions = ["lambda:InvokeFunction"] + resources = [ + "arn:${local.partition}:lambda:${local.region}:${local.account_id}:function/${local.lambda_dispatcher_name}", + "arn:${local.partition}:lambda:${local.region}:${local.account_id}:function/${local.lambda_worker_name}", + "arn:${local.partition}:lambda:${local.region}:${local.account_id}:function/${local.lambda_step_result_name}", + ] + } + statement { + sid = "AllowCloudWatchLogsForPatchLambdas" + effect = "Allow" + actions = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ] + # Scoped to log groups owned by this module + resources = [ + "arn:${local.partition}:logs:${local.region}:${local.account_id}:log-group:/aws/lambda/${var.name_prefix}*", + ] + } + statement { + sid = "AllowEC2NetworkInterfaceForVpc" + effect = "Allow" + actions = [ + "ec2:CreateNetworkInterface", + "ec2:DescribeNetworkInterfaces", + "ec2:DeleteNetworkInterface", + ] + resources = ["*"] + } + statement { + sid = "AllowSQSPatchQueues" + effect = "Allow" + actions = [ + "sqs:SendMessage", + "sqs:ReceiveMessage", + "sqs:DeleteMessage", + "sqs:GetQueueAttributes", + "sqs:ChangeMessageVisibility", + ] + resources = [ + aws_sqs_queue.dispatch_lambda.arn, + aws_sqs_queue.dispatch_remote_execution.arn, + aws_sqs_queue.results.arn, + ] + } + statement { + sid = "AssumePatchRoleInTargetAccount" + effect = "Allow" + actions = ["sts:AssumeRole"] + resources = [module.patch_role.role_arn] + } + statement { + sid = "AccessPatchDb" + effect = "Allow" + actions = ["rds-db:connect"] + resources = [ + "arn:${local.partition}:rds-db:${local.region}:${local.account_id}:dbuser:cluster-*/${local.db_user_name}", + ] + } +} + +data "aws_iam_policy_document" "patch_execproxy_role" { + statement { + sid = "AccessPatchDb" + effect = "Allow" + actions = ["rds-db:connect"] + resources = [ + "arn:${local.partition}:rds-db:${local.region}:${local.account_id}:dbuser:cluster-*/${local.db_user_name}", + ] + } + statement { + sid = "AssumePatchExecutionRole" + effect = "Allow" + actions = ["sts:AssumeRole"] + resources = [module.patch_execution_role.role_arn] + } +} + +# ─── IAM Policies ──────────────────────────────────────────────────────────── + +resource "aws_iam_policy" "patch_role" { + name = local.patch_policy_name + description = "Policy attached to ${local.patch_role_name}: allows EC2 describe/start/stop for patching targets" + policy = data.aws_iam_policy_document.patch_role.json + tags = local.tags_iam +} + +resource "aws_iam_policy" "patch_execution_role" { + name = local.patch_execution_policy_name + description = "Policy attached to ${local.patch_execution_role_name}: allows Lambda invocation, SQS access, RDS IAM auth, and cross-account role assumption" + policy = data.aws_iam_policy_document.patch_execution_role.json + tags = local.tags_iam +} + +resource "aws_iam_policy" "patch_execproxy_role" { + name = local.patch_execproxy_policy_name + description = "Policy attached to ${local.patch_execproxy_role_name}: allows RDS IAM authentication for the execproxy EC2 host" + policy = data.aws_iam_policy_document.patch_execproxy_role.json + tags = local.tags_iam +} diff --git a/rds.tf b/rds.tf new file mode 100644 index 0000000..a201216 --- /dev/null +++ b/rds.tf @@ -0,0 +1,43 @@ +resource "aws_rds_cluster" "patch4" { + backup_retention_period = 7 + cluster_identifier = local.db_cluster_name + copy_tags_to_snapshot = true + database_name = local.db_name + db_subnet_group_name = data.aws_db_subnet_group.patch_db.name + deletion_protection = false + engine = "aurora-postgresql" + engine_version = var.db_engine_version + iam_database_authentication_enabled = true + kms_key_id = module.patch4_key.kms_key_arn + manage_master_user_password = true + master_username = "postgres" + preferred_backup_window = var.preferred_backup_window + preferred_maintenance_window = var.preferred_maintenance_window + skip_final_snapshot = true + storage_encrypted = true + vpc_security_group_ids = [data.aws_security_group.patch_db_sg.id] + + serverlessv2_scaling_configuration { + min_capacity = 0.5 + max_capacity = 1.0 + } + + tags = local.tags_rds +} + +resource "aws_rds_cluster_instance" "patch4" { + auto_minor_version_upgrade = true + cluster_identifier = aws_rds_cluster.patch4.id + copy_tags_to_snapshot = true + db_parameter_group_name = var.db_parameter_group_name + db_subnet_group_name = data.aws_db_subnet_group.patch_db.name + engine = aws_rds_cluster.patch4.engine + engine_version = aws_rds_cluster.patch4.engine_version + identifier = local.db_instance_name + instance_class = "db.serverless" + performance_insights_enabled = false + promotion_tier = 1 + publicly_accessible = false + + tags = local.tags_rds +} diff --git a/roles.tf b/roles.tf new file mode 100644 index 0000000..53f17a5 --- /dev/null +++ b/roles.tf @@ -0,0 +1,38 @@ +# patch_role — assumed by patch_execution_role to perform EC2 operations in target accounts +module "patch_role" { + source = "git::https://github.e.it.census.gov/terraform-modules/aws-iam-role.git?ref=tf-upgrade" + + role_name = local.patch_role_name + role_description = "Assumed by ${local.patch_execution_role_name} to execute patching operations on EC2 instances in target accounts" + assume_policy_document = data.aws_iam_policy_document.patch_role_assume.json + attached_policies = [aws_iam_policy.patch_role.arn] + + tags = local.tags_iam +} + +# patch_execution_role — assumed by Lambda functions to orchestrate patching +module "patch_execution_role" { + source = "git::https://github.e.it.census.gov/terraform-modules/aws-iam-role.git?ref=tf-upgrade" + + role_name = local.patch_execution_role_name + role_description = "Assumed by Lambda functions to invoke patch operations, access SQS/RDS, and assume ${local.patch_role_name} in target accounts" + assume_policy_document = data.aws_iam_policy_document.patch_execution_role_assume.json + attached_policies = [aws_iam_policy.patch_execution_role.arn] + + tags = local.tags_iam +} + +# patch_execproxy_role — applied to the EC2 execproxy host (p4proxy service) +# This instance profile is used by the EC2 host running p4proxy to authenticate +# to RDS via IAM and to assume patch_execution_role for orchestration tasks. +module "patch_execproxy_role" { + source = "git::https://github.e.it.census.gov/terraform-modules/aws-iam-role.git?ref=tf-upgrade" + + role_name = local.patch_execproxy_role_name + role_description = "Applied to the EC2 host running p4proxy; allows RDS IAM auth and assumption of ${local.patch_execution_role_name}" + assume_policy_document = data.aws_iam_policy_document.patch_execproxy_role_assume.json + attached_policies = [aws_iam_policy.patch_execproxy_role.arn] + enable_instance_profile = true + + tags = local.tags_iam +} diff --git a/schema/patch40.sql b/schema/patch40.sql new file mode 100644 index 0000000..11650c4 --- /dev/null +++ b/schema/patch40.sql @@ -0,0 +1,4775 @@ +-- +-- PostgreSQL database dump +-- + +\restrict zAxR96Kp0drTyUOpXNPqmViRJ0UJNgQlGeXnUvBbWYZbVBmfaLz4uIrtA3AynJr + +-- Dumped from database version 15.15 +-- Dumped by pg_dump version 18.2 + +-- Started on 2026-05-22 14:00:35 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET transaction_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- TOC entry 36 (class 2615 OID 29331) +-- Name: patch40; Type: SCHEMA; Schema: -; Owner: postgres +-- + +CREATE SCHEMA patch40; + + +ALTER SCHEMA patch40 OWNER TO postgres; + +-- +-- TOC entry 1152 (class 1247 OID 29334) +-- Name: typ_ec2_inventory; Type: TYPE; Schema: patch40; Owner: postgres +-- + +CREATE TYPE patch40.typ_ec2_inventory AS ( + collectiondate date, + accountid bigint, + instanceid character varying(50), + nametag character varying(128), + reservationid character varying(50), + region character varying(20), + launchtime timestamp without time zone, + privateipaddress character varying(30), + state character varying(20), + collectiontime timestamp without time zone +); + + +ALTER TYPE patch40.typ_ec2_inventory OWNER TO postgres; + +-- +-- TOC entry 1153 (class 1247 OID 29337) +-- Name: typ_schedule_waiver; Type: TYPE; Schema: patch40; Owner: postgres +-- + +CREATE TYPE patch40.typ_schedule_waiver AS ( + cycleid bigint, + cycle character(7), + start date, + requester character varying(128), + notes character varying(2048) +); + + +ALTER TYPE patch40.typ_schedule_waiver OWNER TO postgres; + +-- +-- TOC entry 348 (class 1255 OID 29340) +-- Name: bak_offsetpatchtuesday(integer); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.bak_offsetpatchtuesday(_adjuster integer) RETURNS date + LANGUAGE plpgsql + AS $$ + + DECLARE + cpt date; + fday varchar(20); + _indate date; + tcounter int := 0; + BEGIN + _inDate := patch40.currentpatchtuesday() + _adjuster * INTERVAL '1 month'; + --fday := to_char(now(), 'YYYYMM01'); + fday := to_char(_inDate, 'YYYYMM01'); + cpt := to_date(fday, 'YYYYMMDD'); + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + WHILE tcounter < 2 LOOP + cpt := cpt + 1; + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + END LOOP; + IF now() < cpt THEN + tcounter := 0; + fday := to_char(cpt - interval '1 month', 'YYYYMM01'); + cpt := to_date(fday, 'YYYYMMDD'); + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + WHILE tcounter < 2 LOOP + cpt := cpt + 1; + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + END LOOP; + END IF; + RETURN cpt; + END; + +$$; + + +ALTER FUNCTION patch40.bak_offsetpatchtuesday(_adjuster integer) OWNER TO postgres; + +-- +-- TOC entry 349 (class 1255 OID 29341) +-- Name: bak_slotLabelFromDate(timestamp without time zone); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40."bak_slotLabelFromDate"(indate timestamp without time zone) RETURNS character varying + LANGUAGE plpgsql + AS $$ +DECLARE + tcounter integer := 0; + thisTuesday date := patch40.currentpatchtuesday(); +BEGIN + WHILE thisTuesday <= now() LOOP + IF to_char(thisTuesday, 'DY') = to_char(inDate, 'DY') THEN + tcounter = tcounter + 1; + END IF; + thisTuesday = thisTuesday + 1; + END LOOP; + IF to_char(inDate, 'DY') = 'TUE' THEN + tcounter = tcounter - 1; + END IF; + DROP TABLE IF EXISTS tmp_iteration; + CREATE TEMP TABLE IF NOT EXISTS tmp_iteration( + id serial PRIMARY KEY, + iterate char(2) + ); + + INSERT INTO + tmp_iteration (iterate) + VALUES + ('th'), + ('st'), + ('nd'), + ('rd'), + ('th'), + ('th'), + ('th'), + ('th'); + --RETURN (SELECT iterate FROM tmp_iteration where (id - 1) = extract(isodow from inDate)); + --RETURN to_char(inDate, 'DY'); + RETURN tcounter::char; +END; +$$; + + +ALTER FUNCTION patch40."bak_slotLabelFromDate"(indate timestamp without time zone) OWNER TO postgres; + +-- +-- TOC entry 372 (class 1255 OID 29342) +-- Name: calcdayoffset(date, integer, integer); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.calcdayoffset(_patchtuesday date, _weekcounter integer, _daycounter integer) RETURNS date + LANGUAGE plpgsql + AS $$ +DECLARE + _workerdate date; +BEGIN + IF _weekcounter = 0 THEN RETURN _patchtuesday; END IF; + IF _daycounter = 2 THEN RETURN _patchtuesday + (_weekcounter * 7); END IF; + IF _daycounter > 2 THEN RETURN _patchtuesday + ((_weekcounter - 1) * 7) + (_daycounter - 2); END IF; + RETURN _patchtuesday + (_weekcounter * 7) + (_daycounter - 2); +END; +$$; + + +ALTER FUNCTION patch40.calcdayoffset(_patchtuesday date, _weekcounter integer, _daycounter integer) OWNER TO postgres; + +-- +-- TOC entry 350 (class 1255 OID 29343) +-- Name: currentcycle(); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.currentcycle() RETURNS character + LANGUAGE plpgsql + AS $$ + DECLARE + cpt date; + fday varchar(20); + tcounter int := 0; + BEGIN + fday := to_char(now(), 'YYYYMM01'); + cpt := to_date(fday, 'YYYYMMDD'); + RETURN to_char(patch40.currentpatchtuesday(), 'YYYY-MM'); + END; + $$; + + +ALTER FUNCTION patch40.currentcycle() OWNER TO postgres; + +-- +-- TOC entry 365 (class 1255 OID 40590) +-- Name: currentcycleid(); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.currentcycleid() RETURNS bigint + LANGUAGE plpgsql + AS $$ + BEGIN + RETURN (SELECT cycleid FROM patch40.cycles + WHERE label = to_char(patch40.currentpatchtuesday(), 'YYYY-MM')); + END; + +$$; + + +ALTER FUNCTION patch40.currentcycleid() OWNER TO postgres; + +-- +-- TOC entry 351 (class 1255 OID 29344) +-- Name: currentpatchtuesday(); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.currentpatchtuesday() RETURNS date + LANGUAGE plpgsql + AS $$ + DECLARE + cpt date; + fday varchar(20); + tcounter int := 0; + BEGIN + fday := to_char(now(), 'YYYYMM01'); + cpt := to_date(fday, 'YYYYMMDD'); + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + WHILE tcounter < 2 LOOP + cpt := cpt + 1; + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + END LOOP; + IF now() < cpt THEN + tcounter := 0; + fday := to_char(cpt - interval '1 month', 'YYYYMM01'); + cpt := to_date(fday, 'YYYYMMDD'); + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + WHILE tcounter < 2 LOOP + cpt := cpt + 1; + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + END LOOP; + END IF; + RETURN cpt; + END; + $$; + + +ALTER FUNCTION patch40.currentpatchtuesday() OWNER TO postgres; + +-- +-- TOC entry 352 (class 1255 OID 29345) +-- Name: dbmaintenance(); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.dbmaintenance(OUT _myout character varying) + LANGUAGE plpgsql + AS $$ +DECLARE + thisTuesday timestamp; +BEGIN + SELECT patch40.currentpatchtuesday() into thisTuesday; + SELECT thisTuesday into _myOut; +END; +$$; + + +ALTER PROCEDURE patch40.dbmaintenance(OUT _myout character varying) OWNER TO postgres; + +-- +-- TOC entry 339 (class 1255 OID 29346) +-- Name: dbmaintenance(character varying); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.dbmaintenance(INOUT _myout character varying DEFAULT NULL::character varying) + LANGUAGE plpgsql + AS $$ +DECLARE + thisTuesday date; + thatTuesday date; + thatLabel character(7); +BEGIN + _myOut = ''; + FOR i IN -3..12 LOOP + thisTuesday := patch40.currentpatchtuesday() + i * INTERVAL '1 month'; + thatTuesday := patch40.thatpatchtuesday(thisTuesday); + thatLabel := CONCAT(date_part('year',thatTuesday),'-',to_char(thatTuesday,'MM')); + IF thatLabel NOT IN (SELECT label FROM patch40.cycles) THEN + INSERT INTO patch40.cycles (label, start) VALUES (thatLabel, thatTuesday); + END IF; + END LOOP; +END; +$$; + + +ALTER PROCEDURE patch40.dbmaintenance(INOUT _myout character varying) OWNER TO postgres; + +-- +-- TOC entry 366 (class 1255 OID 42485) +-- Name: schedulecycle(bigint); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.schedulecycle(_cycleid bigint) RETURNS TABLE(cycleid bigint, cycle character, patchid uuid, waived boolean, nametag character varying, clusterid integer, clustername character varying, accountid bigint, region character varying, instanceid character varying, rescheduled boolean, slotid bigint, slotname character varying, starttime timestamp without time zone, stoptime timestamp without time zone, prechecks_tminus_hours smallint, precheck_sequence integer, patch_sequence integer, validation_sequence integer, escalation_sequence integer) + LANGUAGE plpgsql + AS $$ +DECLARE + patchtuesday date; +BEGIN + SELECT start INTO patchtuesday FROM patch40.cycles cyc WHERE cyc.cycleid = _cycleid; + IF patchtuesday IS NULL THEN + SELECT patch40.currentpatchtuesday() INTO patchtuesday; + END IF; + RETURN QUERY + SELECT + cid.cycleid AS cycleid + ,to_char(patchtuesday, 'YYYY-MM')::CHAR(7) AS cycle + ,trim(t.patchid::varchar)::uuid AS patchid + ,CASE WHEN w.requestedby IS NOT NULL THEN 1::bool ELSE 0::bool END as waived + ,t.nametag ,c.clusterid, c.clustername, t.accountid, t.region, t.instanceid + ,CASE WHEN r.temp_slotid IS NOT NULL THEN 1::bool ELSE 0::bool END as rescheduled + ,CASE WHEN r.temp_slotid IS NOT NULL THEN r.temp_slotid ELSE s.slotid END as slotid + ,CASE WHEN r.temp_slotid IS NOT NULL THEN rd.label ELSE s.label END as slotname + ,CASE WHEN r.temp_slotid IS NOT NULL THEN + patch40.calcdayoffset(patchtuesday, rd.weekcounter, rd.dayofweek) + rd.starttime + ELSE + patch40.calcdayoffset(patchtuesday, s.weekcounter, s.dayofweek) + s.starttime + END as starttime + ,CASE WHEN r.temp_slotid IS NOT NULL THEN + --patchtuesday + (7 * (rd.weekcounter)) + (rd.dayofweek - 2) + rd.starttime + (rd.durationminutes * interval '1 minute') + ((patch40.calcdayoffset(patchtuesday, rd.weekcounter, rd.dayofweek) + rd.starttime) + (rd.durationminutes * interval '1 minute')) + ELSE + --patchtuesday + (7 * (s.weekcounter)) + (s.dayofweek - 2) + s.starttime + (s.durationminutes * interval '1 minute') + ((patch40.calcdayoffset(patchtuesday, s.weekcounter, s.dayofweek) + s.starttime) + (s.durationminutes * interval '1 minute')) + END as stoptime + ,c.prechecks_tminus_hours, c.precheck_sequence, c.patch_sequence, c.validation_sequence, c.escalation_sequence + FROM patch40.targets t + JOIN patch40.slotdefinitions s ON (s.slotid = t.slotid) + JOIN patch40.clusters c ON (t.clusterid = c.clusterid) + JOIN patch40.cycles cid ON (cid.label = to_char(patchtuesday, 'YYYY-MM')::CHAR(7)) + LEFT OUTER JOIN patch40.waivers w ON (cid.cycleid = w.cycleid + AND w.patchid = t.patchid) + LEFT OUTER JOIN patch40.reschedules r ON (cid.cycleid = r.cycleid + AND t.patchid = r.patchid) + LEFT OUTER JOIN patch40.slotdefinitions rd on (r.temp_slotid = rd.slotid) + WHERE t.decommissioned IS NULL; +END; + +$$; + + +ALTER FUNCTION patch40.schedulecycle(_cycleid bigint) OWNER TO postgres; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- TOC entry 252 (class 1259 OID 29383) +-- Name: assetdata; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.assetdata ( + patchid uuid NOT NULL, + operating_org character varying(10), + operating_email character varying(128), + operating_phone character varying(32), + owner_org character varying(10), + owner_email character varying(128), + owner_phone character varying(32), + managing_org character varying(10), + managing_email character varying(128), + managing_phone character varying(32), + updated timestamp without time zone, + updatedby character varying(128) +); + + +ALTER TABLE patch40.assetdata OWNER TO postgres; + +-- +-- TOC entry 297 (class 1259 OID 42486) +-- Name: cycle_schedule; Type: VIEW; Schema: patch40; Owner: postgres +-- + +CREATE VIEW patch40.cycle_schedule AS + SELECT schedulecycle.cycleid, + schedulecycle.cycle, + schedulecycle.patchid, + schedulecycle.waived, + schedulecycle.nametag, + schedulecycle.clusterid, + schedulecycle.clustername, + schedulecycle.accountid, + schedulecycle.region, + schedulecycle.instanceid, + schedulecycle.rescheduled, + schedulecycle.slotid, + schedulecycle.slotname, + schedulecycle.starttime, + schedulecycle.stoptime, + schedulecycle.prechecks_tminus_hours, + schedulecycle.precheck_sequence, + schedulecycle.patch_sequence, + schedulecycle.validation_sequence, + schedulecycle.escalation_sequence + FROM patch40.schedulecycle(patch40.currentcycleid()) schedulecycle(cycleid, cycle, patchid, waived, nametag, clusterid, clustername, accountid, region, instanceid, rescheduled, slotid, slotname, starttime, stoptime, prechecks_tminus_hours, precheck_sequence, patch_sequence, validation_sequence, escalation_sequence); + + +ALTER VIEW patch40.cycle_schedule OWNER TO postgres; + +-- +-- TOC entry 275 (class 1259 OID 29647) +-- Name: sequences; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.sequences ( + sequence_id integer NOT NULL, + sequence_type integer NOT NULL, + sequence_step integer NOT NULL, + label character varying, + automation character varying, + arguments json, + commission_date date, + decommission_date date, + decommed_by character varying(128), + related_runstate_check integer DEFAULT '-1'::integer NOT NULL, + skip_if_onprem boolean DEFAULT false NOT NULL, + related_stopprotection_check integer DEFAULT '-1'::integer NOT NULL, + related_solarwinds_suppression integer DEFAULT '-1'::integer NOT NULL, + dispatch_type integer DEFAULT 1 NOT NULL, + run_if_done boolean DEFAULT false NOT NULL +); + + +ALTER TABLE patch40.sequences OWNER TO postgres; + +-- +-- TOC entry 298 (class 1259 OID 42490) +-- Name: cycle_steps_patch; Type: VIEW; Schema: patch40; Owner: postgres +-- + +CREATE VIEW patch40.cycle_steps_patch AS + SELECT p.cycleid, + p.cycle, + p.patchid, + p.waived, + p.nametag, + seq.sequence_type, + p.patch_sequence AS sequence_id, + seq.sequence_step, + seq.label, + p.clusterid, + p.clustername, + p.accountid, + p.region, + p.instanceid, + p.rescheduled, + p.slotid, + p.slotname, + p.starttime, + p.stoptime, + seq.automation, + seq.arguments, + seq.related_runstate_check, + seq.skip_if_onprem, + seq.related_stopprotection_check, + seq.related_solarwinds_suppression, + seq.dispatch_type, + seq.run_if_done + FROM (patch40.cycle_schedule p + JOIN patch40.sequences seq ON ((p.patch_sequence = seq.sequence_id))) + WHERE (seq.sequence_type = 2) + ORDER BY p.nametag, seq.sequence_type, seq.sequence_step; + + +ALTER VIEW patch40.cycle_steps_patch OWNER TO postgres; + +-- +-- TOC entry 256 (class 1259 OID 29399) +-- Name: executions; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.executions ( + uid bigint NOT NULL, + cycleid bigint NOT NULL, + slotid integer NOT NULL, + clusterid integer NOT NULL, + patchid uuid, + automationarn character varying(2048), + receivedtime timestamp without time zone NOT NULL, + startautomationtime timestamp without time zone, + sequence_step integer NOT NULL, + statusid integer NOT NULL, + lastupdatetime timestamp without time zone NOT NULL, + completiontime timestamp without time zone, + executiontypeid bigint NOT NULL, + sequence_id integer, + sequence_type integer +); + + +ALTER TABLE patch40.executions OWNER TO postgres; + +-- +-- TOC entry 270 (class 1259 OID 29470) +-- Name: statusvalues; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.statusvalues ( + statusid integer NOT NULL, + label character varying(30), + subsystem_id integer, + send_to_automation bit(1) NOT NULL +); + + +ALTER TABLE patch40.statusvalues OWNER TO postgres; + +-- +-- TOC entry 299 (class 1259 OID 42495) +-- Name: cycle_steps_patch_results; Type: VIEW; Schema: patch40; Owner: postgres +-- + +CREATE VIEW patch40.cycle_steps_patch_results AS + SELECT s.cycleid, + s.cycle, + s.patchid, + s.waived, + s.nametag, + s.sequence_type, + s.sequence_id, + s.sequence_step, + s.label AS step, + s.clusterid, + s.clustername, + s.accountid, + s.region, + s.instanceid, + s.rescheduled, + s.slotid, + s.slotname, + s.starttime, + s.stoptime, + e.uid, + e.automationarn, + e.receivedtime, + e.startautomationtime, + e.statusid, + v.label AS status, + CASE + WHEN (v.send_to_automation IS NULL) THEN (1)::bit(1) + ELSE v.send_to_automation + END AS send_to_automation, + e.lastupdatetime, + e.completiontime, + e.executiontypeid, + s.automation, + s.arguments, + s.related_runstate_check, + s.skip_if_onprem, + s.related_stopprotection_check, + s.related_solarwinds_suppression, + s.dispatch_type, + s.run_if_done + FROM ((patch40.cycle_steps_patch s + LEFT JOIN patch40.executions e ON (((e.cycleid = s.cycleid) AND (e.slotid = s.slotid) AND (e.sequence_type = s.sequence_type) AND (e.sequence_id = s.sequence_id) AND (e.sequence_step = s.sequence_step) AND (e.patchid = s.patchid)))) + LEFT JOIN patch40.statusvalues v ON ((v.statusid = e.statusid))) + WHERE ((e.lastupdatetime = ( SELECT max(executions.lastupdatetime) AS max + FROM patch40.executions + WHERE ((executions.cycleid = e.cycleid) AND (executions.slotid = e.slotid) AND (executions.sequence_type = e.sequence_type) AND (executions.sequence_id = e.sequence_id) AND (executions.sequence_step = e.sequence_step) AND (executions.patchid = e.patchid)))) OR (e.lastupdatetime IS NULL)); + + +ALTER VIEW patch40.cycle_steps_patch_results OWNER TO postgres; + +-- +-- TOC entry 290 (class 1259 OID 38600) +-- Name: kernel_validation; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.kernel_validation ( + id integer NOT NULL, + os_type integer NOT NULL, + major_version integer NOT NULL, + minor_version integer NOT NULL, + begin_using_date date NOT NULL, + version_string character varying(128) +); + + +ALTER TABLE patch40.kernel_validation OWNER TO postgres; + +-- +-- TOC entry 288 (class 1259 OID 38428) +-- Name: solarwinds_suppression; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.solarwinds_suppression ( + uid bigint NOT NULL, + suppressedfrom timestamp without time zone, + suppresseduntil timestamp without time zone +); + + +ALTER TABLE patch40.solarwinds_suppression OWNER TO postgres; + +-- +-- TOC entry 300 (class 1259 OID 42500) +-- Name: dispatcher; Type: VIEW; Schema: patch40; Owner: postgres +-- + +CREATE VIEW patch40.dispatcher AS + WITH kv AS ( + SELECT json_object_agg(concat((kernel_validation.major_version)::text, ':', (kernel_validation.minor_version)::text), kernel_validation.version_string) AS kv_data + FROM patch40.kernel_validation + WHERE ((now() > kernel_validation.begin_using_date) AND (kernel_validation.begin_using_date < now())) + ), base_data AS ( + SELECT s.cycleid, + s.cycle, + s.patchid, + s.waived, + s.nametag, + s.sequence_type, + s.sequence_id, + s.sequence_step, + s.step, + s.clusterid, + s.clustername, + s.accountid, + s.region, + s.instanceid, + s.rescheduled, + s.slotid, + s.slotname, + s.starttime, + s.stoptime, + s.uid, + s.automationarn, + s.receivedtime, + s.startautomationtime, + s.statusid, + s.status, + s.send_to_automation, + s.lastupdatetime, + s.completiontime, + s.executiontypeid, + s.automation, + s.arguments, + s.related_runstate_check, + s.skip_if_onprem, + s.related_stopprotection_check, + s.related_solarwinds_suppression, + s.dispatch_type, + s.run_if_done, + lag(s.statusid) OVER (PARTITION BY s.cycleid, s.slotid, s.sequence_type, s.sequence_id, s.clusterid, s.patchid ORDER BY s.sequence_step) AS "PreviousStatus_Calc" + FROM patch40.cycle_steps_patch_results s + ) + SELECT DISTINCT ON (b.cycleid, b.slotid, b.sequence_type, b.sequence_id, b.patchid) b.uid, + b.instanceid, + b.sequence_step, + b.step, + b."PreviousStatus_Calc" AS "PreviousStatus", + b.statusid, + b.cycleid, + b.cycle, + b.slotid, + b.slotname, + b.starttime, + b.stoptime, + b.sequence_type, + b.sequence_id, + b.patchid, + b.nametag, + b.waived, + b.rescheduled, + b.clusterid, + b.clustername, + b.accountid, + b.region, + b.automation, + b.arguments, + b.related_runstate_check, + b.skip_if_onprem, + e.statusid AS found_runstate_status, + b.related_stopprotection_check, + p.statusid AS found_stopprotection_status, + sup.suppressedfrom AS sw_suppressedfrom, + sup.suppresseduntil AS sw_suppresseduntil, + kv.kv_data AS kernel_validation, + poc.owner_email AS poc, + b.dispatch_type, + b.run_if_done + FROM ((((((base_data b + CROSS JOIN kv) + LEFT JOIN patch40.executions e ON (((e.cycleid = b.cycleid) AND (e.slotid = b.slotid) AND (e.sequence_type = b.sequence_type) AND (e.sequence_id = b.sequence_id) AND (e.clusterid = b.clusterid) AND (e.patchid = b.patchid) AND (e.sequence_step = b.related_runstate_check)))) + LEFT JOIN patch40.executions p ON (((p.cycleid = b.cycleid) AND (p.slotid = b.slotid) AND (p.sequence_type = b.sequence_type) AND (p.sequence_id = b.sequence_id) AND (p.clusterid = b.clusterid) AND (p.patchid = b.patchid) AND (p.sequence_step = b.related_stopprotection_check)))) + LEFT JOIN patch40.executions w ON (((w.cycleid = b.cycleid) AND (w.slotid = b.slotid) AND (w.sequence_type = b.sequence_type) AND (w.sequence_id = b.sequence_id) AND (w.clusterid = b.clusterid) AND (w.patchid = b.patchid) AND (w.sequence_step = b.related_solarwinds_suppression)))) + LEFT JOIN patch40.solarwinds_suppression sup ON ((sup.uid = w.uid))) + LEFT JOIN patch40.assetdata poc ON ((b.patchid = poc.patchid))) + WHERE ((b.sequence_step IS NOT NULL) AND (b.send_to_automation = (1)::bit(1)) AND (((b.statusid >= 3000) AND (b.statusid < 3499)) OR ((b.statusid IS NULL) AND (((b."PreviousStatus_Calc" >= 2000) AND (b."PreviousStatus_Calc" < 3000)) OR (b."PreviousStatus_Calc" >= 5000))) OR ((b.statusid IS NULL) AND (b.sequence_step = 1))) AND ((now() AT TIME ZONE 'America/New_York'::text) >= b.starttime) AND ((now() AT TIME ZONE 'America/New_York'::text) <= b.stoptime)) + ORDER BY b.cycleid, b.slotid, b.sequence_type, b.sequence_id, b.patchid, b.sequence_step, b.lastupdatetime DESC; + + +ALTER VIEW patch40.dispatcher OWNER TO postgres; + +-- +-- TOC entry 376 (class 1255 OID 42787) +-- Name: dispatch_done(uuid); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.dispatch_done(_patchid uuid) RETURNS SETOF patch40.dispatcher + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN QUERY + WITH kv AS ( + SELECT json_object_agg(concat(kernel_validation.major_version::text, ':', kernel_validation.minor_version::text), kernel_validation.version_string) AS kv_data + FROM patch40.kernel_validation + WHERE now() > kernel_validation.begin_using_date AND kernel_validation.begin_using_date < now() + ), base_data AS ( + SELECT s.cycleid, + s.cycle, + s.patchid, + s.waived, + s.nametag, + s.sequence_type, + s.sequence_id, + s.sequence_step, + s.step, + s.clusterid, + s.clustername, + s.accountid, + s.region, + s.instanceid, + s.rescheduled, + s.slotid, + s.slotname, + s.starttime, + s.stoptime, + s.uid, + s.automationarn, + s.receivedtime, + s.startautomationtime, + s.statusid, + s.status, + s.send_to_automation, + s.lastupdatetime, + s.completiontime, + s.executiontypeid, + s.automation, + s.arguments, + s.related_runstate_check, + s.skip_if_onprem, + s.related_stopprotection_check, + s.related_solarwinds_suppression, + s.dispatch_type, + s.run_if_done, + lag(s.statusid) OVER (PARTITION BY s.cycleid, s.slotid, s.sequence_type, s.sequence_id, s.clusterid, s.patchid ORDER BY s.sequence_step) AS "PreviousStatus_Calc" + FROM patch40.cycle_steps_patch_results s + ) + SELECT --DISTINCT ON + --(b.cycleid, b.slotid, b.sequence_type, b.sequence_id, b.patchid) + --b.cycleid, b.slotid, b.sequence_type, b.sequence_id, b.patchid, + b.uid, + b.instanceid, + b.sequence_step, + b.step, + b."PreviousStatus_Calc" AS "PreviousStatus", + b.statusid, + b.cycleid, + b.cycle, + b.slotid, + b.slotname, + b.starttime, + b.stoptime, + b.sequence_type, + b.sequence_id, + b.patchid, + b.nametag, + b.waived, + b.rescheduled, + b.clusterid, + b.clustername, + b.accountid, + b.region, + b.automation, + b.arguments, + b.related_runstate_check, + b.skip_if_onprem, + e.statusid AS found_runstate_status, + b.related_stopprotection_check, + p.statusid AS found_stopprotection_status, + sup.suppressedfrom AS sw_suppressedfrom, + sup.suppresseduntil AS sw_suppresseduntil, + kv.kv_data AS kernel_validation, + poc.owner_email AS poc, + b.dispatch_type, + b.run_if_done + FROM base_data b + CROSS JOIN kv + LEFT JOIN patch40.executions e ON e.cycleid = b.cycleid AND e.slotid = b.slotid AND e.sequence_type = b.sequence_type AND e.sequence_id = b.sequence_id AND e.clusterid = b.clusterid AND e.patchid = b.patchid AND e.sequence_step = b.related_runstate_check + LEFT JOIN patch40.executions p ON p.cycleid = b.cycleid AND p.slotid = b.slotid AND p.sequence_type = b.sequence_type AND p.sequence_id = b.sequence_id AND p.clusterid = b.clusterid AND p.patchid = b.patchid AND p.sequence_step = b.related_stopprotection_check + LEFT JOIN patch40.executions w ON w.cycleid = b.cycleid AND w.slotid = b.slotid AND w.sequence_type = b.sequence_type AND w.sequence_id = b.sequence_id AND w.clusterid = b.clusterid AND w.patchid = b.patchid AND w.sequence_step = b.related_solarwinds_suppression + LEFT JOIN patch40.solarwinds_suppression sup ON sup.uid = w.uid + LEFT JOIN patch40.assetdata poc ON b.patchid = poc.patchid + WHERE + b.uid is NULL + AND + b.patchid = _patchid + ORDER BY b.cycleid, b.slotid, b.sequence_type, b.sequence_id, b.patchid, b.sequence_step, b.lastupdatetime DESC LIMIT 1; +END; +$$; + + +ALTER FUNCTION patch40.dispatch_done(_patchid uuid) OWNER TO postgres; + +-- +-- TOC entry 338 (class 1255 OID 34373) +-- Name: dispatcher_advance(); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.dispatcher_advance() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN + IF ((NEW.statusid >= 2000 AND NEW.statusid < 3000) + OR + (NEW.statusid >= 6000 AND NEW.statusid < 9000)) + THEN + SELECT * FROM aws_lambda.invoke(aws_commons.create_lambda_function_arn('arn:aws-us-gov:lambda:us-gov-east-1:412187151792:function:patch40-dispatcher-advance', 'us-gov-east-1' + ), + json_build_object( + 'cycleid', OLD.cycleid, + 'slotid', OLD.slotid, + 'sequence_type', OLD.sequence_type, + 'patchid', OLD.patchid + ), + 'Event' + ); + END IF; + RETURN TRIGGER; +END; +$$; + + +ALTER FUNCTION patch40.dispatcher_advance() OWNER TO postgres; + +-- +-- TOC entry 343 (class 1255 OID 34375) +-- Name: dispatcher_execute(); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.dispatcher_execute() + LANGUAGE plpgsql + AS $$DECLARE + lamreturn_cursor CURSOR FOR SELECT * FROM + aws_lambda.invoke( + aws_commons.create_lambda_function_arn( + 'arn:aws-us-gov:lambda:us-gov-east-1:412187151792:function:patch40-dispatcher-patch', 'us-gov-east-1' + ), + '{}'::json); + lamrow RECORD; +BEGIN + IF (SELECT enabled FROM patch40.enable_dispatcher WHERE "type" = 'slot') THEN + OPEN lamreturn_cursor; + LOOP + FETCH lamreturn_cursor INTO lamrow; + EXIT WHEN NOT FOUND; + INSERT INTO patch40.dispatch_history + (timestamp, status_code, payload, executed_version, log_result) + VALUES + (now(), lamrow.status_code, lamrow.payload, lamrow.executed_version, lamrow.log_result); + END LOOP; + END IF; +END; $$; + + +ALTER PROCEDURE patch40.dispatcher_execute() OWNER TO postgres; + +-- +-- TOC entry 389 (class 1255 OID 42571) +-- Name: g_homepage_cycle_achieved(bigint); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.g_homepage_cycle_achieved(_cycleid bigint) RETURNS TABLE(patchid uuid, last_in_sequence integer, last_achieved integer, slotid integer) + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN QUERY +WITH achieved AS ( + SELECT + e.patchid, + MAX(sequence_step) AS last_achieved + FROM patch40.executions e + WHERE + cycleid = _cycleid AND + ((statusid >= 2000 AND statusid < 3000) + OR statusid >= 6000) + + GROUP BY e.patchid +) +SELECT + t.patchid, + MAX(s.sequence_step) AS last_in_sequence, + COALESCE(a.last_achieved, 0) AS last_achieved, + t.slotid +FROM patch40.targets t +JOIN patch40.clusters c ON t.clusterid = c.clusterid +JOIN patch40.sequences s ON c.patch_sequence = s.sequence_id +LEFT JOIN achieved a ON a.patchid = t.patchid +WHERE s.sequence_type = 2 + AND t.patchid NOT IN ( + SELECT w.patchid + FROM patch40.waivers w + WHERE w.cycleid = patch40.currentcycleid() + ) +GROUP BY t.patchid, a.last_achieved;END; +$$; + + +ALTER FUNCTION patch40.g_homepage_cycle_achieved(_cycleid bigint) OWNER TO postgres; + +-- +-- TOC entry 373 (class 1255 OID 42573) +-- Name: g_homepage_cycle_attempted(bigint); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.g_homepage_cycle_attempted(_cycleid bigint) RETURNS TABLE(patchid uuid, last_in_sequence integer, last_attempted integer, slotid integer) + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN QUERY +WITH attempted AS ( + SELECT + e.patchid, + max(e.lastupdatetime) AS lastupdatetime + FROM patch40.executions e + WHERE + cycleid = _cycleid + + GROUP BY e.patchid +) +SELECT + t.patchid, + MAX(s.sequence_step) AS last_in_sequence, + COALESCE((select l.sequence_step from patch40.executions l where l.cycleid = _cycleid and l.patchid = t.patchid and l.lastupdatetime = a.lastupdatetime), 0) AS last_attempted, + t.slotid +FROM patch40.targets t +JOIN patch40.clusters c ON t.clusterid = c.clusterid +JOIN patch40.sequences s ON c.patch_sequence = s.sequence_id +LEFT JOIN attempted a ON a.patchid = t.patchid +WHERE s.sequence_type = 2 + AND t.patchid NOT IN ( + SELECT w.patchid + FROM patch40.waivers w + WHERE w.cycleid = _cycleid + ) +GROUP BY t.patchid, a.lastupdatetime; +END; +$$; + + +ALTER FUNCTION patch40.g_homepage_cycle_attempted(_cycleid bigint) OWNER TO postgres; + +-- +-- TOC entry 367 (class 1255 OID 42509) +-- Name: g_homepage_needs_attention(bigint); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.g_homepage_needs_attention(_cycleid bigint) RETURNS TABLE(patchid uuid, stoptime timestamp without time zone) + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN QUERY + SELECT + a.patchid, l.completeby + FROM patch40.g_homepage_cycle_achieved(patch40.currentcycleid()) a + JOIN patch40.g_target_last_executed_in_cycle_by_sequence_and_patchid(18, 2, a.patchid) l ON l.patchid = a.patchid + WHERE + (a.last_achieved != l.maxstep AND now() AT TIME ZONE 'America/New_York' > l.completeby) + OR + (l.statusid BETWEEN 3000 AND 4999); +END; +$$; + + +ALTER FUNCTION patch40.g_homepage_needs_attention(_cycleid bigint) OWNER TO postgres; + +-- +-- TOC entry 388 (class 1255 OID 42470) +-- Name: g_homepage_slot_occupancy(bigint); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.g_homepage_slot_occupancy(_cycleid bigint) RETURNS TABLE(cycleid bigint, slotid integer, occupancy bigint, starttime timestamp without time zone, durationminutes integer, label character varying) + LANGUAGE plpgsql + AS $$ +DECLARE patchtuesday date; +BEGIN + SELECT start INTO patchtuesday FROM patch40.cycles c WHERE c.cycleid = _cycleid; + RETURN QUERY + SELECT + _cycleid AS "cycleid", + s.slotid, + COUNT(c.patchid) AS occupancy, + patch40.calcdayoffset(patchtuesday, s.weekcounter, s.dayofweek) + s.starttime AS starttime, + s.durationminutes, + s.label + FROM patch40.slotdefinitions s + LEFT OUTER JOIN patch40.cycle_schedule c on s.slotid = c.slotid + GROUP BY s.slotid + ORDER BY starttime ASC; +END; +$$; + + +ALTER FUNCTION patch40.g_homepage_slot_occupancy(_cycleid bigint) OWNER TO postgres; + +-- +-- TOC entry 374 (class 1255 OID 42574) +-- Name: g_slot_details(bigint, integer); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.g_slot_details(_cycleid bigint, _slotid integer) RETURNS TABLE(uid bigint, cycleid bigint, slotid integer, patchid uuid, nametag character varying, last_in_sequence integer, last_attempted integer, step_name character varying, lastupdatetime timestamp without time zone, retry_count bigint, status character varying, return_code integer, stdout text, stderr text, donetest integer) + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN QUERY +WITH progress AS ( + SELECT + p.patchid, + p.last_in_sequence, + p.last_attempted + FROM patch40.g_homepage_cycle_attempted(_cycleid) p + WHERE p.slotid = _slotid +) +SELECT + e.uid, + e.cycleid, + e.slotid, + p.patchid, + t.nametag, + p.last_in_sequence, + p.last_attempted, + s.label AS step_name, + e.lastupdatetime, + e.retry_count, -- ← New: shows how many times this step was attempted + v.label AS status, + o.rc AS return_code, + o.stdout, + o.stderr, + ((((p.last_attempted::float - p.last_in_sequence::float) * -1) / p.last_in_sequence) * 100)::integer as donetest +FROM progress p +LEFT JOIN patch40.targets t + ON t.patchid = p.patchid +LEFT JOIN LATERAL ( + SELECT + e2.*, + COUNT(*) OVER () AS retry_count -- Counts total attempts for this patch + step + FROM patch40.executions e2 + WHERE e2.patchid = p.patchid + AND e2.sequence_step = p.last_attempted + AND e2.cycleid = _cycleid + AND e2.slotid = _slotid + ORDER BY e2.lastupdatetime DESC + LIMIT 1 +) e ON true +LEFT JOIN patch40.sequences s + ON s.sequence_id = e.sequence_id + AND s.sequence_type = e.sequence_type + AND s.sequence_step = e.sequence_step +LEFT JOIN patch40.statusvalues v + ON v.statusid = e.statusid +LEFT JOIN patch40.execution_output o + ON o.uid = e.uid +ORDER BY t.nametag; +END; +$$; + + +ALTER FUNCTION patch40.g_slot_details(_cycleid bigint, _slotid integer) OWNER TO postgres; + +-- +-- TOC entry 368 (class 1255 OID 42608) +-- Name: g_target_details(uuid); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.g_target_details(_patchid uuid) RETURNS TABLE(attribute text, value character varying) + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN QUERY + SELECT 'Hostname', nametag::varchar FROM patch40.targets WHERE patchid = _patchid; + RETURN QUERY + SELECT 'CSP', c.label FROM patch40.targets t JOIN patch40.csps c ON t.cspid = c.cspid WHERE t.patchid = _patchid; + RETURN QUERY + SELECT 'AccountID', accountid::varchar FROM patch40.targets WHERE patchid = _patchid; + RETURN QUERY + SELECT 'Region', region::varchar FROM patch40.targets WHERE patchid = _patchid; + RETURN QUERY + SELECT 'InstanceID', instanceid::varchar FROM patch40.targets WHERE patchid = _patchid; + RETURN QUERY + SELECT 'Commissioned / By', CONCAT(commissioned::varchar, ' / ', commissionedby)::varchar FROM patch40.targets WHERE patchid = _patchid; + RETURN QUERY + SELECT 'Decommissioned / By', CONCAT(decommissioned::varchar, ' / ', decommissionedby)::varchar FROM patch40.targets WHERE patchid = _patchid; + RETURN QUERY + SELECT '', ''::varchar; + RETURN QUERY + SELECT 'Operating Org', COALESCE((SELECT operating_org FROM patch40.assetdata WHERE patchid = _patchid), '-no record-')::varchar; + RETURN QUERY + SELECT 'Operating Email', COALESCE((SELECT operating_email FROM patch40.assetdata WHERE patchid = _patchid), '-no record')::varchar; + RETURN QUERY + SELECT 'Operating Phone', COALESCE((SELECT operating_phone FROM patch40.assetdata WHERE patchid = _patchid), '-no record-')::varchar; + RETURN QUERY + SELECT 'Owner Org', COALESCE((SELECT owner_org FROM patch40.assetdata WHERE patchid = _patchid), '-no record-')::varchar; + RETURN QUERY + SELECT 'Owner Email', COALESCE((SELECT owner_email FROM patch40.assetdata WHERE patchid = _patchid), '-no record')::varchar; + RETURN QUERY + SELECT 'Owner Phone', COALESCE((SELECT owner_phone FROM patch40.assetdata WHERE patchid = _patchid), '-no record')::varchar; + RETURN QUERY + SELECT 'Managing Org', COALESCE((SELECT managing_org FROM patch40.assetdata WHERE patchid = _patchid), '-no record-')::varchar; + RETURN QUERY + SELECT 'Managing Email', COALESCE((SELECT managing_email FROM patch40.assetdata WHERE patchid = _patchid), '-no record-')::varchar; + RETURN QUERY + SELECT 'Managing Phone', COALESCE((SELECT managing_phone FROM patch40.assetdata WHERE patchid = _patchid), '-no record-')::varchar; + RETURN QUERY + SELECT 'Last Update / By', COALESCE((SELECT CONCAT(updated::varchar, ' / ',updatedby) FROM patch40.assetdata WHERE patchid = _patchid), '-no reocrd-')::varchar; + RETURN QUERY + SELECT '', ''::varchar; + RETURN QUERY + SELECT 'Cluster', c.clustername FROM patch40.targets t JOIN patch40.clusters c ON c.clusterid = t.clusterid WHERE t.patchid = _patchid; + RETURN QUERY + SELECT 'Normal Slot', s.label FROM patch40.targets t JOIN patch40.slotdefinitions s ON s.slotid = t.slotid WHERE t.patchid = _patchid; + RETURN QUERY + SELECT 'Rescheduled', '-not implemented-'::varchar; + RETURN QUERY + SELECT 'Waived', '-not implemented-'::varchar; + RETURN QUERY + SELECT '', ''::varchar; + RETURN QUERY + SELECT 'Overrides', argument_overrides::varchar FROM patch40.targets WHERE patchid = _patchid; + RETURN QUERY + SELECT '', ''::varchar; + RETURN QUERY + SELECT 'patchid', _patchid::varchar; +END; +$$; + + +ALTER FUNCTION patch40.g_target_details(_patchid uuid) OWNER TO postgres; + +-- +-- TOC entry 375 (class 1255 OID 42730) +-- Name: g_target_details_execution(uuid, bigint); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.g_target_details_execution(_patchid uuid, _cycleid bigint) RETURNS SETOF patch40.cycle_steps_patch_results + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN QUERY + SELECT s.cycleid, + s.cycle, + s.patchid, + s.waived, + s.nametag, + s.sequence_type, + s.sequence_id, + s.sequence_step, + s.label AS step, + s.clusterid, + s.clustername, + s.accountid, + s.region, + s.instanceid, + s.rescheduled, + s.slotid, + s.slotname, + s.starttime, + s.stoptime, + e.uid, + e.automationarn, + e.receivedtime, + e.startautomationtime, + e.statusid, + v.label AS status, + CASE + WHEN v.send_to_automation IS NULL THEN 1::bit(1) + ELSE v.send_to_automation + END AS send_to_automation, + e.lastupdatetime, + e.completiontime, + e.executiontypeid, + s.automation, + s.arguments, + s.related_runstate_check, + s.skip_if_onprem, + s.related_stopprotection_check, + s.related_solarwinds_suppression, + s.dispatch_type, + s.run_if_done + FROM patch40.cycle_steps_patch s + LEFT JOIN patch40.executions e ON e.cycleid = s.cycleid AND e.slotid = s.slotid AND e.sequence_type = s.sequence_type AND e.sequence_id = s.sequence_id AND e.sequence_step = s.sequence_step AND e.patchid = s.patchid + LEFT JOIN patch40.statusvalues v ON v.statusid = e.statusid + WHERE s.cycleid = _cycleid and s.patchid = _patchid; +END; +$$; + + +ALTER FUNCTION patch40.g_target_details_execution(_patchid uuid, _cycleid bigint) OWNER TO postgres; + +-- +-- TOC entry 369 (class 1255 OID 42591) +-- Name: g_target_last_executed_in_cycle_by_sequence_and_patchid(bigint, integer, uuid); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.g_target_last_executed_in_cycle_by_sequence_and_patchid(_cycleid bigint, _sequence_type integer, _patchid uuid) RETURNS TABLE(patchid uuid, nametag character varying, sequence_step integer, maxstep integer, pct_complete integer, completeby timestamp without time zone, stepname character varying, status character varying, uid bigint, statusid integer) + LANGUAGE plpgsql + AS $$ +BEGIN + RETURN QUERY +SELECT + _patchid, + t.nametag, + COALESCE(e.sequence_step, 0) AS sequence_step, -- explicit + seq.maxstep, + COALESCE( 100.0 * COALESCE( e.sequence_step, 0) / NULLIF(seq.maxstep, 0), 0)::integer AS pct_complete, + p.stoptime AS completeby, + s.label AS stepname, + v.label AS status, + e.uid, + e.statusid +--FROM patch40.g_homepage_needs_attention(_cycleid) p + +FROM patch40.targets t + +LEFT JOIN patch40.clusters cl ON cl.clusterid = t.clusterid + +JOIN patch40.cycle_schedule p on p.patchid = _patchid + +LEFT JOIN LATERAL ( + SELECT ex.sequence_step, ex.uid, ex.statusid + FROM patch40.executions ex + WHERE ex.cycleid = _cycleid + AND ex.sequence_type = _sequence_type + AND ex.sequence_id = COALESCE(cl.patch_sequence, 0) -- safety + AND ex.patchid = _patchid + ORDER BY lastupdatetime DESC + LIMIT 1 +) e ON true + +LEFT JOIN patch40.statusvalues v ON e.statusid = v.statusid + +CROSS JOIN LATERAL ( + SELECT COALESCE(MAX(tseq.sequence_step), 0) AS maxstep + FROM patch40.sequences tseq + WHERE sequence_type = _sequence_type + AND sequence_id = COALESCE(cl.patch_sequence, 0) +) seq + +LEFT JOIN patch40.sequences s + ON s.sequence_type = _sequence_type + AND s.sequence_id = COALESCE(cl.patch_sequence, 0) + AND s.sequence_step = COALESCE(e.sequence_step, 0) +WHERE t.patchid = _patchid; +END; +$$; + + +ALTER FUNCTION patch40.g_target_last_executed_in_cycle_by_sequence_and_patchid(_cycleid bigint, _sequence_type integer, _patchid uuid) OWNER TO postgres; + +-- +-- TOC entry 377 (class 1255 OID 42913) +-- Name: g_target_ui_options_by_cycle_sequence_and_patchid(bigint, integer, uuid); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.g_target_ui_options_by_cycle_sequence_and_patchid(_cycleid bigint, _sequence_type integer, _patchid uuid) RETURNS TABLE(action text) + LANGUAGE plpgsql + AS $$ +DECLARE + _lastexec RECORD; +BEGIN + RETURN QUERY SELECT 'None'; + SELECT * INTO _lastexec FROM patch40.g_target_last_executed_in_cycle_by_sequence_and_patchid(_cycleid, _sequence_type, _patchid); + IF COALESCE(_lastexec.statusid, -1) BETWEEN 4000 AND 4999 THEN + RETURN QUERY SELECT 'Retry'; + RETURN QUERY SELECT 'Next'; + RETURN QUERY SELECT 'Done'; + END IF; +END; +$$; + + +ALTER FUNCTION patch40.g_target_ui_options_by_cycle_sequence_and_patchid(_cycleid bigint, _sequence_type integer, _patchid uuid) OWNER TO postgres; + +-- +-- TOC entry 344 (class 1255 OID 29347) +-- Name: inventory_import(); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.inventory_import() RETURNS TABLE(testout character varying, matchit character varying) + LANGUAGE plpgsql + AS $$ +DECLARE + _target varchar(128); + _slot varchar(128); + _parsedslot varchar(128); + _lookupslot varchar(128); + targets CURSOR FOR SELECT DISTINCT slot FROM patch40._importpatch40schedule WHERE slot != 'DECOM'; +BEGIN + CREATE TEMPORARY TABLE tmpresults (testout varchar(128), matchit varchar(128)) ON COMMIT DROP; + OPEN targets; + LOOP + FETCH NEXT FROM targets INTO _slot; + EXIT WHEN NOT FOUND; + _parsedslot := SPLIT_PART(_slot, '_', 1) || '_' + || UPPER(SPLIT_PART(_slot, '_', 2)) || '_' || SPLIT_PART(_slot, '_', 9); + INSERT INTO tmpresults (testout, matchit) VALUES + (_parsedslot + , (SELECT label FROM patch40.slotdefinitions WHERE label = _parsedslot)); + --INSERT INTO tmpresults (testout) VALUES ('peter'); + END LOOP; + CLOSE targets; + --INSERT INTO tmpresults (testout) VALUES ('petertest'); + RETURN QUERY SELECT tmpresults.testout, tmpresults.matchit FROM tmpresults; +END; +$$; + + +ALTER FUNCTION patch40.inventory_import() OWNER TO postgres; + +-- +-- TOC entry 341 (class 1255 OID 29348) +-- Name: monthpatchtuesday(date); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.monthpatchtuesday(indate date) RETURNS date + LANGUAGE plpgsql + AS $$ + DECLARE + cpt date; + fday varchar(20); + tcounter int := 0; + BEGIN + fday := to_char(indate, 'YYYYMM01'); + cpt := to_date(fday, 'YYYYMMDD'); + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + WHILE tcounter < 2 LOOP + cpt := cpt + 1; + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + END LOOP; + IF indate < cpt THEN + tcounter := 0; + fday := to_char(cpt - interval '1 month', 'YYYYMM01'); + cpt := to_date(fday, 'YYYYMMDD'); + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + WHILE tcounter < 2 LOOP + cpt := cpt + 1; + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + END LOOP; + END IF; + RETURN cpt; + END; + $$; + + +ALTER FUNCTION patch40.monthpatchtuesday(indate date) OWNER TO postgres; + +-- +-- TOC entry 342 (class 1255 OID 29349) +-- Name: numSuffix(integer); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40."numSuffix"(innumber integer) RETURNS character varying + LANGUAGE plpgsql + AS $$ +BEGIN + DROP TABLE IF EXISTS tmp_iteration; + CREATE TEMP TABLE IF NOT EXISTS tmp_iteration( + id serial PRIMARY KEY, + iterate char(2) + ); + + INSERT INTO + tmp_iteration (iterate) + VALUES + ('th'), + ('st'), + ('nd'), + ('rd'), + ('th'), + ('th'), + ('th'), + ('th'); + RETURN (SELECT iterate FROM tmp_iteration where (id - 1) = inNumber); +END; +$$; + + +ALTER FUNCTION patch40."numSuffix"(innumber integer) OWNER TO postgres; + +-- +-- TOC entry 358 (class 1255 OID 40203) +-- Name: remove__sp_step_result(bigint, integer, integer); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.remove__sp_step_result(IN in_uid bigint, IN in_statusid integer, IN in_sentstatus integer) + LANGUAGE plpgsql + AS $$ +DECLARE + my_statusid integer; + has_errors boolean; +BEGIN + -- Check for non-zero return codes in the execution output + SELECT EXISTS ( + SELECT 1 + FROM patch40.execution_output + WHERE uid = in_uid AND rc <> 0 + ) INTO has_errors; + + -- Original logic: Determine the final status based on error existence + IF has_errors THEN + -- If sentstatus is in the 3xxx range, shift to 4xxx; otherwise default to 4000 + IF in_sentstatus >= 3000 AND in_sentstatus <= 3999 THEN + my_statusid := in_sentstatus + 1000; + ELSE + my_statusid := 4000; + END IF; + ELSE + -- No errors found, use the provided status + my_statusid := in_statusid; + END IF; + + -- Perform the update on the executions table + UPDATE patch40.executions + SET + completiontime = now(), + lastupdatetime = now(), + statusid = my_statusid + WHERE uid = in_uid; + + -- Procedures do not use RETURN. + -- If you need to signal success/failure, use RAISE NOTICE or let exceptions bubble up. +END; +$$; + + +ALTER PROCEDURE patch40.remove__sp_step_result(IN in_uid bigint, IN in_statusid integer, IN in_sentstatus integer) OWNER TO postgres; + +-- +-- TOC entry 380 (class 1255 OID 39996) +-- Name: schedulecycle(character varying); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.schedulecycle(_indate character varying) RETURNS TABLE(cycleid bigint, cycle character, patchid uuid, waived character, nametag character varying, clusterid integer, clustername character varying, accountid bigint, region character varying, instanceid character varying, rescheduled character, slotid bigint, slotname character varying, starttime timestamp without time zone, stoptime timestamp without time zone, prechecks_tminus_hours smallint, precheck_sequence integer, patch_sequence integer, validation_sequence integer, escalation_sequence integer) + LANGUAGE plpgsql + AS $$ +DECLARE + patchtuesday date; +BEGIN + IF _indate NOT IN (SELECT to_char(start, 'YYYY-MM-DD') FROM patch40.cycles) THEN + patchtuesday := patch40.currentpatchtuesday(); + ELSE + patchtuesday := _indate::date; + END IF; + RETURN QUERY + SELECT + cid.cycleid AS cycleid + ,to_char(patchtuesday, 'YYYY-MM')::CHAR(7) AS cycle + ,trim(t.patchid::varchar)::uuid AS patchid + ,CASE WHEN w.requestedby IS NOT NULL THEN '*'::char ELSE ' '::char END as waived + ,t.nametag ,c.clusterid, c.clustername, t.accountid, t.region, t.instanceid + ,CASE WHEN r.temp_slotid IS NOT NULL THEN '*'::character ELSE ''::character END as rescheduled + ,CASE WHEN r.temp_slotid IS NOT NULL THEN r.temp_slotid ELSE s.slotid END as slotid + ,CASE WHEN r.temp_slotid IS NOT NULL THEN rd.label ELSE s.label END as slotname + ,CASE WHEN r.temp_slotid IS NOT NULL THEN + patch40.calcdayoffset(patchtuesday, rd.weekcounter, rd.dayofweek) + rd.starttime + ELSE + patch40.calcdayoffset(patchtuesday, s.weekcounter, s.dayofweek) + s.starttime + END as starttime + ,CASE WHEN r.temp_slotid IS NOT NULL THEN + --patchtuesday + (7 * (rd.weekcounter)) + (rd.dayofweek - 2) + rd.starttime + (rd.durationminutes * interval '1 minute') + ((patch40.calcdayoffset(patchtuesday, rd.weekcounter, rd.dayofweek) + rd.starttime) + (rd.durationminutes * interval '1 minute')) + ELSE + --patchtuesday + (7 * (s.weekcounter)) + (s.dayofweek - 2) + s.starttime + (s.durationminutes * interval '1 minute') + ((patch40.calcdayoffset(patchtuesday, s.weekcounter, s.dayofweek) + s.starttime) + (s.durationminutes * interval '1 minute')) + END as stoptime + ,c.prechecks_tminus_hours, c.precheck_sequence, c.patch_sequence, c.validation_sequence, c.escalation_sequence + FROM patch40.targets t + JOIN patch40.slotdefinitions s ON (s.slotid = t.slotid) + JOIN patch40.clusters c ON (t.clusterid = c.clusterid) + JOIN patch40.cycles cid ON (cid.label = to_char(patchtuesday, 'YYYY-MM')::CHAR(7)) + LEFT OUTER JOIN patch40.waivers w ON (cid.cycleid = w.cycleid + AND w.patchid = t.patchid) + LEFT OUTER JOIN patch40.reschedules r ON (cid.cycleid = r.cycleid + AND t.patchid = r.patchid) + LEFT OUTER JOIN patch40.slotdefinitions rd on (r.temp_slotid = rd.slotid) + WHERE t.decommissioned IS NULL; +END; + +$$; + + +ALTER FUNCTION patch40.schedulecycle(_indate character varying) OWNER TO postgres; + +-- +-- TOC entry 381 (class 1255 OID 29351) +-- Name: scheduleinstance(character varying, bigint, character varying); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.scheduleinstance(_instanceid character varying, _accountid bigint, _slotlabel character varying, OUT scheduleresult character varying) RETURNS character varying + LANGUAGE plpgsql + AS $$ +DECLARE + _nametag character varying; + _slotid bigint; + _eslotlabel character varying; + _region character varying; +BEGIN + IF _slotlabel IN (SELECT label FROM patch40.slotdefinitions) THEN + SELECT slotid INTO _slotid FROM patch40.slotdefinitions WHERE label = _slotlabel; + ELSE + scheduleResult := 'ERROR / Slot: ' || _slotlabel || ' not found.'; + RETURN; + END IF; + IF _instanceid NOT IN (SELECT instanceid FROM patch40.targets WHERE accountid = _accountid) THEN + IF substring(_instanceid from 1 for 2) = 'i-' THEN + IF _instanceid NOT IN (SELECT instanceid FROM patch40.ssminventory WHERE accountid = _accountid) THEN + scheduleResult := 'ERROR / Instance: ' || _instanceid || ' not found.'; + RETURN; + END IF; + SELECT computername, region INTO _nametag, _region FROM patch40.ssminventory WHERE accountid = _accountid AND instanceid = _instanceid; + ELSEIF substring(_instanceid from 1 for 3) = 'mi-' THEN + IF _instanceid NOT IN (SELECT instanceid FROM patch40.ssminventory WHERE accountid = _accountid) THEN + scheduleResult := 'ERROR / Hybrid Instance: ' || _instanceid || ' not found.'; + RETURN; + END IF; + _nametag := (SELECT computername FROM patch40.ssminventory WHERE accountid = _accountid and instanceid = _instanceid); + _region := (SELECT region FROM patch40.ssminventory WHERE accountid = _accountid and instanceid = _instanceid); + END IF; + IF (SELECT COUNT(*) FROM patch40.targets WHERE accountid = _accountid AND instanceid = _instanceid AND slotid = _slotid) < 1 THEN + INSERT INTO patch40.targets (accountid, instanceid, nametag, region, slotid, clusterid, commissionedby, commissioned) + VALUES (_accountid, _instanceid, _nametag, _region, _slotid, 10, 'unused', now()); + scheduleResult := 'SUCCESS / Instance ' || _instanceid || ' scheduled in slot: ' || _slotlabel || '.'; + RETURN; + END IF; + ELSEIF _instanceid IN (SELECT instanceid FROM patch40.targets WHERE accountid = _accountid AND (slotid IS NULL OR slotid != _slotid)) THEN + UPDATE patch40.targets SET slotid = _slotid, decommissioned = NULL, decommissionedby = NULL + WHERE accountid = _accountid AND instanceid = _instanceid; + scheduleResult := 'SUCCESS / Instance ' || _instanceid || ' rescheduled to slot: ' || _slotlabel || '.'; + RETURN; + ELSE + SELECT label INTO _eslotlabel FROM patch40.slotdefinitions WHERE slotid = (SELECT slotid FROM patch40.targets WHERE accountid = _accountid AND instanceid = _instanceid); + scheduleResult := 'ERROR / Instance: ' || _instanceid || ' already scheduled in slot: ' || _eslotlabel || '. Please unschedule first.'; + RETURN; + END IF; + scheduleResult := 'ERROR. Unknown condition.'; + RETURN; +END +$$; + + +ALTER FUNCTION patch40.scheduleinstance(_instanceid character varying, _accountid bigint, _slotlabel character varying, OUT scheduleresult character varying) OWNER TO postgres; + +-- +-- TOC entry 384 (class 1255 OID 29352) +-- Name: scheduletmpreschedule(character varying, bigint, bigint, character varying); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.scheduletmpreschedule(_instanceid character varying, _accountid bigint, _cycleid bigint, _altslotlabel character varying, OUT myreturn character varying) RETURNS character varying + LANGUAGE plpgsql + AS $$ +DECLARE + --var_r record; + _cycleLabel character varying; + _altslotid integer; +BEGIN + IF (SELECT count(*) FROM patch40.cycles WHERE cycleid = _cycleid) < 1 THEN + myreturn := 'ERROR / CycleId Not Found' || _cycleid; + RETURN; + ELSE + _cycleLabel := (SELECT label FROM patch40.cycles WHERE cycleid = _cycleid); + END IF; + IF (SELECT count(*) FROM patch40.targets WHERE accountid = _accountid AND instanceid = _instanceid) < 1 THEN + myreturn := 'ERROR / AccountId/InstanceId Not Found.'; + RETURN; + END IF; + IF (SELECT count(*) FROM patch40.slotdefinitions WHERE label = _altslotlabel) < 1 THEN + myreturn := 'ERROR / SlotLabel Not Found.'; + RETURN; + ELSE + _altslotid := (SELECT slotid FROM patch40.slotdefinitions WHERE label = _altslotlabel); + END IF; + IF (SELECT COUNT(*) FROM patch40.reschedules + WHERE cycleid = _cycleid + AND accountid = _accountid + AND instanceid = _instanceid + AND temp_slotid = _altslotid) > 0 + THEN + DELETE FROM patch40.reschedules + WHERE cycleid = _cycleid + AND accountid = _accountid + AND instanceid = _instanceid + AND temp_slotid = _altslotid; + myreturn := 'Successfully removed reschedule during ' || _cycleLabel || ' from ' || _altslotlabel; + ELSE + INSERT INTO patch40.reschedules (cycleid, accountid, instanceid, temp_slotid, requestedby, requestedat) VALUES (_cycleid, _accountid, _instanceid, _altslotid, 'ppinto', now()); + myreturn := 'Successfully added reschedule for ' || _instanceid || ' during ' || _cycleLabel || ' to ' || _altslotlabel; + END IF; + RETURN; +END; +$$; + + +ALTER FUNCTION patch40.scheduletmpreschedule(_instanceid character varying, _accountid bigint, _cycleid bigint, _altslotlabel character varying, OUT myreturn character varying) OWNER TO postgres; + +-- +-- TOC entry 345 (class 1255 OID 29353) +-- Name: scheduletmpreschedule_by_instance(character varying, bigint, bigint, bigint, bigint); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.scheduletmpreschedule_by_instance(_instanceid character varying, _accountid bigint, _cycleid bigint DEFAULT '-1'::integer, _altslotid bigint DEFAULT '-1'::integer, _deletereschedule bigint DEFAULT '-1'::integer) RETURNS TABLE(ocycleid bigint, oclabel character, otemp_slotid bigint, otemp_slotlabel character varying, orequestedby character varying, orequestedat timestamp without time zone) + LANGUAGE plpgsql + AS $$ +DECLARE + var_r record; + tester integer; +BEGIN + IF _deleteReschedule > 0 AND (SELECT COUNT(*) FROM patch40.reschedules + WHERE cycleid = _cycleid + AND accountid = _accountid + AND instanceid = _instanceid + AND temp_slotid = _altslotid) > 1 + THEN + DELETE FROM patch40.reschedules + WHERE cycleid = _cycleid + AND accountid = _accountid + AND instanceid = _instanceid + AND temp_slotid = _altslotid; + ELSEIF _cycleid NOT IN (SELECT cycleid FROM patch40.cycles) THEN + _cycleid = (SELECT cycleid FROM patch40.cycles WHERE label = patch40.currentcycle() ORDER BY start desc limit 13); + ELSEIF (SELECT COUNT(*) FROM patch40.targets WHERE instanceid = _instanceid and accountid = _accountid) > 0 THEN + IF (SELECT COUNT(*) FROM patch40.reschedules WHERE cycleid = _cycleid and accountid = _accountid and instanceid = _instanceid and temp_slotid = _altslotid) > 0 THEN + DELETE FROM patch40.reschedules WHERE cycleid = _cycleid and accountid = _accountid and instanceid = _instanceid and temp_slotid = _altslotid; + ELSEIF _altslotid IN (SELECT slotid FROM patch40.slotdefinitions) THEN + INSERT INTO patch40.reschedules (cycleid, accountid, instanceid, temp_slotid, requestedby, requestedat) VALUES (_cycleid, _accountid, _instanceid, _altslotid, 'ppinto', now()); + END IF; + END IF; + RETURN QUERY + SELECT suba.cycleid, suba.clabel, suba.temp_slotid, suba.slabel, suba.requestedby, suba.requestedat FROM + (SELECT c.cycleid, c.label as clabel, r.temp_slotid, s.label slabel, r.requestedby, r.requestedat + FROM patch40.cycles c + LEFT OUTER JOIN patch40.reschedules r on (c.cycleid = r.cycleid and r.accountid = _accountid and r.instanceid = _instanceid) + LEFT OUTER JOIN patch40.slotdefinitions s on (s.slotid = r.temp_slotid) + ORDER BY c.start DESC LIMIT 13) suba ORDER BY suba.clabel ASC; +END; +$$; + + +ALTER FUNCTION patch40.scheduletmpreschedule_by_instance(_instanceid character varying, _accountid bigint, _cycleid bigint, _altslotid bigint, _deletereschedule bigint) OWNER TO postgres; + +-- +-- TOC entry 385 (class 1255 OID 29354) +-- Name: schedulewaiver(bigint, character varying, bigint); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.schedulewaiver(_accountid bigint, _instanceid character varying, _cycleid bigint) RETURNS TABLE(ocycleid bigint, ocycle character, ostart date, orequester character varying, onotes character varying) + LANGUAGE plpgsql + AS $$ +DECLARE + var_r record; +BEGIN + IF _instanceid NOT IN (SELECT instanceid FROM patch40.targets WHERE accountid = _accountid) THEN + RETURN QUERY SELECT cycleid, label, start, ''::character varying, 'Please select a target to continue'::character varying FROM patch40.qs_cycle_rolling15; + --ELSEIF _cycleid NOT IN (SELECT cycleid FROM patch40.waivers WHERE accountid = _acountid AND instanceid = _instanceid AND cycleid = _cycleid) + -- AND _cycleid in (SELECT cycleid from patch40.cycles) AND _toggle = 1::bool THEN + -- INSERT INTO patch40.waivers (accountid, instanceid, cycleid, requestedby, requestedat) + -- VALUES (_accountid, _instanceid, _cycleid, 'pinto005', now()); + -- RETURN QUERY + -- select c.cycleid, c.label, c.start, w.requestedby, w.notes + -- from patch40.qs_cycle_rolling15 c + -- left outer join patch40.waivers w on (w.cycleid = c.cycleid AND accountid = _accountid AND w.instanceid = _instanceid); + --ELSEIF _cycleid IN (SELECT cycleid from patch40.cycles) AND _toggle = 1::bool THEN + -- DELETE FROM patch40.waivers dw WHERE dw.cycleid = _cycleid AND dw.accountid = _accountid AND dw.instanceid = _instanceid; + -- RETURN QUERY + -- select c.cycleid, c.label, c.start, w.requestedby, w.notes + -- from patch40.qs_cycle_rolling15 c + -- left outer join patch40.waivers w on (w.cycleid = c.cycleid AND w.accountid = c.accountid AND w.instanceid = _instanceid); + ELSE + RETURN QUERY + select c.cycleid, c.label, c.start, w.requestedby, w.notes + from patch40.qs_cycle_rolling15 c + left outer join patch40.waivers w on (w.cycleid = c.cycleid AND w.accountid = _accountid AND w.instanceid = _instanceid); + END IF; +END; +$$; + + +ALTER FUNCTION patch40.schedulewaiver(_accountid bigint, _instanceid character varying, _cycleid bigint) OWNER TO postgres; + +-- +-- TOC entry 386 (class 1255 OID 29355) +-- Name: schedulewaivertoggle(bigint, character varying, bigint, boolean); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.schedulewaivertoggle(_accountid bigint, _instanceid character varying, _cycleid bigint, _toggle boolean DEFAULT (0)::boolean, OUT scheduleresult character varying) RETURNS character varying + LANGUAGE plpgsql + AS $$ +DECLARE + _cycleName character varying; +BEGIN + _cycleName := (SELECT label FROM patch40.cycles WHERE cycleid = _cycleid); + IF _instanceid NOT IN (SELECT instanceid FROM patch40.targets WHERE accountid = _accountid) THEN + scheduleresult := 'Please select a target to continue'::character varying; + ELSEIF _cycleid NOT IN (SELECT cycleid FROM patch40.waivers WHERE accountid = _accountid AND instanceid = _instanceid AND cycleid = _cycleid) + AND _cycleid in (SELECT cycleid from patch40.cycles) AND _toggle = 1::bool THEN + INSERT INTO patch40.waivers (accountid, instanceid, cycleid, requestedby, requestedat) + VALUES (_accountid, _instanceid, _cycleid, 'pinto005', now()); + scheduleresult := 'Toggled waiver for ' || _accountid || '/' || _instanceid ||' during ' || _cycleName || ' to ON.'; + ELSEIF _cycleid IN (SELECT cycleid from patch40.cycles) AND _toggle = 1::bool THEN + DELETE FROM patch40.waivers dw WHERE dw.cycleid = _cycleid AND dw.accountid = _accountid AND dw.instanceid = _instanceid; + scheduleresult := 'Toggled waiver for ' || _accountid || '/' || _instanceid ||' during ' || _cycleName || ' to OFF.'; + ELSE + scheduleresult := 'ERROR / Implausible task.'; + END IF; + RETURN; +END; +$$; + + +ALTER FUNCTION patch40.schedulewaivertoggle(_accountid bigint, _instanceid character varying, _cycleid bigint, _toggle boolean, OUT scheduleresult character varying) OWNER TO postgres; + +-- +-- TOC entry 353 (class 1255 OID 29356) +-- Name: scheduling_slotoccupancy(character varying, bigint, bigint, character, bigint, character varying, character varying, character varying, uuid); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.scheduling_slotoccupancy(_instanceid character varying DEFAULT 'noneSelected'::character varying, _accountid bigint DEFAULT '-1'::bigint, _cycleid bigint DEFAULT '-1'::bigint, _cyclename character DEFAULT 'DEFAULT'::bpchar, _slotid bigint DEFAULT '-1'::bigint, _slotlabel character varying DEFAULT 'noneSelected'::character varying, _task character varying DEFAULT 'noneSelected'::character varying, _requester character varying DEFAULT 'unspecified'::character varying, _guid uuid DEFAULT NULL::uuid) RETURNS TABLE(slotid integer, label character varying, durationminutes integer, dayofweek integer, weekcounter integer, count integer, thisuuid uuid, message character varying) + LANGUAGE plpgsql + AS $$ +DECLARE + var_r record; + var_uuid uuid; +BEGIN + IF _guid = 'dad1fb71-a8e5-419b-832b-de8b15000687'::uuid OR _guid IN (SELECT uid FROM patch40.uids) THEN + RETURN QUERY + SELECT so.slotid, so.label, so.durationminutes, so.dayofweek, so.weekcounter, so.count::integer + , _guid, 'No action taken'::character varying FROM patch40.qs_slot_occupancy_top so; + var_uuid := gen_random_uuid(); + ELSEIF _task = 'PermSchedule' THEN + INSERT INTO patch40.uids (uid, task) VALUES (_guid, _task); + RETURN QUERY + SELECT so.slotid, so.label, so.durationminutes, so.dayofweek, so.weekcounter, so.count::integer + , var_uuid, 'peter'::character varying FROM patch40.qs_slot_occupancy_top so; + END IF; +END; +$$; + + +ALTER FUNCTION patch40.scheduling_slotoccupancy(_instanceid character varying, _accountid bigint, _cycleid bigint, _cyclename character, _slotid bigint, _slotlabel character varying, _task character varying, _requester character varying, _guid uuid) OWNER TO postgres; + +-- +-- TOC entry 355 (class 1255 OID 29357) +-- Name: slotdefinitons_insert(); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.slotdefinitons_insert() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN + NEW.label := (CONCAT(NEW.weekcounter::varchar,patch40."numSuffix"(NEW.weekcounter),'_',patch40."weekdayFromNumber"(NEW.dayofweek),'_',to_char(NEW.starttime,'HH24'),to_char(NEW.starttime,'MI'))); + RETURN NEW; +END; +$$; + + +ALTER FUNCTION patch40.slotdefinitons_insert() OWNER TO postgres; + +-- +-- TOC entry 364 (class 1255 OID 40274) +-- Name: sp_dispatcher(); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.sp_dispatcher() + LANGUAGE plpgsql + AS $$ +DECLARE + rec patch40.dispatcher%ROWTYPE; + rows_data patch40.dispatcher[]; + row_count BIGINT := 0; + lambdaarn TEXT; + ruid BIGINT := -1; + final_payload jsonb; + status_code INTEGER; +BEGIN + -- 1. Get the Router Lambda ARN + SELECT "value" INTO lambdaarn FROM patch40.config WHERE "key" = 'dispatch_lambda_arn'; + + IF lambdaarn IS NULL THEN + RAISE EXCEPTION 'Configuration key "dispatch_lambda_arn" not found in patch40.config'; + END IF; + + -- 2. Load rows + SELECT array_agg(d.*) INTO rows_data FROM (SELECT * FROM patch40.dispatcher LIMIT 200) d; + + IF rows_data IS NULL THEN + RETURN; + END IF; + + FOREACH rec IN ARRAY rows_data + LOOP + -- 3. Create the Execution record + INSERT INTO patch40.executions ( + cycleid, slotid, clusterid, patchid, automationarn, + receivedtime, sequence_step, statusid, lastupdatetime, + executiontypeid, sequence_id, sequence_type + ) + VALUES ( + rec.cycleid, rec.slotid, rec.clusterid, rec.patchid, rec.automation, + now(), rec.sequence_step, 0, now(), 2, rec.sequence_id, rec.sequence_type + ) + RETURNING uid INTO ruid; + -- Early skips (these also update the executions table) + IF rec.skip_if_onprem AND rec.accountid IS NULL THEN + --UPDATE patch40.executions SET statusid = 2900 WHERE uid = ruid; + CALL patch40.sp_step_update(ruid, 2900); + CONTINUE; + END IF; + IF rec.related_runstate_check IS NOT NULL AND rec.related_runstate_check > 0 THEN + IF rec.found_runstate_status = 2905 THEN + UPDATE patch40.executions SET statusid = 6905 WHERE uid = ruid; + CONTINUE; + END IF; + IF rec.related_runstate_check = 2900 THEN + UPDATE patch40.executions SET statusid = 6900 WHERE uid = ruid; + CONTINUE; + END IF; + END IF; + -- 4. FLATTENED PAYLOAD: Merges the UID/Type with all columns from the dispatcher view + -- We convert the record to jsonb and merge in our specific keys + final_payload := to_jsonb(rec) || jsonb_build_object('uid', ruid, 'dispatch_type', rec.dispatch_type); + + -- 5. Invoke + SELECT mycall.status_code INTO status_code + FROM aws_lambda.invoke( + aws_commons.create_lambda_function_arn(lambdaarn, 'us-gov-east-1'), + final_payload, + 'Event' + ) AS mycall; + + -- 6. Cleanup on Failure + IF status_code IS NULL OR status_code != 202 THEN + DELETE FROM patch40.executions WHERE uid = ruid; + END IF; + + END LOOP; +END; +$$; + + +ALTER PROCEDURE patch40.sp_dispatcher() OWNER TO postgres; + +-- +-- TOC entry 378 (class 1255 OID 42915) +-- Name: sp_g_step_action(uuid, character varying, text); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.sp_g_step_action(IN _patchid uuid, IN _requester character varying, IN _action text) + LANGUAGE plpgsql + AS $$ +DECLARE _lastexec RECORD; +BEGIN + SELECT * INTO _lastexec FROM patch40.g_target_last_executed_in_cycle_by_sequence_and_patchid(patch40.currentcycleid(), 2, _patchid); + CASE _action + WHEN 'Retry' THEN CALL patch40.sp_g_step_retry(_lastexec.uid, _requester); + WHEN 'Next' THEN CALL patch40.sp_g_step_next(_lastexec.uid, _requester); + WHEN 'Done' THEN CALL patch40.sp_g_step_done(_patchid, _requester); + END CASE; +END; +$$; + + +ALTER PROCEDURE patch40.sp_g_step_action(IN _patchid uuid, IN _requester character varying, IN _action text) OWNER TO postgres; + +-- +-- TOC entry 383 (class 1255 OID 42791) +-- Name: sp_g_step_done(uuid, character varying); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.sp_g_step_done(IN _patchid uuid, IN _requester character varying) + LANGUAGE plpgsql + AS $$ +DECLARE + _dispatcher patch40.dispatcher%ROWTYPE; + _execution patch40.executions%ROWTYPE; + _cyclesteps patch40.cycle_steps_patch%ROWTYPE; + _ruid bigint; + final_payload jsonb; + status_code integer; + lambdaarn text; + _laststep integer; +BEGIN + + SELECT "value" INTO lambdaarn FROM patch40.config WHERE "key" = 'dispatch_lambda_arn'; + SELECT * INTO _execution FROM patch40.executions WHERE patchid = _patchid ORDER BY lastupdatetime DESC LIMIT 1; + IF _execution.uid IS NOT NULL THEN + INSERT INTO patch40.executions( + cycleid, slotid, clusterid, patchid, + automationarn, receivedtime, sequence_step, statusid, + lastupdatetime, executiontypeid, sequence_id, sequence_type + ) + SELECT cycleid, slotid, clusterid, patchid, + 'sp_step_done', now(), sequence_step, 3300, + now(), dispatch_type, sequence_id, sequence_type + FROM patch40.cycle_steps_patch + WHERE patchid = _patchid AND sequence_step = _execution.sequence_step + RETURNING uid INTO _ruid; + _laststep := _execution.sequence_step; + ELSE + SELECT * INTO _dispatcher FROM patch40.dispatch_done(_patchid); + INSERT INTO patch40.executions ( + cycleid, slotid, clusterid, patchid, + automationarn, receivedtime, sequence_step, statusid, + lastupdatetime, executiontypeid, sequence_id, sequence_type + ) + VALUES ( + _dispatcher.cycleid, _dispatcher.slotid, _dispatcher.clusterid, _dispatcher.patchid, + 'sp_step_done', now(), _dispatcher.sequence_step, 2300, + now(), _dispatcher.dispatch_type, _dispatcher.sequence_id, _dispatcher.sequence_type + ) + RETURNING uid INTO _ruid; + _laststep := 1::integer; + END IF; + INSERT INTO patch40.audit_done(uid, requester, requestedat) VALUES (_ruid, _requester, now()); + COMMIT; + FOR _cyclesteps IN SELECT * FROM patch40.cycle_steps_patch WHERE patchid = _patchid AND sequence_step > _laststep LOOP + IF NOT _cyclesteps.run_if_done THEN + INSERT INTO patch40.executions ( + cycleid, slotid, clusterid, patchid, + automationarn, receivedtime, sequence_step, statusid, + lastupdatetime, executiontypeid, sequence_id, sequence_type + ) + VALUES ( + _cyclesteps.cycleid, _cyclesteps.slotid, _cyclesteps.clusterid, _cyclesteps.patchid, + 'sp_step_done', now(), _cyclesteps.sequence_step, 2300, + now(), 2, _cyclesteps.sequence_id, _cyclesteps.sequence_type + ); + END IF; + END LOOP; + COMMIT; + SELECT * INTO _dispatcher FROM patch40.dispatcher WHERE patchid = _patchid; + WHILE _dispatcher.sequence_step IS NOT NULL LOOP + INSERT INTO patch40.executions ( + cycleid, slotid, clusterid, patchid, + automationarn, receivedtime, sequence_step, statusid, + lastupdatetime, executiontypeid, sequence_id, sequence_type + ) + VALUES ( + _dispatcher.cycleid, _dispatcher.slotid, _dispatcher.clusterid, _dispatcher.patchid, + 'sp_step_update', now(), _dispatcher.sequence_step, 0, + now(), 2, _dispatcher.sequence_id, _dispatcher.sequence_type + ) + RETURNING uid INTO _ruid; + IF _dispatcher.skip_if_onprem AND _dispatcher.accountid IS NULL THEN + UPDATE patch40.executions SET statusid = 6900 WHERE uid = _ruid; + COMMIT; + SELECT * FROM patch40.dispatcher INTO _dispatcher WHERE patchid = _patchid; + CONTINUE; + END IF; + IF _dispatcher.related_runstate_check IS NOT NULL AND _dispatcher.found_runstate_status IN (2905, 2925) THEN + IF _dispatcher.found_runstate_status = 2905 THEN + UPDATE patch40.executions SET statusid = 6905 WHERE uid = _ruid; + ELSIF _dispatcher.related_runstate_check = 2925 THEN + UPDATE patch40.executions SET statusid = 6925 WHERE uid = _ruid; + END IF; + COMMIT; + SELECT * FROM patch40.dispatcher INTO _dispatcher WHERE patchid = _patchid; + CONTINUE; + END IF; + final_payload := to_jsonb(_dispatcher) || jsonb_build_object('uid', _ruid, 'dispatch_type', _dispatcher.dispatch_type); + SELECT mycall.status_code INTO status_code + FROM aws_lambda.invoke( + aws_commons.create_lambda_function_arn(lambdaarn, 'us-gov-east-1'), + final_payload, + 'Event' + ) AS mycall; + _dispatcher.sequence_step := NULL; + END LOOP; +END; +$$; + + +ALTER PROCEDURE patch40.sp_g_step_done(IN _patchid uuid, IN _requester character varying) OWNER TO postgres; + +-- +-- TOC entry 390 (class 1255 OID 42744) +-- Name: sp_g_step_next(bigint, character varying); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.sp_g_step_next(IN _uid bigint, IN _requester character varying) + LANGUAGE plpgsql + AS $$ +DECLARE + _dispatcher patch40.dispatcher%ROWTYPE; + _execution patch40.executions%ROWTYPE; + ruid bigint; + final_payload jsonb; + status_code integer; + lambdaarn text; +BEGIN + INSERT INTO patch40.audit_next(uid, requester, requestedat) VALUES (_uid, _requester, now()); + SELECT "value" INTO lambdaarn FROM patch40.config WHERE "key" = 'dispatch_lambda_arn'; + SELECT * FROM patch40.executions INTO _execution WHERE uid = _uid; + RAISE INFO 'Record: %', _execution.patchid; + UPDATE patch40.executions SET statusid = 2100 WHERE uid = _uid; + COMMIT; + SELECT * FROM patch40.dispatcher INTO _dispatcher WHERE patchid = _execution.patchid; + WHILE _dispatcher.sequence_step IS NOT NULL LOOP + INSERT INTO patch40.executions ( + cycleid, slotid, clusterid, patchid, + automationarn, receivedtime, sequence_step, statusid, + lastupdatetime, executiontypeid, sequence_id, sequence_type + ) + VALUES ( + _dispatcher.cycleid, _dispatcher.slotid, _dispatcher.clusterid, _dispatcher.patchid, + 'sp_step_update', now(), _dispatcher.sequence_step, 0, + now(), 2, _dispatcher.sequence_id, _dispatcher.sequence_type + ) + RETURNING uid INTO ruid; + IF _dispatcher.skip_if_onprem AND _dispatcher.accountid IS NULL THEN + RAISE NOTICE 'Skipping for on-prem'; + UPDATE patch40.executions SET statusid = 6900 WHERE uid = ruid; + COMMIT; + SELECT * FROM patch40.dispatcher INTO _dispatcher WHERE patchid = _patchid; + CONTINUE; + END IF; + IF _dispatcher.related_runstate_check IS NOT NULL AND _dispatcher.found_runstate_status IN (2905, 2925) THEN + RAISE NOTICE 'Processing related runstate check'; + IF _dispatcher.found_runstate_status = 2905 THEN + UPDATE patch40.executions SET statusid = 6905 WHERE uid = ruid; + ELSIF _dispatcher.related_runstate_check = 2925 THEN + UPDATE patch40.executions SET statusid = 6925 WHERE uid = ruid; + END IF; + COMMIT; + SELECT * FROM patch40.dispatcher INTO _dispatcher WHERE patchid = _patchid; + CONTINUE; + END IF; + final_payload := to_jsonb(_dispatcher) || jsonb_build_object('uid', ruid, 'dispatch_type', _dispatcher.dispatch_type); + SELECT mycall.status_code INTO status_code + FROM aws_lambda.invoke( + aws_commons.create_lambda_function_arn(lambdaarn, 'us-gov-east-1'), + final_payload, + 'Event' + ) AS mycall; + _dispatcher.sequence_step := NULL; + END LOOP; +END; +$$; + + +ALTER PROCEDURE patch40.sp_g_step_next(IN _uid bigint, IN _requester character varying) OWNER TO postgres; + +-- +-- TOC entry 370 (class 1255 OID 42715) +-- Name: sp_g_step_retry(bigint, character varying); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.sp_g_step_retry(IN _uid bigint, IN _requester character varying) + LANGUAGE plpgsql + AS $$ +DECLARE + _dispatcher patch40.dispatcher%ROWTYPE; + _execution patch40.executions%ROWTYPE; + ruid bigint; + final_payload jsonb; + status_code integer; + lambdaarn text; +BEGIN + INSERT INTO patch40.audit_retry(uid, requester, requestedat) VALUES (_uid, _requester, now()); + SELECT "value" INTO lambdaarn FROM patch40.config WHERE "key" = 'dispatch_lambda_arn'; + SELECT * FROM patch40.executions INTO _execution WHERE uid = _uid; + INSERT INTO patch40.executions ( + cycleid, slotid, clusterid, patchid, + automationarn, receivedtime, sequence_step, statusid, + lastupdatetime, executiontypeid, sequence_id, sequence_type + ) + VALUES ( + _execution.cycleid, _execution.slotid, _execution.clusterid, _execution.patchid, + 'sp_g_step_retry', now(), _execution.sequence_step, 3200, + now(), 2, _execution.sequence_id, _execution.sequence_type + ) + RETURNING uid INTO ruid; + COMMIT; + SELECT * FROM patch40.dispatcher INTO _dispatcher WHERE patchid = _execution.patchid; + final_payload := to_jsonb(_dispatcher) || jsonb_build_object('uid', ruid, 'dispatch_type', _dispatcher.dispatch_type); + SELECT mycall.status_code INTO status_code + FROM aws_lambda.invoke( + aws_commons.create_lambda_function_arn(lambdaarn, 'us-gov-east-1'), + final_payload, + 'Event' + ) AS mycall; + _dispatcher.sequence_step := NULL; +END; +$$; + + +ALTER PROCEDURE patch40.sp_g_step_retry(IN _uid bigint, IN _requester character varying) OWNER TO postgres; + +-- +-- TOC entry 357 (class 1255 OID 40201) +-- Name: sp_remote_exec_output(bigint, integer, text, text); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.sp_remote_exec_output(IN in_uid bigint, IN in_rc integer, IN in_stdout text, IN in_stderr text) + LANGUAGE plpgsql + AS $$ +DECLARE +BEGIN + INSERT INTO patch40.execution_output (uid, stdout, stderr, rc) + VALUES (in_uid, in_stdout, in_stderr, in_rc); +END; +$$; + + +ALTER PROCEDURE patch40.sp_remote_exec_output(IN in_uid bigint, IN in_rc integer, IN in_stdout text, IN in_stderr text) OWNER TO postgres; + +-- +-- TOC entry 359 (class 1255 OID 40204) +-- Name: sp_step_received(bigint, integer, integer, integer, integer, uuid, character varying, integer); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.sp_step_received(IN in_cycleid bigint, IN in_slotid integer, IN in_sequence_type integer, IN in_sequence_id integer, IN in_clusterid integer, IN in_patchid uuid, IN in_automationarn character varying, IN in_sequence_step integer, OUT out_uid bigint) + LANGUAGE plpgsql SECURITY DEFINER + SET search_path TO 'patch40', 'pg_temp' + AS $$ +BEGIN + INSERT INTO patch40.executions ( + cycleid, + slotid, + sequence_type, + sequence_id, + clusterid, + patchid, + automationarn, + receivedtime, + sequence_step, + statusid, + lastupdatetime, + executiontypeid + ) + VALUES ( + in_cycleid, + in_slotid, + in_sequence_type, + in_sequence_id, + in_clusterid, + in_patchid, + in_automationarn, + now(), + in_sequence_step, + 1000, -- Received status + now(), + 1 -- Execution type + ) + RETURNING uid INTO out_uid; + +END; +$$; + + +ALTER PROCEDURE patch40.sp_step_received(IN in_cycleid bigint, IN in_slotid integer, IN in_sequence_type integer, IN in_sequence_id integer, IN in_clusterid integer, IN in_patchid uuid, IN in_automationarn character varying, IN in_sequence_step integer, OUT out_uid bigint) OWNER TO postgres; + +-- +-- TOC entry 363 (class 1255 OID 40357) +-- Name: sp_step_update(bigint, integer); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.sp_step_update(IN in_uid bigint, IN in_statusid integer) + LANGUAGE plpgsql + AS $$ +DECLARE + _dispatcher patch40.dispatcher%ROWTYPE; + _patchid uuid; + ruid bigint; + final_payload jsonb; + status_code integer; + lambdaarn text; +BEGIN + SELECT patchid INTO _patchid FROM patch40.executions WHERE uid = in_uid; + UPDATE patch40.executions + SET + lastupdatetime = now(), + statusid = in_statusid + WHERE uid = in_uid; + COMMIT; + SELECT "value" INTO lambdaarn FROM patch40.config WHERE "key" = 'dispatch_lambda_arn'; + SELECT * FROM patch40.dispatcher INTO _dispatcher WHERE patchid = _patchid; + WHILE _dispatcher.sequence_step IS NOT NULL LOOP + INSERT INTO patch40.executions ( + cycleid, slotid, clusterid, patchid, + automationarn, receivedtime, sequence_step, statusid, + lastupdatetime, executiontypeid, sequence_id, sequence_type + ) + VALUES ( + _dispatcher.cycleid, _dispatcher.slotid, _dispatcher.clusterid, _dispatcher.patchid, + 'sp_step_update', now(), _dispatcher.sequence_step, 0, + now(), 2, _dispatcher.sequence_id, _dispatcher.sequence_type + ) + RETURNING uid INTO ruid; + IF _dispatcher.skip_if_onprem AND _dispatcher.accountid IS NULL THEN + RAISE NOTICE 'Skipping for on-prem'; + UPDATE patch40.executions SET statusid = 6900 WHERE uid = ruid; + COMMIT; + SELECT * FROM patch40.dispatcher INTO _dispatcher WHERE patchid = _patchid; + CONTINUE; + END IF; + IF _dispatcher.related_runstate_check IS NOT NULL AND _dispatcher.found_runstate_status IN (2905, 2925) THEN + RAISE NOTICE 'Processing related runstate check'; + IF _dispatcher.found_runstate_status = 2905 THEN + UPDATE patch40.executions SET statusid = 6905 WHERE uid = ruid; + ELSIF _dispatcher.related_runstate_check = 2925 THEN + UPDATE patch40.executions SET statusid = 6925 WHERE uid = ruid; + END IF; + COMMIT; + SELECT * FROM patch40.dispatcher INTO _dispatcher WHERE patchid = _patchid; + CONTINUE; + END IF; + final_payload := to_jsonb(_dispatcher) || jsonb_build_object('uid', ruid, 'dispatch_type', _dispatcher.dispatch_type); + SELECT mycall.status_code INTO status_code + FROM aws_lambda.invoke( + aws_commons.create_lambda_function_arn(lambdaarn, 'us-gov-east-1'), + final_payload, + 'Event' + ) AS mycall; + _dispatcher.sequence_step := NULL; + END LOOP; +END; +$$; + + +ALTER PROCEDURE patch40.sp_step_update(IN in_uid bigint, IN in_statusid integer) OWNER TO postgres; + +-- +-- TOC entry 360 (class 1255 OID 40468) +-- Name: sp_step_update_processing(bigint); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.sp_step_update_processing(IN in_uid bigint) + LANGUAGE plpgsql + AS $$ +DECLARE + _rowcount integer := 0; +BEGIN + -- Perform the update on the executions table + SELECT COUNT(*) INTO _rowcount FROM patch40.executions WHERE uid = in_uid AND (statusid = 0 OR statusid BETWEEN 3000 AND 3999); + IF _rowcount > 0 THEN + UPDATE patch40.executions + SET + lastupdatetime = now(), + statusid = 1010 + WHERE uid = in_uid; + ELSE + RAISE EXCEPTION 'UID: % not found with statusid = 0', in_uid; + END IF; +END; +$$; + + +ALTER PROCEDURE patch40.sp_step_update_processing(IN in_uid bigint) OWNER TO postgres; + +-- +-- TOC entry 361 (class 1255 OID 40466) +-- Name: sp_step_update_processing(bigint, integer); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.sp_step_update_processing(IN in_uid bigint, IN in_statusid integer) + LANGUAGE plpgsql + AS $$ +DECLARE + _rowcount integer := 0; +BEGIN + -- Perform the update on the executions table + SELECT COUNT(*) INTO _rowcount FROM patch40.executions WHERE uid = in_uid AND statusid = 0; + UPDATE patch40.executions + SET + lastupdatetime = now(), + statusid = in_statusid + WHERE uid = in_uid; + + -- Procedures do not use RETURN. + -- If you need to signal success/failure, use RAISE NOTICE or let exceptions bubble up. +END; +$$; + + +ALTER PROCEDURE patch40.sp_step_update_processing(IN in_uid bigint, IN in_statusid integer) OWNER TO postgres; + +-- +-- TOC entry 362 (class 1255 OID 40407) +-- Name: sp_sw_store_existing(bigint, timestamp without time zone, timestamp without time zone); Type: PROCEDURE; Schema: patch40; Owner: postgres +-- + +CREATE PROCEDURE patch40.sp_sw_store_existing(IN in_uid bigint, IN in_suppressedfrom timestamp without time zone, IN in_suppresseduntil timestamp without time zone) + LANGUAGE plpgsql + AS $$ +DECLARE + has_record boolean; +-- my_statusid integer; +-- has_errors boolean; + +BEGIN + SELECT EXISTS ( + SELECT 1 + FROM patch40.solarwinds_suppression + WHERE uid = in_uid + ) INTO has_record; + + IF NOT has_record THEN + INSERT INTO patch40.solarwinds_suppression(uid, suppressedfrom, suppresseduntil) + VALUES (in_uid, in_suppressedfrom, in_suppresseduntil); + END IF; +END; +$$; + + +ALTER PROCEDURE patch40.sp_sw_store_existing(IN in_uid bigint, IN in_suppressedfrom timestamp without time zone, IN in_suppresseduntil timestamp without time zone) OWNER TO postgres; + +-- +-- TOC entry 354 (class 1255 OID 29358) +-- Name: step_launched(bigint, character varying); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.step_launched(in_uid bigint, in_arn character varying) RETURNS character varying + LANGUAGE plpgsql + AS $$ +DECLARE + my_uid bigint; +BEGIN + UPDATE patch40.executions + SET + automationarn = in_arn, + startautomationtime = now(), + lastupdatetime = now(), + statusid = 1010 + WHERE uid = in_uid; + RETURN 'success'; +END; +$$; + + +ALTER FUNCTION patch40.step_launched(in_uid bigint, in_arn character varying) OWNER TO postgres; + +-- +-- TOC entry 387 (class 1255 OID 29846) +-- Name: step_received(bigint, integer, integer, integer, integer, uuid, character varying, integer); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.step_received(in_cycleid bigint, in_slotid integer, in_sequence_type integer, in_sequence_id integer, in_clusterid integer, in_patchid uuid, in_automationarn character varying, in_sequence_step integer) RETURNS character varying + LANGUAGE plpgsql + AS $$ +DECLARE + my_uid bigint; +BEGIN + INSERT INTO patch40.executions ( + cycleid, + slotid, + sequence_type, + sequence_id, + clusterid, + patchid, + automationarn, + receivedtime, + sequence_step, + statusid, + lastupdatetime, + executiontypeid + ) + VALUES ( + in_cycleid, + in_slotid, + in_sequence_type, + in_sequence_id, + in_clusterid, + in_patchid, + in_automationarn, + now(), + in_sequence_step, + 1000, + now(), + 1 + ) RETURNING uid into my_uid; + RETURN my_uid; +END; +$$; + + +ALTER FUNCTION patch40.step_received(in_cycleid bigint, in_slotid integer, in_sequence_type integer, in_sequence_id integer, in_clusterid integer, in_patchid uuid, in_automationarn character varying, in_sequence_step integer) OWNER TO postgres; + +-- +-- TOC entry 356 (class 1255 OID 40177) +-- Name: step_result(bigint, integer, integer); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.step_result(in_uid bigint, in_statusid integer, in_sentstatus integer) RETURNS character varying + LANGUAGE plpgsql + AS $$ +DECLARE + my_statusid integer; +BEGIN + IF (select count(*) rc from patch40.execution_output WHERE uid = in_uid and rc <> 0) > 0 THEN + IF in_sentstatus < 3000 OR in_sentstatus > 3999 THEN + my_statusid := 4000; + ELSE + my_statusid := in_sentstatus + 1000; + END IF; + ELSE + my_statusid := in_statusid; + END IF; + + UPDATE patch40.executions + SET + completiontime = now(), + lastupdatetime = now(), + statusid = my_statusid + WHERE uid = in_uid; + RETURN 'success'; +END; +$$; + + +ALTER FUNCTION patch40.step_result(in_uid bigint, in_statusid integer, in_sentstatus integer) OWNER TO postgres; + +-- +-- TOC entry 346 (class 1255 OID 29361) +-- Name: thatpatchtuesday(date); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.thatpatchtuesday(_indate date) RETURNS date + LANGUAGE plpgsql + AS $$ + + DECLARE + cpt date; + fday varchar(20); + tcounter int := 0; + BEGIN + --fday := to_char(now(), 'YYYYMM01'); + fday := to_char(_inDate, 'YYYYMM01'); + cpt := to_date(fday, 'YYYYMMDD'); + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + WHILE tcounter < 2 LOOP + cpt := cpt + 1; + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + END LOOP; + IF now() < cpt THEN + tcounter := 0; + fday := to_char(cpt - interval '1 month', 'YYYYMM01'); + cpt := to_date(fday, 'YYYYMMDD'); + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + WHILE tcounter < 2 LOOP + cpt := cpt + 1; + IF to_char(cpt, 'ID') = '2' THEN + tcounter := tcounter + 1; + END IF; + END LOOP; + END IF; + RETURN cpt; + END; + +$$; + + +ALTER FUNCTION patch40.thatpatchtuesday(_indate date) OWNER TO postgres; + +-- +-- TOC entry 382 (class 1255 OID 29362) +-- Name: unscheduleinstance(bigint, character varying); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40.unscheduleinstance(_accountid bigint, _instanceid character varying, OUT unscheduleresult character varying) RETURNS character varying + LANGUAGE plpgsql + AS $$ +DECLARE + _nametag character varying; + _slotid bigint; + _slotlabel character varying; +BEGIN + IF _instanceid NOT IN (SELECT instanceid FROM patch40.targets WHERE accountid = _accountid AND slotid IS NOT NULL) + THEN + unscheduleResult := 'Input of ' || _instanceid || ' had no match at ' || (select to_char(CURRENT_TIMESTAMP, 'yyyy-mm-dd hh24:mi:ss')); + ELSE + SELECT slotid INTO _slotid FROM patch40.targets WHERE instanceid = _instanceid; + UPDATE patch40.targets + SET slotid = NULL, decommissioned = now(), decommissionedby = 'unsupported' + WHERE accountid = _accountid AND instanceid = _instanceid; + -- --RETURNING nametag INTO _nametag; + SELECT nametag INTO _nametag from patch40.targets where instanceid = _instanceid; + SELECT label into _slotlabel FROM patch40.slotdefinitions where slotid = _slotid; + unscheduleResult := _nametag || ' (' || _instanceid || ') was unscheduled from ' || _slotlabel || ' at ' || (select to_char(CURRENT_TIMESTAMP, 'yyyy-mm-dd hh24:mi:ss')); + END IF; + RETURN; +END +$$; + + +ALTER FUNCTION patch40.unscheduleinstance(_accountid bigint, _instanceid character varying, OUT unscheduleresult character varying) OWNER TO postgres; + +-- +-- TOC entry 347 (class 1255 OID 29363) +-- Name: weekdayFromNumber(integer); Type: FUNCTION; Schema: patch40; Owner: postgres +-- + +CREATE FUNCTION patch40."weekdayFromNumber"(innumber integer) RETURNS character varying + LANGUAGE plpgsql + AS $$ +BEGIN + DROP TABLE IF EXISTS tmp_iteration; + CREATE TEMP TABLE IF NOT EXISTS tmp_iteration( + id serial PRIMARY KEY, + iterate char(3) + ); + + INSERT INTO + tmp_iteration (iterate) + VALUES + ('SUN'), + ('MON'), + ('TUE'), + ('WED'), + ('THU'), + ('FRI'), + ('SAT'); + RETURN (SELECT iterate FROM tmp_iteration where (id - 1) = innumber); +END; +$$; + + +ALTER FUNCTION patch40."weekdayFromNumber"(innumber integer) OWNER TO postgres; + +-- +-- TOC entry 250 (class 1259 OID 29370) +-- Name: archive_ec2inventory; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.archive_ec2inventory ( + collectiondate date NOT NULL, + accountid bigint NOT NULL, + instanceid character varying(50) NOT NULL, + nametag character varying(128), + reservationid character varying(50), + region character varying(20) NOT NULL, + launchtime timestamp without time zone, + privateipaddress character varying(30), + state character varying(20), + collectiontime timestamp without time zone NOT NULL +); + + +ALTER TABLE patch40.archive_ec2inventory OWNER TO postgres; + +-- +-- TOC entry 251 (class 1259 OID 29373) +-- Name: archive_satellite; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.archive_satellite ( + collectiondate date NOT NULL, + inserttime timestamp without time zone, + id bigint NOT NULL, + name character varying(128), + ip character(16), + ip6 character(40), + operatingsystem_name character varying(64), + architecture_name character varying(32), + kernel_version character varying(64), + model_name character varying(32), + hostgroup_name character varying(32), + hostgroup_title character varying(128), + location_name character varying(32), + created_at timestamp without time zone, + mac character varying(17), + last_checkin timestamp without time zone, + boot_time timestamp without time zone +); + + +ALTER TABLE patch40.archive_satellite OWNER TO postgres; + +-- +-- TOC entry 304 (class 1259 OID 42753) +-- Name: audit_done; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.audit_done ( + uid bigint NOT NULL, + requester character varying(24) NOT NULL, + requestedat timestamp without time zone NOT NULL +); + + +ALTER TABLE patch40.audit_done OWNER TO postgres; + +-- +-- TOC entry 303 (class 1259 OID 42734) +-- Name: audit_next; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.audit_next ( + uid bigint NOT NULL, + requester character varying(24) NOT NULL, + requestedat timestamp without time zone NOT NULL +); + + +ALTER TABLE patch40.audit_next OWNER TO postgres; + +-- +-- TOC entry 302 (class 1259 OID 42703) +-- Name: audit_retry; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.audit_retry ( + uid bigint NOT NULL, + requester character varying(24) NOT NULL, + requestedat timestamp without time zone NOT NULL +); + + +ALTER TABLE patch40.audit_retry OWNER TO postgres; + +-- +-- TOC entry 253 (class 1259 OID 29388) +-- Name: clusters; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.clusters ( + clusterid integer NOT NULL, + clustername character varying(128), + prechecks_tminus_hours smallint, + precheck_sequence integer, + patch_sequence integer, + validation_sequence integer, + escalation_sequence integer, + notes character varying(2048) +); + + +ALTER TABLE patch40.clusters OWNER TO postgres; + +-- +-- TOC entry 292 (class 1259 OID 40088) +-- Name: config; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.config ( + key character varying(32) NOT NULL, + value text +); + + +ALTER TABLE patch40.config OWNER TO postgres; + +-- +-- TOC entry 301 (class 1259 OID 42609) +-- Name: csps; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.csps ( + cspid integer NOT NULL, + label character varying(64) NOT NULL +); + + +ALTER TABLE patch40.csps OWNER TO postgres; + +-- +-- TOC entry 254 (class 1259 OID 29393) +-- Name: cycles; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.cycles ( + cycleid bigint NOT NULL, + label character(7) NOT NULL, + start date, + notes character varying(2048) +); + + +ALTER TABLE patch40.cycles OWNER TO postgres; + +-- +-- TOC entry 255 (class 1259 OID 29398) +-- Name: cycles_cycleid_seq; Type: SEQUENCE; Schema: patch40; Owner: postgres +-- + +ALTER TABLE patch40.cycles ALTER COLUMN cycleid ADD GENERATED ALWAYS AS IDENTITY ( + SEQUENCE NAME patch40.cycles_cycleid_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + + +-- +-- TOC entry 286 (class 1259 OID 34317) +-- Name: dispatch_history; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.dispatch_history ( + uid bigint NOT NULL, + "timestamp" timestamp without time zone, + status_code integer, + payload json, + executed_version text, + log_result text +); + + +ALTER TABLE patch40.dispatch_history OWNER TO postgres; + +-- +-- TOC entry 285 (class 1259 OID 34316) +-- Name: dispatch_history_uid_seq; Type: SEQUENCE; Schema: patch40; Owner: postgres +-- + +ALTER TABLE patch40.dispatch_history ALTER COLUMN uid ADD GENERATED ALWAYS AS IDENTITY ( + SEQUENCE NAME patch40.dispatch_history_uid_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + + +-- +-- TOC entry 291 (class 1259 OID 38741) +-- Name: dispatch_types; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.dispatch_types ( + dtypeid integer NOT NULL, + label character varying(32) NOT NULL +); + + +ALTER TABLE patch40.dispatch_types OWNER TO postgres; + +-- +-- TOC entry 287 (class 1259 OID 34329) +-- Name: enable_dispatcher; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.enable_dispatcher ( + enabled boolean NOT NULL, + type character varying(24) NOT NULL +); + + +ALTER TABLE patch40.enable_dispatcher OWNER TO postgres; + +-- +-- TOC entry 276 (class 1259 OID 29660) +-- Name: execution_output; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.execution_output ( + uid bigint NOT NULL, + stdout text, + stderr text, + rc integer +); + + +ALTER TABLE patch40.execution_output OWNER TO postgres; + +-- +-- TOC entry 257 (class 1259 OID 29404) +-- Name: executions_uid_seq; Type: SEQUENCE; Schema: patch40; Owner: postgres +-- + +ALTER TABLE patch40.executions ALTER COLUMN uid ADD GENERATED ALWAYS AS IDENTITY ( + SEQUENCE NAME patch40.executions_uid_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + + +-- +-- TOC entry 258 (class 1259 OID 29405) +-- Name: executiontypes; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.executiontypes ( + executiontypeid bigint NOT NULL, + executiontype character varying(32) +); + + +ALTER TABLE patch40.executiontypes OWNER TO postgres; + +-- +-- TOC entry 259 (class 1259 OID 29408) +-- Name: executiontypes_executiontypeid_seq; Type: SEQUENCE; Schema: patch40; Owner: postgres +-- + +ALTER TABLE patch40.executiontypes ALTER COLUMN executiontypeid ADD GENERATED ALWAYS AS IDENTITY ( + SEQUENCE NAME patch40.executiontypes_executiontypeid_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + + +-- +-- TOC entry 296 (class 1259 OID 40654) +-- Name: g_homepage_time_stats; Type: VIEW; Schema: patch40; Owner: postgres +-- + +CREATE VIEW patch40.g_homepage_time_stats AS + WITH completed_jobs AS ( + SELECT c.patchid, + EXTRACT(epoch FROM (max(b.lastupdatetime) - min(b.receivedtime))) AS job_duration + FROM (patch40.g_homepage_cycle_achieved(patch40.currentcycleid()) c(patchid, last_in_sequence, last_achieved, slotid) + LEFT JOIN patch40.executions b ON ((c.patchid = b.patchid))) + WHERE (c.last_in_sequence = c.last_achieved) + GROUP BY c.patchid + ) + SELECT round((avg(completed_jobs.job_duration) / (60)::numeric), 2) AS average, + round((min(completed_jobs.job_duration) / (60)::numeric), 2) AS fastest, + round((max(completed_jobs.job_duration) / (60)::numeric), 2) AS slowest, + round(((percentile_cont((0.5)::double precision) WITHIN GROUP (ORDER BY ((completed_jobs.job_duration)::double precision)) / (60)::double precision))::numeric, 2) AS median + FROM completed_jobs; + + +ALTER VIEW patch40.g_homepage_time_stats OWNER TO postgres; + +-- +-- TOC entry 289 (class 1259 OID 38599) +-- Name: kernel_validation_id_seq; Type: SEQUENCE; Schema: patch40; Owner: postgres +-- + +ALTER TABLE patch40.kernel_validation ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY ( + SEQUENCE NAME patch40.kernel_validation_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + + +-- +-- TOC entry 263 (class 1259 OID 29441) +-- Name: latest_ec2inventory; Type: VIEW; Schema: patch40; Owner: postgres +-- + +CREATE VIEW patch40.latest_ec2inventory AS + SELECT archive_ec2inventory.collectiondate, + archive_ec2inventory.accountid, + archive_ec2inventory.instanceid, + archive_ec2inventory.nametag, + archive_ec2inventory.reservationid, + archive_ec2inventory.region, + archive_ec2inventory.launchtime, + archive_ec2inventory.privateipaddress, + archive_ec2inventory.state, + archive_ec2inventory.collectiontime + FROM patch40.archive_ec2inventory + WHERE (archive_ec2inventory.collectiondate = ( SELECT max(archive_ec2inventory_1.collectiondate) AS max + FROM patch40.archive_ec2inventory archive_ec2inventory_1)); + + +ALTER VIEW patch40.latest_ec2inventory OWNER TO postgres; + +-- +-- TOC entry 264 (class 1259 OID 29445) +-- Name: latest_satellite; Type: VIEW; Schema: patch40; Owner: postgres +-- + +CREATE VIEW patch40.latest_satellite AS + SELECT archive_satellite.collectiondate, + archive_satellite.inserttime, + archive_satellite.id, + archive_satellite.name, + archive_satellite.ip, + archive_satellite.ip6, + archive_satellite.operatingsystem_name, + archive_satellite.architecture_name, + archive_satellite.hostgroup_name, + archive_satellite.location_name, + archive_satellite.created_at, + archive_satellite.mac, + archive_satellite.last_checkin, + archive_satellite.boot_time + FROM patch40.archive_satellite + WHERE (archive_satellite.collectiondate = ( SELECT max(archive_satellite_1.collectiondate) AS max + FROM patch40.archive_satellite archive_satellite_1)); + + +ALTER VIEW patch40.latest_satellite OWNER TO postgres; + +-- +-- TOC entry 294 (class 1259 OID 40367) +-- Name: notification_template_types; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.notification_template_types ( + notificationtypeid integer NOT NULL, + label character varying(64) +); + + +ALTER TABLE patch40.notification_template_types OWNER TO postgres; + +-- +-- TOC entry 293 (class 1259 OID 40366) +-- Name: notification_template_types_notificationtypeid_seq; Type: SEQUENCE; Schema: patch40; Owner: postgres +-- + +ALTER TABLE patch40.notification_template_types ALTER COLUMN notificationtypeid ADD GENERATED ALWAYS AS IDENTITY ( + SEQUENCE NAME patch40.notification_template_types_notificationtypeid_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + + +-- +-- TOC entry 295 (class 1259 OID 40372) +-- Name: notification_templates; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.notification_templates ( + notificationtypeid integer NOT NULL, + activation_date date NOT NULL, + template text NOT NULL +); + + +ALTER TABLE patch40.notification_templates OWNER TO postgres; + +-- +-- TOC entry 265 (class 1259 OID 29450) +-- Name: procedures_uid_seq; Type: SEQUENCE; Schema: patch40; Owner: postgres +-- + +CREATE SEQUENCE patch40.procedures_uid_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE patch40.procedures_uid_seq OWNER TO postgres; + +-- +-- TOC entry 266 (class 1259 OID 29451) +-- Name: qs_cycle_rolling15; Type: VIEW; Schema: patch40; Owner: postgres +-- + +CREATE VIEW patch40.qs_cycle_rolling15 AS + SELECT cycles.cycleid, + cycles.label, + cycles.start, + cycles.notes + FROM patch40.cycles + WHERE (cycles.start > (now() - '465 days'::interval)) + ORDER BY cycles.start + LIMIT 15; + + +ALTER VIEW patch40.qs_cycle_rolling15 OWNER TO postgres; + +-- +-- TOC entry 260 (class 1259 OID 29414) +-- Name: slotdefinitions_slotid_seq; Type: SEQUENCE; Schema: patch40; Owner: postgres +-- + +CREATE SEQUENCE patch40.slotdefinitions_slotid_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE patch40.slotdefinitions_slotid_seq OWNER TO postgres; + +-- +-- TOC entry 261 (class 1259 OID 29415) +-- Name: slotdefinitions; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.slotdefinitions ( + slotid integer DEFAULT nextval('patch40.slotdefinitions_slotid_seq'::regclass) NOT NULL, + weekcounter integer NOT NULL, + dayofweek integer NOT NULL, + starttime time(6) without time zone NOT NULL, + durationminutes integer NOT NULL, + retired boolean NOT NULL, + label character varying(20) DEFAULT 'PleaseRefresh'::character varying, + notes character varying(256) +); + + +ALTER TABLE patch40.slotdefinitions OWNER TO postgres; + +-- +-- TOC entry 262 (class 1259 OID 29420) +-- Name: targets; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.targets ( + patchid uuid DEFAULT gen_random_uuid() NOT NULL, + accountid bigint, + instanceid character varying(50), + nametag character varying(128), + region character varying, + slotid integer, + clusterid integer NOT NULL, + commissioned timestamp without time zone, + commissionedby character varying(128), + decommissioned timestamp without time zone, + decommissionedby character varying(128), + argument_overrides json, + cspid integer NOT NULL +); + + +ALTER TABLE patch40.targets OWNER TO postgres; + +-- +-- TOC entry 267 (class 1259 OID 29455) +-- Name: qs_slot_occupancy_detail; Type: VIEW; Schema: patch40; Owner: postgres +-- + +CREATE VIEW patch40.qs_slot_occupancy_detail AS + SELECT t.patchid, + t.slotid, + s.label AS slotlabel, + t.nametag, + c.clusterid, + c.clustername, + t.accountid, + t.region, + t.instanceid, + t.commissioned, + t.commissionedby + FROM ((patch40.targets t + LEFT JOIN patch40.clusters c ON ((t.clusterid = c.clusterid))) + JOIN patch40.slotdefinitions s ON ((t.slotid = s.slotid))); + + +ALTER VIEW patch40.qs_slot_occupancy_detail OWNER TO postgres; + +-- +-- TOC entry 268 (class 1259 OID 29460) +-- Name: qs_slot_occupancy_top; Type: VIEW; Schema: patch40; Owner: postgres +-- + +CREATE VIEW patch40.qs_slot_occupancy_top AS +SELECT + NULL::integer AS slotid, + NULL::character varying(20) AS label, + NULL::integer AS durationminutes, + NULL::time(6) without time zone AS starttime, + NULL::integer AS dayofweek, + NULL::integer AS weekcounter, + NULL::bigint AS count; + + +ALTER VIEW patch40.qs_slot_occupancy_top OWNER TO postgres; + +-- +-- TOC entry 269 (class 1259 OID 29464) +-- Name: reschedules; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.reschedules ( + cycleid bigint NOT NULL, + patchid uuid NOT NULL, + temp_slotid bigint, + requestedby character varying(128), + requestedat timestamp without time zone, + notes character varying(2048) +); + + +ALTER TABLE patch40.reschedules OWNER TO postgres; + +-- +-- TOC entry 274 (class 1259 OID 29642) +-- Name: sequence_types; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.sequence_types ( + sequence_type_id integer NOT NULL, + label character varying(64) NOT NULL +); + + +ALTER TABLE patch40.sequence_types OWNER TO postgres; + +-- +-- TOC entry 273 (class 1259 OID 29641) +-- Name: sequence_types_sequence_type_id_seq; Type: SEQUENCE; Schema: patch40; Owner: postgres +-- + +ALTER TABLE patch40.sequence_types ALTER COLUMN sequence_type_id ADD GENERATED ALWAYS AS IDENTITY ( + SEQUENCE NAME patch40.sequence_types_sequence_type_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + + +-- +-- TOC entry 277 (class 1259 OID 29768) +-- Name: subsystems; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.subsystems ( + subsystem_id integer NOT NULL, + label character varying(24) +); + + +ALTER TABLE patch40.subsystems OWNER TO postgres; + +-- +-- TOC entry 271 (class 1259 OID 29481) +-- Name: users; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.users ( + login character varying(128), + name character varying(128), + email character varying(128), + notes character varying(2048) +); + + +ALTER TABLE patch40.users OWNER TO postgres; + +-- +-- TOC entry 272 (class 1259 OID 29486) +-- Name: waivers; Type: TABLE; Schema: patch40; Owner: postgres +-- + +CREATE TABLE patch40.waivers ( + patchid uuid NOT NULL, + cycleid bigint NOT NULL, + requestedby character varying(128) NOT NULL, + requestedat timestamp without time zone NOT NULL, + notes character varying(2048) +); + + +ALTER TABLE patch40.waivers OWNER TO postgres; + +-- +-- TOC entry 4480 (class 2606 OID 29499) +-- Name: clusters clusters_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.clusters + ADD CONSTRAINT clusters_pkey PRIMARY KEY (clusterid); + + +-- +-- TOC entry 4526 (class 2606 OID 40094) +-- Name: config config_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.config + ADD CONSTRAINT config_pkey PRIMARY KEY (key); + + +-- +-- TOC entry 4532 (class 2606 OID 42613) +-- Name: csps csps_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.csps + ADD CONSTRAINT csps_pkey PRIMARY KEY (cspid); + + +-- +-- TOC entry 4482 (class 2606 OID 29501) +-- Name: cycles cycles_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.cycles + ADD CONSTRAINT cycles_pkey PRIMARY KEY (cycleid); + + +-- +-- TOC entry 4516 (class 2606 OID 34323) +-- Name: dispatch_history dispatch_history_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.dispatch_history + ADD CONSTRAINT dispatch_history_pkey PRIMARY KEY (uid); + + +-- +-- TOC entry 4524 (class 2606 OID 38745) +-- Name: dispatch_types dispatch_types_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.dispatch_types + ADD CONSTRAINT dispatch_types_pkey PRIMARY KEY (dtypeid); + + +-- +-- TOC entry 4518 (class 2606 OID 34333) +-- Name: enable_dispatcher enable_dispatcher_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.enable_dispatcher + ADD CONSTRAINT enable_dispatcher_pkey PRIMARY KEY (type); + + +-- +-- TOC entry 4511 (class 2606 OID 29666) +-- Name: execution_output execution_output_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.execution_output + ADD CONSTRAINT execution_output_pkey PRIMARY KEY (uid); + + +-- +-- TOC entry 4484 (class 2606 OID 29503) +-- Name: executions executions_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.executions + ADD CONSTRAINT executions_pkey PRIMARY KEY (uid); + + +-- +-- TOC entry 4492 (class 2606 OID 29505) +-- Name: executiontypes executiontypes_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.executiontypes + ADD CONSTRAINT executiontypes_pkey PRIMARY KEY (executiontypeid); + + +-- +-- TOC entry 4522 (class 2606 OID 38604) +-- Name: kernel_validation kernel_validation_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.kernel_validation + ADD CONSTRAINT kernel_validation_pkey PRIMARY KEY (id, os_type, major_version, minor_version, begin_using_date); + + +-- +-- TOC entry 4528 (class 2606 OID 40371) +-- Name: notification_template_types notification_template_types_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.notification_template_types + ADD CONSTRAINT notification_template_types_pkey PRIMARY KEY (notificationtypeid); + + +-- +-- TOC entry 4530 (class 2606 OID 40378) +-- Name: notification_templates notification_templates_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.notification_templates + ADD CONSTRAINT notification_templates_pkey PRIMARY KEY (notificationtypeid, activation_date); + + +-- +-- TOC entry 4476 (class 2606 OID 29507) +-- Name: archive_satellite pkey_archive_satellite_collectiondate_id; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.archive_satellite + ADD CONSTRAINT pkey_archive_satellite_collectiondate_id PRIMARY KEY (collectiondate, id); + + +-- +-- TOC entry 4478 (class 2606 OID 29509) +-- Name: assetdata pkey_assetdata; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.assetdata + ADD CONSTRAINT pkey_assetdata PRIMARY KEY (patchid); + + +-- +-- TOC entry 4538 (class 2606 OID 42757) +-- Name: audit_done pkey_done_uid; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.audit_done + ADD CONSTRAINT pkey_done_uid PRIMARY KEY (uid); + + +-- +-- TOC entry 4473 (class 2606 OID 29511) +-- Name: archive_ec2inventory pkey_ec2inventory; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.archive_ec2inventory + ADD CONSTRAINT pkey_ec2inventory PRIMARY KEY (collectiondate, accountid, instanceid); + + +-- +-- TOC entry 4536 (class 2606 OID 42738) +-- Name: audit_next pkey_next_uid; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.audit_next + ADD CONSTRAINT pkey_next_uid PRIMARY KEY (uid); + + +-- +-- TOC entry 4498 (class 2606 OID 29513) +-- Name: reschedules pkey_reschedules; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.reschedules + ADD CONSTRAINT pkey_reschedules PRIMARY KEY (cycleid, patchid); + + +-- +-- TOC entry 4534 (class 2606 OID 42707) +-- Name: audit_retry pkey_uid; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.audit_retry + ADD CONSTRAINT pkey_uid PRIMARY KEY (uid); + + +-- +-- TOC entry 4503 (class 2606 OID 29515) +-- Name: waivers pkey_waivers; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.waivers + ADD CONSTRAINT pkey_waivers PRIMARY KEY (cycleid, patchid); + + +-- +-- TOC entry 4505 (class 2606 OID 29646) +-- Name: sequence_types sequence_types_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.sequence_types + ADD CONSTRAINT sequence_types_pkey PRIMARY KEY (sequence_type_id); + + +-- +-- TOC entry 4509 (class 2606 OID 29653) +-- Name: sequences sequences_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.sequences + ADD CONSTRAINT sequences_pkey PRIMARY KEY (sequence_id, sequence_step, sequence_type); + + +-- +-- TOC entry 4494 (class 2606 OID 29517) +-- Name: slotdefinitions slotdefinitions_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.slotdefinitions + ADD CONSTRAINT slotdefinitions_pkey PRIMARY KEY (slotid); + + +-- +-- TOC entry 4520 (class 2606 OID 38432) +-- Name: solarwinds_suppression solarwinds_suppression_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.solarwinds_suppression + ADD CONSTRAINT solarwinds_suppression_pkey PRIMARY KEY (uid); + + +-- +-- TOC entry 4501 (class 2606 OID 29521) +-- Name: statusvalues statusvalues_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.statusvalues + ADD CONSTRAINT statusvalues_pkey PRIMARY KEY (statusid); + + +-- +-- TOC entry 4514 (class 2606 OID 29772) +-- Name: subsystems subsystems_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.subsystems + ADD CONSTRAINT subsystems_pkey PRIMARY KEY (subsystem_id); + + +-- +-- TOC entry 4496 (class 2606 OID 29523) +-- Name: targets targets_pkey; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.targets + ADD CONSTRAINT targets_pkey PRIMARY KEY (patchid); + + +-- +-- TOC entry 4490 (class 2606 OID 29527) +-- Name: executions uniq_ud; Type: CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.executions + ADD CONSTRAINT uniq_ud UNIQUE (uid); + + +-- +-- TOC entry 4474 (class 1259 OID 29528) +-- Name: archive_satellite_collectdate_name; Type: INDEX; Schema: patch40; Owner: postgres +-- + +CREATE INDEX archive_satellite_collectdate_name ON patch40.archive_satellite USING btree (collectiondate DESC, name) WITH (deduplicate_items='true'); + + +-- +-- TOC entry 4506 (class 1259 OID 29659) +-- Name: fki_fk_sequence_type; Type: INDEX; Schema: patch40; Owner: postgres +-- + +CREATE INDEX fki_fk_sequence_type ON patch40.sequences USING btree (sequence_type); + + +-- +-- TOC entry 4499 (class 1259 OID 29778) +-- Name: fki_fk_subsystem_id; Type: INDEX; Schema: patch40; Owner: postgres +-- + +CREATE INDEX fki_fk_subsystem_id ON patch40.statusvalues USING btree (subsystem_id); + + +-- +-- TOC entry 4512 (class 1259 OID 38447) +-- Name: fki_fk_uid_executions; Type: INDEX; Schema: patch40; Owner: postgres +-- + +CREATE INDEX fki_fk_uid_executions ON patch40.execution_output USING btree (uid); + + +-- +-- TOC entry 4485 (class 1259 OID 29532) +-- Name: fki_fkey_execution_executiontypes_executiontype; Type: INDEX; Schema: patch40; Owner: postgres +-- + +CREATE INDEX fki_fkey_execution_executiontypes_executiontype ON patch40.executions USING btree (executiontypeid); + + +-- +-- TOC entry 4486 (class 1259 OID 38795) +-- Name: idx_comp_dispatchjoin; Type: INDEX; Schema: patch40; Owner: postgres +-- + +CREATE INDEX idx_comp_dispatchjoin ON patch40.executions USING btree (cycleid, slotid, sequence_type, sequence_id, clusterid, patchid) WITH (deduplicate_items='true'); + + +-- +-- TOC entry 4487 (class 1259 OID 38803) +-- Name: idx_executions_composite; Type: INDEX; Schema: patch40; Owner: postgres +-- + +CREATE INDEX idx_executions_composite ON patch40.executions USING btree (cycleid, slotid, sequence_type, sequence_id, sequence_step, patchid, lastupdatetime); + + +-- +-- TOC entry 4488 (class 1259 OID 42508) +-- Name: idx_executions_latest; Type: INDEX; Schema: patch40; Owner: postgres +-- + +CREATE INDEX idx_executions_latest ON patch40.executions USING btree (cycleid, sequence_type, sequence_id, patchid, lastupdatetime DESC); + + +-- +-- TOC entry 4507 (class 1259 OID 38804) +-- Name: idx_sequences_composite; Type: INDEX; Schema: patch40; Owner: postgres +-- + +CREATE INDEX idx_sequences_composite ON patch40.sequences USING btree (sequence_type, sequence_id, sequence_step); + + +-- +-- TOC entry 4709 (class 2618 OID 29463) +-- Name: qs_slot_occupancy_top _RETURN; Type: RULE; Schema: patch40; Owner: postgres +-- + +CREATE OR REPLACE VIEW patch40.qs_slot_occupancy_top AS + SELECT s.slotid, + s.label, + s.durationminutes, + s.starttime, + s.dayofweek, + s.weekcounter, + count(t.instanceid) AS count + FROM (patch40.slotdefinitions s + LEFT JOIN patch40.targets t ON ((s.slotid = t.slotid))) + GROUP BY s.slotid, s.label, s.durationminutes + ORDER BY s.label; + + +-- +-- TOC entry 4561 (class 2620 OID 29542) +-- Name: slotdefinitions slotdefinitions_insert; Type: TRIGGER; Schema: patch40; Owner: postgres +-- + +CREATE TRIGGER slotdefinitions_insert BEFORE INSERT OR UPDATE OF weekcounter, dayofweek, starttime, durationminutes ON patch40.slotdefinitions FOR EACH ROW EXECUTE FUNCTION patch40.slotdefinitons_insert(); + + +-- +-- TOC entry 4557 (class 2606 OID 40379) +-- Name: notification_templates fk_notificationtypeid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.notification_templates + ADD CONSTRAINT fk_notificationtypeid FOREIGN KEY (notificationtypeid) REFERENCES patch40.notification_template_types(notificationtypeid); + + +-- +-- TOC entry 4554 (class 2606 OID 29654) +-- Name: sequences fk_sequence_type; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.sequences + ADD CONSTRAINT fk_sequence_type FOREIGN KEY (sequence_type) REFERENCES patch40.sequence_types(sequence_type_id); + + +-- +-- TOC entry 4551 (class 2606 OID 29773) +-- Name: statusvalues fk_subsystem_id; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.statusvalues + ADD CONSTRAINT fk_subsystem_id FOREIGN KEY (subsystem_id) REFERENCES patch40.subsystems(subsystem_id) NOT VALID; + + +-- +-- TOC entry 4555 (class 2606 OID 38442) +-- Name: execution_output fk_uid_executions; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.execution_output + ADD CONSTRAINT fk_uid_executions FOREIGN KEY (uid) REFERENCES patch40.executions(uid); + + +-- +-- TOC entry 4556 (class 2606 OID 38433) +-- Name: solarwinds_suppression fk_uid_executions; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.solarwinds_suppression + ADD CONSTRAINT fk_uid_executions FOREIGN KEY (uid) REFERENCES patch40.executions(uid); + + +-- +-- TOC entry 4539 (class 2606 OID 29558) +-- Name: assetdata fkey_assetdata_targets; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.assetdata + ADD CONSTRAINT fkey_assetdata_targets FOREIGN KEY (patchid) REFERENCES patch40.targets(patchid); + + +-- +-- TOC entry 4546 (class 2606 OID 42623) +-- Name: targets fkey_csps_cspid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.targets + ADD CONSTRAINT fkey_csps_cspid FOREIGN KEY (cspid) REFERENCES patch40.csps(cspid) NOT VALID; + + +-- +-- TOC entry 4560 (class 2606 OID 42758) +-- Name: audit_done fkey_done_uid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.audit_done + ADD CONSTRAINT fkey_done_uid FOREIGN KEY (uid) REFERENCES patch40.executions(uid); + + +-- +-- TOC entry 4540 (class 2606 OID 29563) +-- Name: executions fkey_execution_executiontypes_executiontype; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.executions + ADD CONSTRAINT fkey_execution_executiontypes_executiontype FOREIGN KEY (executiontypeid) REFERENCES patch40.executiontypes(executiontypeid) NOT VALID; + + +-- +-- TOC entry 4541 (class 2606 OID 29568) +-- Name: executions fkey_executions_clusters_clusterid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.executions + ADD CONSTRAINT fkey_executions_clusters_clusterid FOREIGN KEY (clusterid) REFERENCES patch40.clusters(clusterid); + + +-- +-- TOC entry 4542 (class 2606 OID 29573) +-- Name: executions fkey_executions_cycles_cycleid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.executions + ADD CONSTRAINT fkey_executions_cycles_cycleid FOREIGN KEY (cycleid) REFERENCES patch40.cycles(cycleid); + + +-- +-- TOC entry 4543 (class 2606 OID 29578) +-- Name: executions fkey_executions_slotdefinitions_slotid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.executions + ADD CONSTRAINT fkey_executions_slotdefinitions_slotid FOREIGN KEY (slotid) REFERENCES patch40.slotdefinitions(slotid); + + +-- +-- TOC entry 4544 (class 2606 OID 29583) +-- Name: executions fkey_executions_statusvalues_statusid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.executions + ADD CONSTRAINT fkey_executions_statusvalues_statusid FOREIGN KEY (statusid) REFERENCES patch40.statusvalues(statusid); + + +-- +-- TOC entry 4545 (class 2606 OID 29588) +-- Name: executions fkey_executions_targets_patchid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.executions + ADD CONSTRAINT fkey_executions_targets_patchid FOREIGN KEY (patchid) REFERENCES patch40.targets(patchid); + + +-- +-- TOC entry 4559 (class 2606 OID 42739) +-- Name: audit_next fkey_next_uid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.audit_next + ADD CONSTRAINT fkey_next_uid FOREIGN KEY (uid) REFERENCES patch40.executions(uid); + + +-- +-- TOC entry 4549 (class 2606 OID 29593) +-- Name: reschedules fkey_reschedules_slotdefinitions_slotid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.reschedules + ADD CONSTRAINT fkey_reschedules_slotdefinitions_slotid FOREIGN KEY (temp_slotid) REFERENCES patch40.slotdefinitions(slotid); + + +-- +-- TOC entry 4550 (class 2606 OID 29598) +-- Name: reschedules fkey_reschedules_targets_patchid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.reschedules + ADD CONSTRAINT fkey_reschedules_targets_patchid FOREIGN KEY (patchid) REFERENCES patch40.targets(patchid); + + +-- +-- TOC entry 4547 (class 2606 OID 29603) +-- Name: targets fkey_targets_clusters_clusterid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.targets + ADD CONSTRAINT fkey_targets_clusters_clusterid FOREIGN KEY (clusterid) REFERENCES patch40.clusters(clusterid); + + +-- +-- TOC entry 4548 (class 2606 OID 29608) +-- Name: targets fkey_targets_slotdefinitions_slotid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.targets + ADD CONSTRAINT fkey_targets_slotdefinitions_slotid FOREIGN KEY (slotid) REFERENCES patch40.slotdefinitions(slotid); + + +-- +-- TOC entry 4558 (class 2606 OID 42708) +-- Name: audit_retry fkey_uid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.audit_retry + ADD CONSTRAINT fkey_uid FOREIGN KEY (uid) REFERENCES patch40.executions(uid); + + +-- +-- TOC entry 4552 (class 2606 OID 29613) +-- Name: waivers fkey_waivers_cycles_cycleid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.waivers + ADD CONSTRAINT fkey_waivers_cycles_cycleid FOREIGN KEY (cycleid) REFERENCES patch40.cycles(cycleid); + + +-- +-- TOC entry 4553 (class 2606 OID 29618) +-- Name: waivers fkey_waivers_targets_patchid; Type: FK CONSTRAINT; Schema: patch40; Owner: postgres +-- + +ALTER TABLE ONLY patch40.waivers + ADD CONSTRAINT fkey_waivers_targets_patchid FOREIGN KEY (patchid) REFERENCES patch40.targets(patchid); + + +-- +-- TOC entry 4723 (class 0 OID 0) +-- Dependencies: 36 +-- Name: SCHEMA patch40; Type: ACL; Schema: -; Owner: postgres +-- + +REVOKE ALL ON SCHEMA patch40 FROM postgres; +GRANT USAGE ON SCHEMA patch40 TO patch40_app; +GRANT USAGE ON SCHEMA patch40 TO patch40_ui_users; + + +-- +-- TOC entry 4724 (class 0 OID 0) +-- Dependencies: 1152 +-- Name: TYPE typ_ec2_inventory; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON TYPE patch40.typ_ec2_inventory FROM PUBLIC; +REVOKE ALL ON TYPE patch40.typ_ec2_inventory FROM postgres; +GRANT ALL ON TYPE patch40.typ_ec2_inventory TO patch40_app; + + +-- +-- TOC entry 4725 (class 0 OID 0) +-- Dependencies: 1153 +-- Name: TYPE typ_schedule_waiver; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON TYPE patch40.typ_schedule_waiver FROM PUBLIC; +REVOKE ALL ON TYPE patch40.typ_schedule_waiver FROM postgres; +GRANT ALL ON TYPE patch40.typ_schedule_waiver TO patch40_app; + + +-- +-- TOC entry 4726 (class 0 OID 0) +-- Dependencies: 372 +-- Name: FUNCTION calcdayoffset(_patchtuesday date, _weekcounter integer, _daycounter integer); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.calcdayoffset(_patchtuesday date, _weekcounter integer, _daycounter integer) FROM PUBLIC; +GRANT ALL ON FUNCTION patch40.calcdayoffset(_patchtuesday date, _weekcounter integer, _daycounter integer) TO patch40_app; +GRANT ALL ON FUNCTION patch40.calcdayoffset(_patchtuesday date, _weekcounter integer, _daycounter integer) TO patch40_ui_users; + + +-- +-- TOC entry 4727 (class 0 OID 0) +-- Dependencies: 350 +-- Name: FUNCTION currentcycle(); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40.currentcycle() TO patch40_app; + + +-- +-- TOC entry 4728 (class 0 OID 0) +-- Dependencies: 365 +-- Name: FUNCTION currentcycleid(); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40.currentcycleid() TO patch40_app; + + +-- +-- TOC entry 4729 (class 0 OID 0) +-- Dependencies: 351 +-- Name: FUNCTION currentpatchtuesday(); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40.currentpatchtuesday() TO patch40_app; + + +-- +-- TOC entry 4730 (class 0 OID 0) +-- Dependencies: 352 +-- Name: PROCEDURE dbmaintenance(OUT _myout character varying); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON PROCEDURE patch40.dbmaintenance(OUT _myout character varying) TO patch40_app; + + +-- +-- TOC entry 4731 (class 0 OID 0) +-- Dependencies: 366 +-- Name: FUNCTION schedulecycle(_cycleid bigint); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40.schedulecycle(_cycleid bigint) TO patch40_app; + + +-- +-- TOC entry 4732 (class 0 OID 0) +-- Dependencies: 252 +-- Name: TABLE assetdata; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.assetdata FROM postgres; +GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.assetdata TO patch40_app; +GRANT SELECT ON TABLE patch40.assetdata TO patch40_ui_users; + + +-- +-- TOC entry 4733 (class 0 OID 0) +-- Dependencies: 297 +-- Name: TABLE cycle_schedule; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.cycle_schedule FROM postgres; +GRANT SELECT ON TABLE patch40.cycle_schedule TO patch40_app; +GRANT SELECT ON TABLE patch40.cycle_schedule TO patch40_ui_users; + + +-- +-- TOC entry 4734 (class 0 OID 0) +-- Dependencies: 275 +-- Name: TABLE sequences; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.sequences FROM postgres; +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE patch40.sequences TO patch40_app; +GRANT SELECT ON TABLE patch40.sequences TO patch40_ui_users; + + +-- +-- TOC entry 4735 (class 0 OID 0) +-- Dependencies: 298 +-- Name: TABLE cycle_steps_patch; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.cycle_steps_patch FROM postgres; +GRANT SELECT ON TABLE patch40.cycle_steps_patch TO patch40_app; +GRANT SELECT ON TABLE patch40.cycle_steps_patch TO patch40_ui_users; + + +-- +-- TOC entry 4736 (class 0 OID 0) +-- Dependencies: 256 +-- Name: TABLE executions; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.executions FROM postgres; +GRANT SELECT,INSERT,UPDATE ON TABLE patch40.executions TO patch40_app; +GRANT SELECT,INSERT ON TABLE patch40.executions TO patch40_ui_users; + + +-- +-- TOC entry 4737 (class 0 OID 0) +-- Dependencies: 270 +-- Name: TABLE statusvalues; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.statusvalues FROM postgres; +GRANT SELECT ON TABLE patch40.statusvalues TO patch40_app; +GRANT SELECT ON TABLE patch40.statusvalues TO patch40_ui_users; + + +-- +-- TOC entry 4738 (class 0 OID 0) +-- Dependencies: 299 +-- Name: TABLE cycle_steps_patch_results; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.cycle_steps_patch_results FROM postgres; +GRANT SELECT ON TABLE patch40.cycle_steps_patch_results TO patch40_app; + + +-- +-- TOC entry 4739 (class 0 OID 0) +-- Dependencies: 290 +-- Name: TABLE kernel_validation; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.kernel_validation FROM postgres; +GRANT SELECT,INSERT,UPDATE ON TABLE patch40.kernel_validation TO patch40_app; + + +-- +-- TOC entry 4740 (class 0 OID 0) +-- Dependencies: 288 +-- Name: TABLE solarwinds_suppression; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.solarwinds_suppression FROM postgres; +GRANT SELECT,INSERT ON TABLE patch40.solarwinds_suppression TO patch40_app; + + +-- +-- TOC entry 4741 (class 0 OID 0) +-- Dependencies: 300 +-- Name: TABLE dispatcher; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.dispatcher FROM postgres; +GRANT SELECT ON TABLE patch40.dispatcher TO patch40_app; +GRANT SELECT ON TABLE patch40.dispatcher TO patch40_ui_users; + + +-- +-- TOC entry 4742 (class 0 OID 0) +-- Dependencies: 376 +-- Name: FUNCTION dispatch_done(_patchid uuid); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40.dispatch_done(_patchid uuid) TO patch40_app; + + +-- +-- TOC entry 4743 (class 0 OID 0) +-- Dependencies: 343 +-- Name: PROCEDURE dispatcher_execute(); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON PROCEDURE patch40.dispatcher_execute() TO patch40_app; + + +-- +-- TOC entry 4744 (class 0 OID 0) +-- Dependencies: 389 +-- Name: FUNCTION g_homepage_cycle_achieved(_cycleid bigint); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.g_homepage_cycle_achieved(_cycleid bigint) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.g_homepage_cycle_achieved(_cycleid bigint) FROM postgres; +GRANT ALL ON FUNCTION patch40.g_homepage_cycle_achieved(_cycleid bigint) TO patch40_app; +GRANT ALL ON FUNCTION patch40.g_homepage_cycle_achieved(_cycleid bigint) TO patch40_ui_users; + + +-- +-- TOC entry 4745 (class 0 OID 0) +-- Dependencies: 373 +-- Name: FUNCTION g_homepage_cycle_attempted(_cycleid bigint); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.g_homepage_cycle_attempted(_cycleid bigint) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.g_homepage_cycle_attempted(_cycleid bigint) FROM postgres; +GRANT ALL ON FUNCTION patch40.g_homepage_cycle_attempted(_cycleid bigint) TO patch40_app; +GRANT ALL ON FUNCTION patch40.g_homepage_cycle_attempted(_cycleid bigint) TO patch40_ui_users; + + +-- +-- TOC entry 4746 (class 0 OID 0) +-- Dependencies: 367 +-- Name: FUNCTION g_homepage_needs_attention(_cycleid bigint); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.g_homepage_needs_attention(_cycleid bigint) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.g_homepage_needs_attention(_cycleid bigint) FROM postgres; +GRANT ALL ON FUNCTION patch40.g_homepage_needs_attention(_cycleid bigint) TO patch40_app; +GRANT ALL ON FUNCTION patch40.g_homepage_needs_attention(_cycleid bigint) TO patch40_ui_users; + + +-- +-- TOC entry 4747 (class 0 OID 0) +-- Dependencies: 388 +-- Name: FUNCTION g_homepage_slot_occupancy(_cycleid bigint); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.g_homepage_slot_occupancy(_cycleid bigint) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.g_homepage_slot_occupancy(_cycleid bigint) FROM postgres; +GRANT ALL ON FUNCTION patch40.g_homepage_slot_occupancy(_cycleid bigint) TO patch40_app; +GRANT ALL ON FUNCTION patch40.g_homepage_slot_occupancy(_cycleid bigint) TO patch40_ui_users; + + +-- +-- TOC entry 4748 (class 0 OID 0) +-- Dependencies: 374 +-- Name: FUNCTION g_slot_details(_cycleid bigint, _slotid integer); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.g_slot_details(_cycleid bigint, _slotid integer) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.g_slot_details(_cycleid bigint, _slotid integer) FROM postgres; +GRANT ALL ON FUNCTION patch40.g_slot_details(_cycleid bigint, _slotid integer) TO patch40_app; +GRANT ALL ON FUNCTION patch40.g_slot_details(_cycleid bigint, _slotid integer) TO patch40_ui_users; + + +-- +-- TOC entry 4749 (class 0 OID 0) +-- Dependencies: 368 +-- Name: FUNCTION g_target_details(_patchid uuid); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.g_target_details(_patchid uuid) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.g_target_details(_patchid uuid) FROM postgres; +GRANT ALL ON FUNCTION patch40.g_target_details(_patchid uuid) TO patch40_app; +GRANT ALL ON FUNCTION patch40.g_target_details(_patchid uuid) TO patch40_ui_users; + + +-- +-- TOC entry 4750 (class 0 OID 0) +-- Dependencies: 375 +-- Name: FUNCTION g_target_details_execution(_patchid uuid, _cycleid bigint); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.g_target_details_execution(_patchid uuid, _cycleid bigint) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.g_target_details_execution(_patchid uuid, _cycleid bigint) FROM postgres; +GRANT ALL ON FUNCTION patch40.g_target_details_execution(_patchid uuid, _cycleid bigint) TO patch40_app; +GRANT ALL ON FUNCTION patch40.g_target_details_execution(_patchid uuid, _cycleid bigint) TO patch40_ui_users; + + +-- +-- TOC entry 4751 (class 0 OID 0) +-- Dependencies: 369 +-- Name: FUNCTION g_target_last_executed_in_cycle_by_sequence_and_patchid(_cycleid bigint, _sequence_type integer, _patchid uuid); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40.g_target_last_executed_in_cycle_by_sequence_and_patchid(_cycleid bigint, _sequence_type integer, _patchid uuid) TO patch40_app; +GRANT ALL ON FUNCTION patch40.g_target_last_executed_in_cycle_by_sequence_and_patchid(_cycleid bigint, _sequence_type integer, _patchid uuid) TO patch40_ui_users; + + +-- +-- TOC entry 4752 (class 0 OID 0) +-- Dependencies: 377 +-- Name: FUNCTION g_target_ui_options_by_cycle_sequence_and_patchid(_cycleid bigint, _sequence_type integer, _patchid uuid); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40.g_target_ui_options_by_cycle_sequence_and_patchid(_cycleid bigint, _sequence_type integer, _patchid uuid) TO patch40_app; + + +-- +-- TOC entry 4753 (class 0 OID 0) +-- Dependencies: 341 +-- Name: FUNCTION monthpatchtuesday(indate date); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40.monthpatchtuesday(indate date) TO patch40_app; + + +-- +-- TOC entry 4754 (class 0 OID 0) +-- Dependencies: 342 +-- Name: FUNCTION "numSuffix"(innumber integer); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40."numSuffix"(innumber integer) TO patch40_app; + + +-- +-- TOC entry 4755 (class 0 OID 0) +-- Dependencies: 358 +-- Name: PROCEDURE remove__sp_step_result(IN in_uid bigint, IN in_statusid integer, IN in_sentstatus integer); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON PROCEDURE patch40.remove__sp_step_result(IN in_uid bigint, IN in_statusid integer, IN in_sentstatus integer) FROM PUBLIC; +REVOKE ALL ON PROCEDURE patch40.remove__sp_step_result(IN in_uid bigint, IN in_statusid integer, IN in_sentstatus integer) FROM postgres; +GRANT ALL ON PROCEDURE patch40.remove__sp_step_result(IN in_uid bigint, IN in_statusid integer, IN in_sentstatus integer) TO patch40_app; + + +-- +-- TOC entry 4756 (class 0 OID 0) +-- Dependencies: 380 +-- Name: FUNCTION schedulecycle(_indate character varying); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.schedulecycle(_indate character varying) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.schedulecycle(_indate character varying) FROM postgres; +GRANT ALL ON FUNCTION patch40.schedulecycle(_indate character varying) TO patch40_app; + + +-- +-- TOC entry 4757 (class 0 OID 0) +-- Dependencies: 381 +-- Name: FUNCTION scheduleinstance(_instanceid character varying, _accountid bigint, _slotlabel character varying, OUT scheduleresult character varying); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.scheduleinstance(_instanceid character varying, _accountid bigint, _slotlabel character varying, OUT scheduleresult character varying) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.scheduleinstance(_instanceid character varying, _accountid bigint, _slotlabel character varying, OUT scheduleresult character varying) FROM postgres; +GRANT ALL ON FUNCTION patch40.scheduleinstance(_instanceid character varying, _accountid bigint, _slotlabel character varying, OUT scheduleresult character varying) TO patch40_app; + + +-- +-- TOC entry 4758 (class 0 OID 0) +-- Dependencies: 384 +-- Name: FUNCTION scheduletmpreschedule(_instanceid character varying, _accountid bigint, _cycleid bigint, _altslotlabel character varying, OUT myreturn character varying); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40.scheduletmpreschedule(_instanceid character varying, _accountid bigint, _cycleid bigint, _altslotlabel character varying, OUT myreturn character varying) TO patch40_app; + + +-- +-- TOC entry 4759 (class 0 OID 0) +-- Dependencies: 345 +-- Name: FUNCTION scheduletmpreschedule_by_instance(_instanceid character varying, _accountid bigint, _cycleid bigint, _altslotid bigint, _deletereschedule bigint); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40.scheduletmpreschedule_by_instance(_instanceid character varying, _accountid bigint, _cycleid bigint, _altslotid bigint, _deletereschedule bigint) TO patch40_app; + + +-- +-- TOC entry 4760 (class 0 OID 0) +-- Dependencies: 385 +-- Name: FUNCTION schedulewaiver(_accountid bigint, _instanceid character varying, _cycleid bigint); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.schedulewaiver(_accountid bigint, _instanceid character varying, _cycleid bigint) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.schedulewaiver(_accountid bigint, _instanceid character varying, _cycleid bigint) FROM postgres; +GRANT ALL ON FUNCTION patch40.schedulewaiver(_accountid bigint, _instanceid character varying, _cycleid bigint) TO patch40_app; + + +-- +-- TOC entry 4761 (class 0 OID 0) +-- Dependencies: 386 +-- Name: FUNCTION schedulewaivertoggle(_accountid bigint, _instanceid character varying, _cycleid bigint, _toggle boolean, OUT scheduleresult character varying); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.schedulewaivertoggle(_accountid bigint, _instanceid character varying, _cycleid bigint, _toggle boolean, OUT scheduleresult character varying) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.schedulewaivertoggle(_accountid bigint, _instanceid character varying, _cycleid bigint, _toggle boolean, OUT scheduleresult character varying) FROM postgres; +GRANT ALL ON FUNCTION patch40.schedulewaivertoggle(_accountid bigint, _instanceid character varying, _cycleid bigint, _toggle boolean, OUT scheduleresult character varying) TO patch40_app; + + +-- +-- TOC entry 4762 (class 0 OID 0) +-- Dependencies: 353 +-- Name: FUNCTION scheduling_slotoccupancy(_instanceid character varying, _accountid bigint, _cycleid bigint, _cyclename character, _slotid bigint, _slotlabel character varying, _task character varying, _requester character varying, _guid uuid); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40.scheduling_slotoccupancy(_instanceid character varying, _accountid bigint, _cycleid bigint, _cyclename character, _slotid bigint, _slotlabel character varying, _task character varying, _requester character varying, _guid uuid) TO patch40_app; + + +-- +-- TOC entry 4763 (class 0 OID 0) +-- Dependencies: 355 +-- Name: FUNCTION slotdefinitons_insert(); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.slotdefinitons_insert() FROM PUBLIC; + + +-- +-- TOC entry 4764 (class 0 OID 0) +-- Dependencies: 364 +-- Name: PROCEDURE sp_dispatcher(); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON PROCEDURE patch40.sp_dispatcher() TO patch40_app; + + +-- +-- TOC entry 4765 (class 0 OID 0) +-- Dependencies: 378 +-- Name: PROCEDURE sp_g_step_action(IN _patchid uuid, IN _requester character varying, IN _action text); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON PROCEDURE patch40.sp_g_step_action(IN _patchid uuid, IN _requester character varying, IN _action text) FROM PUBLIC; +GRANT ALL ON PROCEDURE patch40.sp_g_step_action(IN _patchid uuid, IN _requester character varying, IN _action text) TO patch40_app; +GRANT ALL ON PROCEDURE patch40.sp_g_step_action(IN _patchid uuid, IN _requester character varying, IN _action text) TO patch40_ui_users; + + +-- +-- TOC entry 4766 (class 0 OID 0) +-- Dependencies: 383 +-- Name: PROCEDURE sp_g_step_done(IN _patchid uuid, IN _requester character varying); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON PROCEDURE patch40.sp_g_step_done(IN _patchid uuid, IN _requester character varying) TO patch40_app; +GRANT ALL ON PROCEDURE patch40.sp_g_step_done(IN _patchid uuid, IN _requester character varying) TO patch40_ui_users; + + +-- +-- TOC entry 4767 (class 0 OID 0) +-- Dependencies: 390 +-- Name: PROCEDURE sp_g_step_next(IN _uid bigint, IN _requester character varying); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON PROCEDURE patch40.sp_g_step_next(IN _uid bigint, IN _requester character varying) FROM PUBLIC; +REVOKE ALL ON PROCEDURE patch40.sp_g_step_next(IN _uid bigint, IN _requester character varying) FROM postgres; +GRANT ALL ON PROCEDURE patch40.sp_g_step_next(IN _uid bigint, IN _requester character varying) TO patch40_app; +GRANT ALL ON PROCEDURE patch40.sp_g_step_next(IN _uid bigint, IN _requester character varying) TO patch40_ui_users; + + +-- +-- TOC entry 4768 (class 0 OID 0) +-- Dependencies: 370 +-- Name: PROCEDURE sp_g_step_retry(IN _uid bigint, IN _requester character varying); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON PROCEDURE patch40.sp_g_step_retry(IN _uid bigint, IN _requester character varying) FROM PUBLIC; +REVOKE ALL ON PROCEDURE patch40.sp_g_step_retry(IN _uid bigint, IN _requester character varying) FROM postgres; +GRANT ALL ON PROCEDURE patch40.sp_g_step_retry(IN _uid bigint, IN _requester character varying) TO patch40_app; +GRANT ALL ON PROCEDURE patch40.sp_g_step_retry(IN _uid bigint, IN _requester character varying) TO patch40_ui_users; + + +-- +-- TOC entry 4769 (class 0 OID 0) +-- Dependencies: 357 +-- Name: PROCEDURE sp_remote_exec_output(IN in_uid bigint, IN in_rc integer, IN in_stdout text, IN in_stderr text); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON PROCEDURE patch40.sp_remote_exec_output(IN in_uid bigint, IN in_rc integer, IN in_stdout text, IN in_stderr text) FROM PUBLIC; +REVOKE ALL ON PROCEDURE patch40.sp_remote_exec_output(IN in_uid bigint, IN in_rc integer, IN in_stdout text, IN in_stderr text) FROM postgres; +GRANT ALL ON PROCEDURE patch40.sp_remote_exec_output(IN in_uid bigint, IN in_rc integer, IN in_stdout text, IN in_stderr text) TO patch40_app; + + +-- +-- TOC entry 4770 (class 0 OID 0) +-- Dependencies: 359 +-- Name: PROCEDURE sp_step_received(IN in_cycleid bigint, IN in_slotid integer, IN in_sequence_type integer, IN in_sequence_id integer, IN in_clusterid integer, IN in_patchid uuid, IN in_automationarn character varying, IN in_sequence_step integer, OUT out_uid bigint); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON PROCEDURE patch40.sp_step_received(IN in_cycleid bigint, IN in_slotid integer, IN in_sequence_type integer, IN in_sequence_id integer, IN in_clusterid integer, IN in_patchid uuid, IN in_automationarn character varying, IN in_sequence_step integer, OUT out_uid bigint) FROM PUBLIC; +REVOKE ALL ON PROCEDURE patch40.sp_step_received(IN in_cycleid bigint, IN in_slotid integer, IN in_sequence_type integer, IN in_sequence_id integer, IN in_clusterid integer, IN in_patchid uuid, IN in_automationarn character varying, IN in_sequence_step integer, OUT out_uid bigint) FROM postgres; +GRANT ALL ON PROCEDURE patch40.sp_step_received(IN in_cycleid bigint, IN in_slotid integer, IN in_sequence_type integer, IN in_sequence_id integer, IN in_clusterid integer, IN in_patchid uuid, IN in_automationarn character varying, IN in_sequence_step integer, OUT out_uid bigint) TO patch40_app; + + +-- +-- TOC entry 4771 (class 0 OID 0) +-- Dependencies: 363 +-- Name: PROCEDURE sp_step_update(IN in_uid bigint, IN in_statusid integer); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON PROCEDURE patch40.sp_step_update(IN in_uid bigint, IN in_statusid integer) FROM PUBLIC; +REVOKE ALL ON PROCEDURE patch40.sp_step_update(IN in_uid bigint, IN in_statusid integer) FROM postgres; +GRANT ALL ON PROCEDURE patch40.sp_step_update(IN in_uid bigint, IN in_statusid integer) TO patch40_app; + + +-- +-- TOC entry 4772 (class 0 OID 0) +-- Dependencies: 360 +-- Name: PROCEDURE sp_step_update_processing(IN in_uid bigint); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON PROCEDURE patch40.sp_step_update_processing(IN in_uid bigint) TO patch40_app; + + +-- +-- TOC entry 4773 (class 0 OID 0) +-- Dependencies: 361 +-- Name: PROCEDURE sp_step_update_processing(IN in_uid bigint, IN in_statusid integer); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON PROCEDURE patch40.sp_step_update_processing(IN in_uid bigint, IN in_statusid integer) FROM PUBLIC; +REVOKE ALL ON PROCEDURE patch40.sp_step_update_processing(IN in_uid bigint, IN in_statusid integer) FROM postgres; +GRANT ALL ON PROCEDURE patch40.sp_step_update_processing(IN in_uid bigint, IN in_statusid integer) TO patch40_app; + + +-- +-- TOC entry 4774 (class 0 OID 0) +-- Dependencies: 362 +-- Name: PROCEDURE sp_sw_store_existing(IN in_uid bigint, IN in_suppressedfrom timestamp without time zone, IN in_suppresseduntil timestamp without time zone); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON PROCEDURE patch40.sp_sw_store_existing(IN in_uid bigint, IN in_suppressedfrom timestamp without time zone, IN in_suppresseduntil timestamp without time zone) FROM PUBLIC; +REVOKE ALL ON PROCEDURE patch40.sp_sw_store_existing(IN in_uid bigint, IN in_suppressedfrom timestamp without time zone, IN in_suppresseduntil timestamp without time zone) FROM postgres; +GRANT ALL ON PROCEDURE patch40.sp_sw_store_existing(IN in_uid bigint, IN in_suppressedfrom timestamp without time zone, IN in_suppresseduntil timestamp without time zone) TO patch40_app; + + +-- +-- TOC entry 4775 (class 0 OID 0) +-- Dependencies: 354 +-- Name: FUNCTION step_launched(in_uid bigint, in_arn character varying); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.step_launched(in_uid bigint, in_arn character varying) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.step_launched(in_uid bigint, in_arn character varying) FROM postgres; +GRANT ALL ON FUNCTION patch40.step_launched(in_uid bigint, in_arn character varying) TO patch40_app; + + +-- +-- TOC entry 4776 (class 0 OID 0) +-- Dependencies: 387 +-- Name: FUNCTION step_received(in_cycleid bigint, in_slotid integer, in_sequence_type integer, in_sequence_id integer, in_clusterid integer, in_patchid uuid, in_automationarn character varying, in_sequence_step integer); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.step_received(in_cycleid bigint, in_slotid integer, in_sequence_type integer, in_sequence_id integer, in_clusterid integer, in_patchid uuid, in_automationarn character varying, in_sequence_step integer) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.step_received(in_cycleid bigint, in_slotid integer, in_sequence_type integer, in_sequence_id integer, in_clusterid integer, in_patchid uuid, in_automationarn character varying, in_sequence_step integer) FROM postgres; +GRANT ALL ON FUNCTION patch40.step_received(in_cycleid bigint, in_slotid integer, in_sequence_type integer, in_sequence_id integer, in_clusterid integer, in_patchid uuid, in_automationarn character varying, in_sequence_step integer) TO patch40_app; + + +-- +-- TOC entry 4777 (class 0 OID 0) +-- Dependencies: 356 +-- Name: FUNCTION step_result(in_uid bigint, in_statusid integer, in_sentstatus integer); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.step_result(in_uid bigint, in_statusid integer, in_sentstatus integer) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.step_result(in_uid bigint, in_statusid integer, in_sentstatus integer) FROM postgres; +GRANT ALL ON FUNCTION patch40.step_result(in_uid bigint, in_statusid integer, in_sentstatus integer) TO patch40_app; + + +-- +-- TOC entry 4778 (class 0 OID 0) +-- Dependencies: 346 +-- Name: FUNCTION thatpatchtuesday(_indate date); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40.thatpatchtuesday(_indate date) TO patch40_app; + + +-- +-- TOC entry 4779 (class 0 OID 0) +-- Dependencies: 382 +-- Name: FUNCTION unscheduleinstance(_accountid bigint, _instanceid character varying, OUT unscheduleresult character varying); Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON FUNCTION patch40.unscheduleinstance(_accountid bigint, _instanceid character varying, OUT unscheduleresult character varying) FROM PUBLIC; +REVOKE ALL ON FUNCTION patch40.unscheduleinstance(_accountid bigint, _instanceid character varying, OUT unscheduleresult character varying) FROM postgres; +GRANT ALL ON FUNCTION patch40.unscheduleinstance(_accountid bigint, _instanceid character varying, OUT unscheduleresult character varying) TO patch40_app; + + +-- +-- TOC entry 4780 (class 0 OID 0) +-- Dependencies: 347 +-- Name: FUNCTION "weekdayFromNumber"(innumber integer); Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON FUNCTION patch40."weekdayFromNumber"(innumber integer) TO patch40_app; + + +-- +-- TOC entry 4781 (class 0 OID 0) +-- Dependencies: 250 +-- Name: TABLE archive_ec2inventory; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.archive_ec2inventory FROM postgres; +GRANT SELECT,INSERT,DELETE ON TABLE patch40.archive_ec2inventory TO patch40_app; + + +-- +-- TOC entry 4782 (class 0 OID 0) +-- Dependencies: 251 +-- Name: TABLE archive_satellite; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.archive_satellite FROM postgres; +GRANT SELECT,INSERT,DELETE ON TABLE patch40.archive_satellite TO patch40_app; + + +-- +-- TOC entry 4783 (class 0 OID 0) +-- Dependencies: 304 +-- Name: TABLE audit_done; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.audit_done FROM postgres; +GRANT SELECT,INSERT ON TABLE patch40.audit_done TO patch40_app; +GRANT SELECT,INSERT ON TABLE patch40.audit_done TO patch40_ui_users; + + +-- +-- TOC entry 4784 (class 0 OID 0) +-- Dependencies: 303 +-- Name: TABLE audit_next; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.audit_next FROM postgres; +GRANT SELECT,INSERT ON TABLE patch40.audit_next TO patch40_app; +GRANT SELECT,INSERT ON TABLE patch40.audit_next TO patch40_ui_users; + + +-- +-- TOC entry 4785 (class 0 OID 0) +-- Dependencies: 302 +-- Name: TABLE audit_retry; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.audit_retry FROM postgres; +GRANT SELECT,INSERT ON TABLE patch40.audit_retry TO patch40_app; +GRANT SELECT,INSERT ON TABLE patch40.audit_retry TO patch40_ui_users; + + +-- +-- TOC entry 4786 (class 0 OID 0) +-- Dependencies: 253 +-- Name: TABLE clusters; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.clusters FROM postgres; +GRANT SELECT,INSERT,UPDATE ON TABLE patch40.clusters TO patch40_app; +GRANT SELECT ON TABLE patch40.clusters TO patch40_ui_users; + + +-- +-- TOC entry 4787 (class 0 OID 0) +-- Dependencies: 292 +-- Name: TABLE config; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.config FROM postgres; +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE patch40.config TO patch40_app; +GRANT SELECT ON TABLE patch40.config TO patch40_ui_users; + + +-- +-- TOC entry 4788 (class 0 OID 0) +-- Dependencies: 301 +-- Name: TABLE csps; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.csps FROM postgres; +GRANT SELECT,INSERT,UPDATE ON TABLE patch40.csps TO patch40_app; +GRANT SELECT ON TABLE patch40.csps TO patch40_ui_users; + + +-- +-- TOC entry 4789 (class 0 OID 0) +-- Dependencies: 254 +-- Name: TABLE cycles; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.cycles FROM postgres; +GRANT SELECT ON TABLE patch40.cycles TO patch40_app; +GRANT SELECT ON TABLE patch40.cycles TO patch40_ui_users; + + +-- +-- TOC entry 4790 (class 0 OID 0) +-- Dependencies: 255 +-- Name: SEQUENCE cycles_cycleid_seq; Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON SEQUENCE patch40.cycles_cycleid_seq TO patch40_app; + + +-- +-- TOC entry 4791 (class 0 OID 0) +-- Dependencies: 286 +-- Name: TABLE dispatch_history; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.dispatch_history FROM postgres; +GRANT SELECT,INSERT ON TABLE patch40.dispatch_history TO patch40_app; + + +-- +-- TOC entry 4792 (class 0 OID 0) +-- Dependencies: 285 +-- Name: SEQUENCE dispatch_history_uid_seq; Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON SEQUENCE patch40.dispatch_history_uid_seq TO patch40_app; + + +-- +-- TOC entry 4793 (class 0 OID 0) +-- Dependencies: 291 +-- Name: TABLE dispatch_types; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.dispatch_types FROM postgres; +GRANT SELECT ON TABLE patch40.dispatch_types TO patch40_app; + + +-- +-- TOC entry 4794 (class 0 OID 0) +-- Dependencies: 287 +-- Name: TABLE enable_dispatcher; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.enable_dispatcher FROM postgres; +GRANT SELECT,UPDATE ON TABLE patch40.enable_dispatcher TO patch40_app; + + +-- +-- TOC entry 4795 (class 0 OID 0) +-- Dependencies: 276 +-- Name: TABLE execution_output; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.execution_output FROM postgres; +GRANT SELECT,INSERT ON TABLE patch40.execution_output TO patch40_app; +GRANT SELECT ON TABLE patch40.execution_output TO patch40_ui_users; + + +-- +-- TOC entry 4796 (class 0 OID 0) +-- Dependencies: 257 +-- Name: SEQUENCE executions_uid_seq; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON SEQUENCE patch40.executions_uid_seq FROM postgres; +GRANT ALL ON SEQUENCE patch40.executions_uid_seq TO patch40_app; + + +-- +-- TOC entry 4797 (class 0 OID 0) +-- Dependencies: 258 +-- Name: TABLE executiontypes; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.executiontypes FROM postgres; +GRANT SELECT ON TABLE patch40.executiontypes TO patch40_app; + + +-- +-- TOC entry 4798 (class 0 OID 0) +-- Dependencies: 259 +-- Name: SEQUENCE executiontypes_executiontypeid_seq; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON SEQUENCE patch40.executiontypes_executiontypeid_seq FROM postgres; +GRANT ALL ON SEQUENCE patch40.executiontypes_executiontypeid_seq TO patch40_app; + + +-- +-- TOC entry 4799 (class 0 OID 0) +-- Dependencies: 296 +-- Name: TABLE g_homepage_time_stats; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.g_homepage_time_stats FROM postgres; +GRANT SELECT ON TABLE patch40.g_homepage_time_stats TO patch40_app; +GRANT SELECT ON TABLE patch40.g_homepage_time_stats TO patch40_ui_users; + + +-- +-- TOC entry 4800 (class 0 OID 0) +-- Dependencies: 289 +-- Name: SEQUENCE kernel_validation_id_seq; Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON SEQUENCE patch40.kernel_validation_id_seq TO patch40_app; + + +-- +-- TOC entry 4801 (class 0 OID 0) +-- Dependencies: 263 +-- Name: TABLE latest_ec2inventory; Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT SELECT ON TABLE patch40.latest_ec2inventory TO patch40_app; + + +-- +-- TOC entry 4802 (class 0 OID 0) +-- Dependencies: 264 +-- Name: TABLE latest_satellite; Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT SELECT ON TABLE patch40.latest_satellite TO patch40_app; + + +-- +-- TOC entry 4803 (class 0 OID 0) +-- Dependencies: 294 +-- Name: TABLE notification_template_types; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.notification_template_types FROM postgres; +GRANT SELECT ON TABLE patch40.notification_template_types TO patch40_app; + + +-- +-- TOC entry 4804 (class 0 OID 0) +-- Dependencies: 293 +-- Name: SEQUENCE notification_template_types_notificationtypeid_seq; Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON SEQUENCE patch40.notification_template_types_notificationtypeid_seq TO patch40_app; + + +-- +-- TOC entry 4805 (class 0 OID 0) +-- Dependencies: 295 +-- Name: TABLE notification_templates; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.notification_templates FROM postgres; +GRANT SELECT ON TABLE patch40.notification_templates TO patch40_app; + + +-- +-- TOC entry 4806 (class 0 OID 0) +-- Dependencies: 265 +-- Name: SEQUENCE procedures_uid_seq; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON SEQUENCE patch40.procedures_uid_seq FROM postgres; +GRANT ALL ON SEQUENCE patch40.procedures_uid_seq TO patch40_app; + + +-- +-- TOC entry 4807 (class 0 OID 0) +-- Dependencies: 266 +-- Name: TABLE qs_cycle_rolling15; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.qs_cycle_rolling15 FROM postgres; +GRANT SELECT ON TABLE patch40.qs_cycle_rolling15 TO patch40_app; + + +-- +-- TOC entry 4808 (class 0 OID 0) +-- Dependencies: 260 +-- Name: SEQUENCE slotdefinitions_slotid_seq; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE ALL ON SEQUENCE patch40.slotdefinitions_slotid_seq FROM postgres; +GRANT ALL ON SEQUENCE patch40.slotdefinitions_slotid_seq TO patch40_app; + + +-- +-- TOC entry 4809 (class 0 OID 0) +-- Dependencies: 261 +-- Name: TABLE slotdefinitions; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.slotdefinitions FROM postgres; +GRANT SELECT,UPDATE ON TABLE patch40.slotdefinitions TO patch40_app; +GRANT SELECT ON TABLE patch40.slotdefinitions TO patch40_ui_users; + + +-- +-- TOC entry 4810 (class 0 OID 0) +-- Dependencies: 262 +-- Name: TABLE targets; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.targets FROM postgres; +GRANT SELECT,INSERT,UPDATE ON TABLE patch40.targets TO patch40_app; +GRANT SELECT ON TABLE patch40.targets TO patch40_ui_users; + + +-- +-- TOC entry 4811 (class 0 OID 0) +-- Dependencies: 267 +-- Name: TABLE qs_slot_occupancy_detail; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.qs_slot_occupancy_detail FROM postgres; +GRANT SELECT ON TABLE patch40.qs_slot_occupancy_detail TO patch40_app; + + +-- +-- TOC entry 4812 (class 0 OID 0) +-- Dependencies: 268 +-- Name: TABLE qs_slot_occupancy_top; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.qs_slot_occupancy_top FROM postgres; +GRANT SELECT ON TABLE patch40.qs_slot_occupancy_top TO patch40_app; + + +-- +-- TOC entry 4813 (class 0 OID 0) +-- Dependencies: 269 +-- Name: TABLE reschedules; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.reschedules FROM postgres; +GRANT SELECT,DELETE,UPDATE ON TABLE patch40.reschedules TO patch40_app; +GRANT SELECT ON TABLE patch40.reschedules TO patch40_ui_users; + + +-- +-- TOC entry 4814 (class 0 OID 0) +-- Dependencies: 274 +-- Name: TABLE sequence_types; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.sequence_types FROM postgres; +GRANT SELECT ON TABLE patch40.sequence_types TO patch40_app; +GRANT SELECT ON TABLE patch40.sequence_types TO patch40_ui_users; + + +-- +-- TOC entry 4815 (class 0 OID 0) +-- Dependencies: 273 +-- Name: SEQUENCE sequence_types_sequence_type_id_seq; Type: ACL; Schema: patch40; Owner: postgres +-- + +GRANT ALL ON SEQUENCE patch40.sequence_types_sequence_type_id_seq TO patch40_app; + + +-- +-- TOC entry 4816 (class 0 OID 0) +-- Dependencies: 277 +-- Name: TABLE subsystems; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.subsystems FROM postgres; +GRANT SELECT ON TABLE patch40.subsystems TO patch40_app; + + +-- +-- TOC entry 4817 (class 0 OID 0) +-- Dependencies: 271 +-- Name: TABLE users; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.users FROM postgres; +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE patch40.users TO patch40_app; + + +-- +-- TOC entry 4818 (class 0 OID 0) +-- Dependencies: 272 +-- Name: TABLE waivers; Type: ACL; Schema: patch40; Owner: postgres +-- + +REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE patch40.waivers FROM postgres; +GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE patch40.waivers TO patch40_app; +GRANT SELECT ON TABLE patch40.waivers TO patch40_ui_users; + + +-- +-- TOC entry 2361 (class 826 OID 29623) +-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: patch40; Owner: postgres +-- + +ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA patch40 GRANT SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLES TO patch40_app; + + +-- Completed on 2026-05-22 14:00:38 + +-- +-- PostgreSQL database dump complete +-- + +\unrestrict zAxR96Kp0drTyUOpXNPqmViRJ0UJNgQlGeXnUvBbWYZbVBmfaLz4uIrtA3AynJr + diff --git a/sqs.tf b/sqs.tf new file mode 100644 index 0000000..0f9874d --- /dev/null +++ b/sqs.tf @@ -0,0 +1,109 @@ +# ─── SQS Queue Policy Documents ───────────────────────────────────────────── +# Note: owner-statement queue policies use lowercase "sqs:" prefix per convention. +# policy_id and sid are set explicitly per review feedback. + +data "aws_iam_policy_document" "sqs_dispatch_lambda" { + policy_id = "${local.sqs_dispatch_lambda_name}-policy" + + statement { + sid = "AllowAccountOwnerFullAccess" + effect = "Allow" + actions = ["sqs:*"] + + principals { + type = "AWS" + identifiers = ["arn:${local.partition}:iam::${local.account_id}:root"] + } + + resources = [aws_sqs_queue.dispatch_lambda.arn] + } +} + +data "aws_iam_policy_document" "sqs_dispatch_remote_execution" { + policy_id = "${local.sqs_dispatch_remote_execution_name}-policy" + + statement { + sid = "AllowAccountOwnerFullAccess" + effect = "Allow" + actions = ["sqs:*"] + + principals { + type = "AWS" + identifiers = ["arn:${local.partition}:iam::${local.account_id}:root"] + } + + resources = [aws_sqs_queue.dispatch_remote_execution.arn] + } +} + +data "aws_iam_policy_document" "sqs_results" { + policy_id = "${local.sqs_results_name}-policy" + + statement { + sid = "AllowAccountOwnerFullAccess" + effect = "Allow" + actions = ["sqs:*"] + + principals { + type = "AWS" + identifiers = ["arn:${local.partition}:iam::${local.account_id}:root"] + } + + resources = [aws_sqs_queue.results.arn] + } +} + +# ─── SQS Queues ────────────────────────────────────────────────────────────── + +resource "aws_sqs_queue" "dispatch_lambda" { + name = local.sqs_dispatch_lambda_name + delay_seconds = 3 + max_message_size = 1048576 + message_retention_seconds = 345600 + receive_wait_time_seconds = 0 + visibility_timeout_seconds = 360 + sqs_managed_sse_enabled = true + + tags = local.tags_sqs +} + +resource "aws_sqs_queue" "dispatch_remote_execution" { + name = local.sqs_dispatch_remote_execution_name + delay_seconds = 5 + max_message_size = 1048576 + message_retention_seconds = 345600 + receive_wait_time_seconds = 0 + visibility_timeout_seconds = 3600 + sqs_managed_sse_enabled = true + + tags = local.tags_sqs +} + +resource "aws_sqs_queue" "results" { + name = local.sqs_results_name + delay_seconds = 0 + max_message_size = 1048576 + message_retention_seconds = 345600 + receive_wait_time_seconds = 0 + visibility_timeout_seconds = 30 + sqs_managed_sse_enabled = true + + tags = local.tags_sqs +} + +# ─── SQS Queue Policies ────────────────────────────────────────────────────── + +resource "aws_sqs_queue_policy" "dispatch_lambda" { + queue_url = aws_sqs_queue.dispatch_lambda.id + policy = data.aws_iam_policy_document.sqs_dispatch_lambda.json +} + +resource "aws_sqs_queue_policy" "dispatch_remote_execution" { + queue_url = aws_sqs_queue.dispatch_remote_execution.id + policy = data.aws_iam_policy_document.sqs_dispatch_remote_execution.json +} + +resource "aws_sqs_queue_policy" "results" { + queue_url = aws_sqs_queue.results.id + policy = data.aws_iam_policy_document.sqs_results.json +} diff --git a/variables.common.tf b/variables.common.tf index c77ef47..e2363b9 100644 --- a/variables.common.tf +++ b/variables.common.tf @@ -18,9 +18,3 @@ variable "override_prefixes" { type = map(string) default = {} } - -variable "tags" { - description = "AWS Tags to apply to appropriate resources" - type = map(string) - default = {} -} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..904cdfc --- /dev/null +++ b/variables.tf @@ -0,0 +1,89 @@ +# ─── Identity / BLF ────────────────────────────────────────────────────────── + +variable "name_prefix" { + description = "BLF name prefix applied to all resources (e.g. 'csvd-patch40'). Drives resource names for IAM roles, Lambda functions, SQS queues, RDS cluster, KMS key, and CloudWatch log groups." + type = string + default = "csvd-patch40" +} + +# ─── FinOps Tags (required) ─────────────────────────────────────────────────── + +variable "finops_project_name" { + description = "FinOps project name tag value (e.g. 'csvd_patch4'). Must NOT be a catchall value." + type = string +} + +variable "finops_project_number" { + description = "FinOps project number tag value (e.g. 'fs0000000009'). Must NOT be a catchall value." + type = string +} + +# ─── Additional Tags ────────────────────────────────────────────────────────── + +variable "tags" { + description = "Additional tags merged onto every resource (account tags, infrastructure tags, application tags from the calling module)." + type = map(string) + default = {} +} + +# ─── Networking ─────────────────────────────────────────────────────────────── + +variable "vpc_name" { + description = "Value of the Name tag on the target VPC. Used for security group and subnet lookups." + type = string +} + +variable "db_subnet_group_name" { + description = "Name of the existing RDS subnet group to use for the Aurora cluster. Should reference *-db-* subnets." + type = string +} + +variable "db_security_group_name" { + description = "Name tag of the security group to attach to the RDS cluster." + type = string +} + +variable "lambda_security_group_name" { + description = "Name tag of the security group to attach to Lambda functions." + type = string +} + +# ─── RDS ────────────────────────────────────────────────────────────────────── + +variable "db_engine_version" { + description = "Aurora PostgreSQL engine version." + type = string + default = "15.15" +} + +variable "db_parameter_group_name" { + description = "Name of the existing Aurora PostgreSQL parameter group." + type = string + default = "census-baseline-aurora-postgres-15" +} + +variable "preferred_backup_window" { + description = "Daily time range (UTC) for automated RDS backups. Format: hh24:mi-hh24:mi." + type = string + default = "22:21-22:51" +} + +variable "preferred_maintenance_window" { + description = "Weekly time range (UTC) for RDS maintenance. Format: ddd:hh24:mi-ddd:hh24:mi." + type = string + default = "mon:21:42-mon:22:12" +} + +# ─── Lambda ─────────────────────────────────────────────────────────────────── + +variable "lambda_runtime" { + description = "Python runtime version for all Lambda functions." + type = string + default = "python3.13" +} + +variable "log_retention_days" { + description = "CloudWatch log group retention period in days." + type = number + default = 14 +} diff --git a/versions.tf b/versions.tf index 4ba10ce..86163ea 100644 --- a/versions.tf +++ b/versions.tf @@ -1,9 +1,13 @@ terraform { + required_version = ">= 1.0.0" required_providers { aws = { source = "hashicorp/aws" - version = ">= 3.66.0" + version = ">= 6.0" + } + archive = { + source = "hashicorp/archive" + version = ">= 2.0" } } -# required_version = ">= 0.13" } From 964e5518c7d26665a40d37009d013643e93dac95 Mon Sep 17 00:00:00 2001 From: Dave Arnold Date: Wed, 8 Jul 2026 14:06:51 -0400 Subject: [PATCH 2/7] feat: add tags.tf and tags.yml to module --- tags.tf | 10 ++++++++++ tags.yml | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tags.tf create mode 100644 tags.yml diff --git a/tags.tf b/tags.tf new file mode 100644 index 0000000..3e8cb3b --- /dev/null +++ b/tags.tf @@ -0,0 +1,10 @@ +module "tags" { + source = "git@github.e.it.census.gov:terraform-modules/boc-nts//tags" + filename = format("%v/%v", path.root, "tags.yml") + + legacy_tags = merge( + var.account_tags, + var.infrastructure_tags, + var.application_tags, + ) +} \ No newline at end of file diff --git a/tags.yml b/tags.yml new file mode 100644 index 0000000..bad64a9 --- /dev/null +++ b/tags.yml @@ -0,0 +1,10 @@ +finops: + number: 2 + name: csvd_patch + roles: + - rds + - kms + - sqs + - iam + - lambda + - cloudwatch \ No newline at end of file From 518da425be3ad5dce595d9227571ad0560a33dba Mon Sep 17 00:00:00 2001 From: Dave Arnold Date: Wed, 8 Jul 2026 14:11:37 -0400 Subject: [PATCH 3/7] refactor: use boc-nts tags module outputs for resource tagging - tags.tf: set legacy_tags = var.tags (replaces account/infra/app var merge) - locals.tf: replace manual finops_tags + base_tags with module.tags.tags and per-resource role via module.tags.finops_roles[role] - variables.tf: remove finops_project_name and finops_project_number variables (finops config now lives in tags.yml) --- locals.tf | 19 ++++++------------- tags.tf | 6 +----- variables.tf | 12 ------------ 3 files changed, 7 insertions(+), 30 deletions(-) diff --git a/locals.tf b/locals.tf index dc8f1d2..2598999 100644 --- a/locals.tf +++ b/locals.tf @@ -1,18 +1,11 @@ locals { # ─── Tagging ──────────────────────────────────────────────────────────────── - finops_tags = { - finops_project_name = var.finops_project_name - finops_project_number = var.finops_project_number - } - - base_tags = merge({ "boc:created_by" = "terraform" }, var.tags) - - tags_rds = merge(local.base_tags, local.finops_tags, { finops_project_role = "${var.name_prefix}_rds" }) - tags_kms = merge(local.base_tags, local.finops_tags, { finops_project_role = "${var.name_prefix}_kms" }) - tags_sqs = merge(local.base_tags, local.finops_tags, { finops_project_role = "${var.name_prefix}_sqs" }) - tags_lambda = merge(local.base_tags, local.finops_tags, { finops_project_role = "${var.name_prefix}_lambda" }) - tags_cloudwatch = merge(local.base_tags, local.finops_tags, { finops_project_role = "${var.name_prefix}_cloudwatch" }) - tags_iam = merge(local.base_tags, local.finops_tags, { finops_project_role = "${var.name_prefix}_iam" }) + tags_rds = merge(module.tags.tags, module.tags.finops_roles["rds"]) + tags_kms = merge(module.tags.tags, module.tags.finops_roles["kms"]) + tags_sqs = merge(module.tags.tags, module.tags.finops_roles["sqs"]) + tags_lambda = merge(module.tags.tags, module.tags.finops_roles["lambda"]) + tags_cloudwatch = merge(module.tags.tags, module.tags.finops_roles["cloudwatch"]) + tags_iam = merge(module.tags.tags, module.tags.finops_roles["iam"]) # ─── Resource Names ───────────────────────────────────────────────────────── lambda_dispatcher_name = "${var.name_prefix}-dispatcher" diff --git a/tags.tf b/tags.tf index 3e8cb3b..a15ded0 100644 --- a/tags.tf +++ b/tags.tf @@ -2,9 +2,5 @@ module "tags" { source = "git@github.e.it.census.gov:terraform-modules/boc-nts//tags" filename = format("%v/%v", path.root, "tags.yml") - legacy_tags = merge( - var.account_tags, - var.infrastructure_tags, - var.application_tags, - ) + legacy_tags = var.tags } \ No newline at end of file diff --git a/variables.tf b/variables.tf index 904cdfc..7005d5c 100644 --- a/variables.tf +++ b/variables.tf @@ -6,18 +6,6 @@ variable "name_prefix" { default = "csvd-patch40" } -# ─── FinOps Tags (required) ─────────────────────────────────────────────────── - -variable "finops_project_name" { - description = "FinOps project name tag value (e.g. 'csvd_patch4'). Must NOT be a catchall value." - type = string -} - -variable "finops_project_number" { - description = "FinOps project number tag value (e.g. 'fs0000000009'). Must NOT be a catchall value." - type = string -} - # ─── Additional Tags ────────────────────────────────────────────────────────── variable "tags" { From 78f3ea2447ae19979101d021374e01a7a6f85046 Mon Sep 17 00:00:00 2001 From: Dave Arnold Date: Wed, 8 Jul 2026 15:39:57 -0400 Subject: [PATCH 4/7] fix: remove double r- prefix from role name locals The aws-iam-role module prepends r- internally, so passing r-name resulted in r-r-name. Strip the prefix from patch_role_name, patch_execution_role_name, and patch_execproxy_role_name. --- locals.tf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/locals.tf b/locals.tf index 2598999..36c6e81 100644 --- a/locals.tf +++ b/locals.tf @@ -24,9 +24,9 @@ locals { kms_alias_name = "k-kms-${var.name_prefix}" - patch_role_name = "r-${var.name_prefix}" - patch_execution_role_name = "r-${var.name_prefix}-execution" - patch_execproxy_role_name = "r-${var.name_prefix}-execproxy" + patch_role_name = var.name_prefix + patch_execution_role_name = "${var.name_prefix}-execution" + patch_execproxy_role_name = "${var.name_prefix}-execproxy" patch_policy_name = "p-${var.name_prefix}" patch_execution_policy_name = "p-${var.name_prefix}-execution" From 74ed0ef10925ed08f3d2e3f7afcae07aea48daef Mon Sep 17 00:00:00 2001 From: Dave Arnold Date: Wed, 8 Jul 2026 15:52:25 -0400 Subject: [PATCH 5/7] style: replace string interpolation with format() org-wide convention - locals.tf: all resource/log group name expressions - lambda.tf: path.module archive sources and layer source_path - sqs.tf: policy_id fields and owner ARN identifiers - policies.tf: all ARN constructions (iam, lambda, logs, rds-db) and org path - roles.tf: module source git@ format + role_description strings Also corrects roles.tf module sources from git::https:// to git@ per terraform-support naming convention. --- lambda.tf | 14 +++++++------- locals.tf | 38 +++++++++++++++++++------------------- policies.tf | 20 ++++++++++---------- roles.tf | 12 ++++++------ sqs.tf | 12 ++++++------ 5 files changed, 48 insertions(+), 48 deletions(-) diff --git a/lambda.tf b/lambda.tf index 8438faa..aca42ca 100644 --- a/lambda.tf +++ b/lambda.tf @@ -1,19 +1,19 @@ data "archive_file" "dispatcher" { type = "zip" - source_dir = "${path.module}/lambda-dispatcher" - output_path = "${path.module}/builds/dispatcher.zip" + source_dir = format("%v/lambda-dispatcher", path.module) + output_path = format("%v/builds/dispatcher.zip", path.module) } data "archive_file" "step_result" { type = "zip" - source_dir = "${path.module}/lambda-step-result" - output_path = "${path.module}/builds/step-result.zip" + source_dir = format("%v/lambda-step-result", path.module) + output_path = format("%v/builds/step-result.zip", path.module) } data "archive_file" "worker" { type = "zip" - source_dir = "${path.module}/lambda-worker" - output_path = "${path.module}/builds/worker.zip" + source_dir = format("%v/lambda-worker", path.module) + output_path = format("%v/builds/worker.zip", path.module) } module "lambda_layer" { @@ -30,7 +30,7 @@ module "lambda_layer" { source_path = [ { - path = "${path.module}/lambda-layer" + path = format("%v/lambda-layer", path.module) pip_requirements = true prefix_in_zip = "python" } diff --git a/locals.tf b/locals.tf index 36c6e81..64d1cf7 100644 --- a/locals.tf +++ b/locals.tf @@ -8,33 +8,33 @@ locals { tags_iam = merge(module.tags.tags, module.tags.finops_roles["iam"]) # ─── Resource Names ───────────────────────────────────────────────────────── - lambda_dispatcher_name = "${var.name_prefix}-dispatcher" - lambda_step_result_name = "${var.name_prefix}-step-result" - lambda_worker_name = "${var.name_prefix}-worker-lambda" - lambda_layer_name = "${var.name_prefix}-layer-v1" + lambda_dispatcher_name = format("%v-dispatcher", var.name_prefix) + lambda_step_result_name = format("%v-step-result", var.name_prefix) + lambda_worker_name = format("%v-worker-lambda", var.name_prefix) + lambda_layer_name = format("%v-layer-v1", var.name_prefix) - sqs_dispatch_lambda_name = "${var.name_prefix}-dispatch-lambda" - sqs_dispatch_remote_execution_name = "${var.name_prefix}-dispatch-remote-execution" - sqs_results_name = "${var.name_prefix}-results" + sqs_dispatch_lambda_name = format("%v-dispatch-lambda", var.name_prefix) + sqs_dispatch_remote_execution_name = format("%v-dispatch-remote-execution", var.name_prefix) + sqs_results_name = format("%v-results", var.name_prefix) db_cluster_name = var.name_prefix - db_instance_name = "${var.name_prefix}-instance-1" - db_name = replace("${var.name_prefix}_db", "-", "_") - db_user_name = "${replace(var.name_prefix, "-", "")}lambda_iam" + db_instance_name = format("%v-instance-1", var.name_prefix) + db_name = replace(format("%v_db", var.name_prefix), "-", "_") + db_user_name = format("%vlambda_iam", replace(var.name_prefix, "-", "")) - kms_alias_name = "k-kms-${var.name_prefix}" + kms_alias_name = format("k-kms-%v", var.name_prefix) patch_role_name = var.name_prefix - patch_execution_role_name = "${var.name_prefix}-execution" - patch_execproxy_role_name = "${var.name_prefix}-execproxy" + patch_execution_role_name = format("%v-execution", var.name_prefix) + patch_execproxy_role_name = format("%v-execproxy", var.name_prefix) - patch_policy_name = "p-${var.name_prefix}" - patch_execution_policy_name = "p-${var.name_prefix}-execution" - patch_execproxy_policy_name = "p-${var.name_prefix}-execproxy" + patch_policy_name = format("p-%v", var.name_prefix) + patch_execution_policy_name = format("p-%v-execution", var.name_prefix) + patch_execproxy_policy_name = format("p-%v-execproxy", var.name_prefix) - log_group_dispatcher = "/aws/lambda/${local.lambda_dispatcher_name}" - log_group_step_result = "/aws/lambda/${local.lambda_step_result_name}" - log_group_worker = "/aws/lambda/${local.lambda_worker_name}" + log_group_dispatcher = format("/aws/lambda/%v", local.lambda_dispatcher_name) + log_group_step_result = format("/aws/lambda/%v", local.lambda_step_result_name) + log_group_worker = format("/aws/lambda/%v", local.lambda_worker_name) # ─── ARN helpers ──────────────────────────────────────────────────────────── partition = data.aws_partition.current.partition diff --git a/policies.tf b/policies.tf index 4c317f8..66cbfc5 100644 --- a/policies.tf +++ b/policies.tf @@ -7,17 +7,17 @@ data "aws_iam_policy_document" "patch_role_assume" { actions = ["sts:AssumeRole"] principals { type = "AWS" - identifiers = ["arn:${local.partition}:iam::${local.account_id}:root"] + identifiers = [format("arn:%v:iam::%v:root", local.partition, local.account_id)] } condition { test = "ArnLike" variable = "aws:PrincipalArn" - values = ["arn:${local.partition}:iam::${local.account_id}:role/${local.patch_execution_role_name}"] + values = [format("arn:%v:iam::%v:role/%v", local.partition, local.account_id, local.patch_execution_role_name)] } condition { test = "ForAnyValue:StringLike" variable = "aws:PrincipalOrgPaths" - values = ["${data.aws_organizations_organization.org.id}/*"] + values = [format("%v/*", data.aws_organizations_organization.org.id)] } } } @@ -36,7 +36,7 @@ data "aws_iam_policy_document" "patch_execution_role_assume" { actions = ["sts:AssumeRole"] principals { type = "AWS" - identifiers = ["arn:${local.partition}:iam::${local.account_id}:role/${local.patch_execproxy_role_name}"] + identifiers = [format("arn:%v:iam::%v:role/%v", local.partition, local.account_id, local.patch_execproxy_role_name)] } } } @@ -94,9 +94,9 @@ data "aws_iam_policy_document" "patch_execution_role" { effect = "Allow" actions = ["lambda:InvokeFunction"] resources = [ - "arn:${local.partition}:lambda:${local.region}:${local.account_id}:function/${local.lambda_dispatcher_name}", - "arn:${local.partition}:lambda:${local.region}:${local.account_id}:function/${local.lambda_worker_name}", - "arn:${local.partition}:lambda:${local.region}:${local.account_id}:function/${local.lambda_step_result_name}", + format("arn:%v:lambda:%v:%v:function/%v", local.partition, local.region, local.account_id, local.lambda_dispatcher_name), + format("arn:%v:lambda:%v:%v:function/%v", local.partition, local.region, local.account_id, local.lambda_worker_name), + format("arn:%v:lambda:%v:%v:function/%v", local.partition, local.region, local.account_id, local.lambda_step_result_name), ] } statement { @@ -109,7 +109,7 @@ data "aws_iam_policy_document" "patch_execution_role" { ] # Scoped to log groups owned by this module resources = [ - "arn:${local.partition}:logs:${local.region}:${local.account_id}:log-group:/aws/lambda/${var.name_prefix}*", + format("arn:%v:logs:%v:%v:log-group:/aws/lambda/%v*", local.partition, local.region, local.account_id, var.name_prefix), ] } statement { @@ -149,7 +149,7 @@ data "aws_iam_policy_document" "patch_execution_role" { effect = "Allow" actions = ["rds-db:connect"] resources = [ - "arn:${local.partition}:rds-db:${local.region}:${local.account_id}:dbuser:cluster-*/${local.db_user_name}", + format("arn:%v:rds-db:%v:%v:dbuser:cluster-*/%v", local.partition, local.region, local.account_id, local.db_user_name), ] } } @@ -160,7 +160,7 @@ data "aws_iam_policy_document" "patch_execproxy_role" { effect = "Allow" actions = ["rds-db:connect"] resources = [ - "arn:${local.partition}:rds-db:${local.region}:${local.account_id}:dbuser:cluster-*/${local.db_user_name}", + format("arn:%v:rds-db:%v:%v:dbuser:cluster-*/%v", local.partition, local.region, local.account_id, local.db_user_name), ] } statement { diff --git a/roles.tf b/roles.tf index 53f17a5..aeccc9d 100644 --- a/roles.tf +++ b/roles.tf @@ -1,9 +1,9 @@ # patch_role — assumed by patch_execution_role to perform EC2 operations in target accounts module "patch_role" { - source = "git::https://github.e.it.census.gov/terraform-modules/aws-iam-role.git?ref=tf-upgrade" + source = "git@github.e.it.census.gov:terraform-modules/aws-iam-role.git?ref=tf-upgrade" role_name = local.patch_role_name - role_description = "Assumed by ${local.patch_execution_role_name} to execute patching operations on EC2 instances in target accounts" + role_description = format("Assumed by %v to execute patching operations on EC2 instances in target accounts", local.patch_execution_role_name) assume_policy_document = data.aws_iam_policy_document.patch_role_assume.json attached_policies = [aws_iam_policy.patch_role.arn] @@ -12,10 +12,10 @@ module "patch_role" { # patch_execution_role — assumed by Lambda functions to orchestrate patching module "patch_execution_role" { - source = "git::https://github.e.it.census.gov/terraform-modules/aws-iam-role.git?ref=tf-upgrade" + source = "git@github.e.it.census.gov:terraform-modules/aws-iam-role.git?ref=tf-upgrade" role_name = local.patch_execution_role_name - role_description = "Assumed by Lambda functions to invoke patch operations, access SQS/RDS, and assume ${local.patch_role_name} in target accounts" + role_description = format("Assumed by Lambda functions to invoke patch operations, access SQS/RDS, and assume %v in target accounts", local.patch_role_name) assume_policy_document = data.aws_iam_policy_document.patch_execution_role_assume.json attached_policies = [aws_iam_policy.patch_execution_role.arn] @@ -26,10 +26,10 @@ module "patch_execution_role" { # This instance profile is used by the EC2 host running p4proxy to authenticate # to RDS via IAM and to assume patch_execution_role for orchestration tasks. module "patch_execproxy_role" { - source = "git::https://github.e.it.census.gov/terraform-modules/aws-iam-role.git?ref=tf-upgrade" + source = "git@github.e.it.census.gov:terraform-modules/aws-iam-role.git?ref=tf-upgrade" role_name = local.patch_execproxy_role_name - role_description = "Applied to the EC2 host running p4proxy; allows RDS IAM auth and assumption of ${local.patch_execution_role_name}" + role_description = format("Applied to the EC2 host running p4proxy; allows RDS IAM auth and assumption of %v", local.patch_execution_role_name) assume_policy_document = data.aws_iam_policy_document.patch_execproxy_role_assume.json attached_policies = [aws_iam_policy.patch_execproxy_role.arn] enable_instance_profile = true diff --git a/sqs.tf b/sqs.tf index 0f9874d..cc79761 100644 --- a/sqs.tf +++ b/sqs.tf @@ -3,7 +3,7 @@ # policy_id and sid are set explicitly per review feedback. data "aws_iam_policy_document" "sqs_dispatch_lambda" { - policy_id = "${local.sqs_dispatch_lambda_name}-policy" + policy_id = format("%v-policy", local.sqs_dispatch_lambda_name) statement { sid = "AllowAccountOwnerFullAccess" @@ -12,7 +12,7 @@ data "aws_iam_policy_document" "sqs_dispatch_lambda" { principals { type = "AWS" - identifiers = ["arn:${local.partition}:iam::${local.account_id}:root"] + identifiers = [format("arn:%v:iam::%v:root", local.partition, local.account_id)] } resources = [aws_sqs_queue.dispatch_lambda.arn] @@ -20,7 +20,7 @@ data "aws_iam_policy_document" "sqs_dispatch_lambda" { } data "aws_iam_policy_document" "sqs_dispatch_remote_execution" { - policy_id = "${local.sqs_dispatch_remote_execution_name}-policy" + policy_id = format("%v-policy", local.sqs_dispatch_remote_execution_name) statement { sid = "AllowAccountOwnerFullAccess" @@ -29,7 +29,7 @@ data "aws_iam_policy_document" "sqs_dispatch_remote_execution" { principals { type = "AWS" - identifiers = ["arn:${local.partition}:iam::${local.account_id}:root"] + identifiers = [format("arn:%v:iam::%v:root", local.partition, local.account_id)] } resources = [aws_sqs_queue.dispatch_remote_execution.arn] @@ -37,7 +37,7 @@ data "aws_iam_policy_document" "sqs_dispatch_remote_execution" { } data "aws_iam_policy_document" "sqs_results" { - policy_id = "${local.sqs_results_name}-policy" + policy_id = format("%v-policy", local.sqs_results_name) statement { sid = "AllowAccountOwnerFullAccess" @@ -46,7 +46,7 @@ data "aws_iam_policy_document" "sqs_results" { principals { type = "AWS" - identifiers = ["arn:${local.partition}:iam::${local.account_id}:root"] + identifiers = [format("arn:%v:iam::%v:root", local.partition, local.account_id)] } resources = [aws_sqs_queue.results.arn] From 21ec4cd3cac3a8a4608b9a5ed4174e1b81766ac4 Mon Sep 17 00:00:00 2001 From: Dave Arnold Date: Wed, 8 Jul 2026 15:55:11 -0400 Subject: [PATCH 6/7] fix: wire missing DB env vars into worker and step_result lambdas worker: - replace unused RESULTS_QUEUE_URL with input_queue_url (sqs.delete_message) - add dbEndpoint, dbUsername, dbDatabase, dbRegion step_result: - add environment block with dbEndpoint, dbUsername, dbDatabase, dbRegion dispatcher unchanged (no DB access) --- lambda.tf | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lambda.tf b/lambda.tf index aca42ca..d0b737b 100644 --- a/lambda.tf +++ b/lambda.tf @@ -96,6 +96,15 @@ resource "aws_lambda_function" "step_result" { ipv6_allowed_for_dual_stack = false } + environment { + variables = { + dbEndpoint = aws_rds_cluster.patch4.endpoint + dbUsername = local.db_user_name + dbDatabase = local.db_name + dbRegion = local.region + } + } + ephemeral_storage { size = 512 } tracing_config { mode = "PassThrough" } @@ -130,7 +139,11 @@ resource "aws_lambda_function" "worker" { environment { variables = { - RESULTS_QUEUE_URL = aws_sqs_queue.results.url + input_queue_url = aws_sqs_queue.dispatch_lambda.url + dbEndpoint = aws_rds_cluster.patch4.endpoint + dbUsername = local.db_user_name + dbDatabase = local.db_name + dbRegion = local.region } } From f7c125694ad6b200bafd0d77002e4b3e2033d4ed Mon Sep 17 00:00:00 2001 From: Dave Arnold Date: Wed, 8 Jul 2026 16:35:21 -0400 Subject: [PATCH 7/7] fix: replace hardcoded target role ARN in ec2.py with env vars - Add patch_target_role_name variable (default: r-inf-patch) for the cross-account role name that must exist in each target account - Worker Lambda now passes aws_partition and patch_target_role_name as env vars alongside existing DB/queue vars - ec2.py builds the target ARN dynamically from env vars instead of hardcoding partition (aws-us-gov) and role name (r-inf-patch) --- lambda-worker/src/ec2.py | 7 +++++-- lambda.tf | 12 +++++++----- variables.tf | 6 ++++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lambda-worker/src/ec2.py b/lambda-worker/src/ec2.py index a30b397..239beeb 100644 --- a/lambda-worker/src/ec2.py +++ b/lambda-worker/src/ec2.py @@ -1,5 +1,6 @@ import boto3 import logging +import os from botocore.config import Config from botocore.exceptions import ClientError @@ -18,8 +19,10 @@ def assumedRoleSession(account, region): botoconf = Config(region_name=region, retries={'max_attempts': 5, 'mode': 'standard'}) sts = boto3.client('sts', region_name=region, config=botoconf) - sts_role_arn = f"arn:aws-us-gov:iam::{account}:role/r-inf-patch" - sts_session_name = f"patch_session_{account}" + sts_role_arn = "arn:{}:iam::{}:role/{}".format( + os.environ["aws_partition"], account, os.environ["patch_target_role_name"] + ) + sts_session_name = "patch_session_{}".format(account) try: # CHANGED: Ensure this variable name matches the one used below diff --git a/lambda.tf b/lambda.tf index d0b737b..78fef7f 100644 --- a/lambda.tf +++ b/lambda.tf @@ -139,11 +139,13 @@ resource "aws_lambda_function" "worker" { environment { variables = { - input_queue_url = aws_sqs_queue.dispatch_lambda.url - dbEndpoint = aws_rds_cluster.patch4.endpoint - dbUsername = local.db_user_name - dbDatabase = local.db_name - dbRegion = local.region + input_queue_url = aws_sqs_queue.dispatch_lambda.url + aws_partition = local.partition + patch_target_role_name = var.patch_target_role_name + dbEndpoint = aws_rds_cluster.patch4.endpoint + dbUsername = local.db_user_name + dbDatabase = local.db_name + dbRegion = local.region } } diff --git a/variables.tf b/variables.tf index 7005d5c..e240490 100644 --- a/variables.tf +++ b/variables.tf @@ -6,6 +6,12 @@ variable "name_prefix" { default = "csvd-patch40" } +variable "patch_target_role_name" { + description = "Name of the IAM role that exists in each target account and is assumed by the worker Lambda to perform EC2 operations (e.g. 'r-inf-patch')." + type = string + default = "r-inf-patch" +} + # ─── Additional Tags ────────────────────────────────────────────────────────── variable "tags" {