Admin workflow - IAM PERMISSIONS md, utils module etc. (#1323)
* IAM PERMISSIONS md, utils module etc. * IAM PERMISSIONS md, utils module etc. * IAM PERMISSIONS md, utils module etc. * IAM PERMISSIONS md, utils module etc. * IAM PERMISSIONS md, utils module etc. * IAM PERMISSIONS md, utils module etc. * IAM PERMISSIONS md, utils module etc.
This commit is contained in:
+266
@@ -0,0 +1,266 @@
|
||||
# IAM Permissions for Admin Approval Workflow sample
|
||||
|
||||
Create IAM user or role with the following permissions.
|
||||
|
||||
> **Before using these policies**, replace every occurrence of `YOUR_ACCOUNT_ID` with your 12-digit AWS account ID.
|
||||
> Run the following command to find it:
|
||||
> ```bash
|
||||
> aws sts get-caller-identity --query Account --output text
|
||||
> ```
|
||||
> Then do a find-and-replace of `YOUR_ACCOUNT_ID` in the JSON below before attaching the policy.
|
||||
|
||||
## Policy for AWS Agent Registry access (Administrator)
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "AllowCreatingAndListingRegistries",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"bedrock-agentcore:CreateRegistry",
|
||||
"bedrock-agentcore:ListRegistries"
|
||||
],
|
||||
"Resource": ["arn:aws:bedrock-agentcore:*:YOUR_ACCOUNT_ID:*"]
|
||||
},
|
||||
{
|
||||
"Sid": "AllowGetUpdateDeleteRegistry",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"bedrock-agentcore:GetRegistry",
|
||||
"bedrock-agentcore:UpdateRegistry",
|
||||
"bedrock-agentcore:DeleteRegistry"
|
||||
],
|
||||
"Resource": ["arn:aws:bedrock-agentcore:*:YOUR_ACCOUNT_ID:registry/*"]
|
||||
},
|
||||
{
|
||||
"Sid": "AllowCreatingAndListingRegistryRecords",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"bedrock-agentcore:CreateRegistryRecord",
|
||||
"bedrock-agentcore:ListRegistryRecords"
|
||||
],
|
||||
"Resource": ["arn:aws:bedrock-agentcore:*:YOUR_ACCOUNT_ID:registry/*"]
|
||||
},
|
||||
{
|
||||
"Sid": "AllowRecordLevelOperations",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"bedrock-agentcore:GetRegistryRecord",
|
||||
"bedrock-agentcore:UpdateRegistryRecord",
|
||||
"bedrock-agentcore:DeleteRegistryRecord",
|
||||
"bedrock-agentcore:SubmitRegistryRecordForApproval"
|
||||
],
|
||||
"Resource": ["arn:aws:bedrock-agentcore:*:YOUR_ACCOUNT_ID:registry/*/record/*"]
|
||||
},
|
||||
{
|
||||
"Sid": "AllowApproveRejectDeprecateRecords",
|
||||
"Effect": "Allow",
|
||||
"Action": ["bedrock-agentcore:UpdateRegistryRecordStatus"],
|
||||
"Resource": ["arn:aws:bedrock-agentcore:*:YOUR_ACCOUNT_ID:registry/*/record/*"]
|
||||
},
|
||||
{
|
||||
"Sid": "AdditionalPermissionForRegistryManagedWorkloadIdentity",
|
||||
"Effect": "Allow",
|
||||
"Action": ["bedrock-agentcore:*WorkloadIdentity"],
|
||||
"Resource": ["arn:aws:bedrock-agentcore:*:YOUR_ACCOUNT_ID:workload-identity-directory/default/workload-identity/*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Policy for AWS Agent Registry access (Publisher)
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "AllowListingAllRegistries",
|
||||
"Effect": "Allow",
|
||||
"Action": ["bedrock-agentcore:ListRegistries"],
|
||||
"Resource": ["arn:aws:bedrock-agentcore:*:YOUR_ACCOUNT_ID:*"]
|
||||
},
|
||||
{
|
||||
"Sid": "AllowGetRegistry",
|
||||
"Effect": "Allow",
|
||||
"Action": ["bedrock-agentcore:GetRegistry"],
|
||||
"Resource": ["arn:aws:bedrock-agentcore:*:YOUR_ACCOUNT_ID:registry/*"]
|
||||
},
|
||||
{
|
||||
"Sid": "AllowCreatingAndListingRegistryRecords",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"bedrock-agentcore:CreateRegistryRecord",
|
||||
"bedrock-agentcore:ListRegistryRecords"
|
||||
],
|
||||
"Resource": ["arn:aws:bedrock-agentcore:*:YOUR_ACCOUNT_ID:registry/*"]
|
||||
},
|
||||
{
|
||||
"Sid": "AllowRecordLevelOperations",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"bedrock-agentcore:GetRegistryRecord",
|
||||
"bedrock-agentcore:UpdateRegistryRecord",
|
||||
"bedrock-agentcore:DeleteRegistryRecord",
|
||||
"bedrock-agentcore:SubmitRegistryRecordForApproval"
|
||||
],
|
||||
"Resource": ["arn:aws:bedrock-agentcore:*:YOUR_ACCOUNT_ID:registry/*/record/*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Permissions Required to deploy the required CI/CD stack such as DynamoDB and AWS Lambda etc.
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "STSCallerIdentity",
|
||||
"Effect": "Allow",
|
||||
"Action": ["sts:GetCallerIdentity"],
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Sid": "CloudFormationValidate",
|
||||
"Effect": "Allow",
|
||||
"Action": ["cloudformation:ValidateTemplate"],
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Sid": "CloudFormationStackManagement",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"cloudformation:CreateStack",
|
||||
"cloudformation:UpdateStack",
|
||||
"cloudformation:DeleteStack",
|
||||
"cloudformation:DescribeStacks",
|
||||
"cloudformation:DescribeStackEvents",
|
||||
"cloudformation:DescribeStackResources",
|
||||
"cloudformation:GetTemplate",
|
||||
"cloudformation:ListStackResources",
|
||||
"cloudformation:CreateChangeSet",
|
||||
"cloudformation:DescribeChangeSet",
|
||||
"cloudformation:ExecuteChangeSet",
|
||||
"cloudformation:DeleteChangeSet"
|
||||
],
|
||||
"Resource": "arn:aws:cloudformation:*:YOUR_ACCOUNT_ID:stack/*/*"
|
||||
},
|
||||
{
|
||||
"Sid": "S3StagingBucketManagement",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:CreateBucket",
|
||||
"s3:DeleteBucket",
|
||||
"s3:HeadBucket",
|
||||
"s3:PutBucketPublicAccessBlock",
|
||||
"s3:GetBucketPublicAccessBlock",
|
||||
"s3:ListBucket",
|
||||
"s3:DeleteObject",
|
||||
"s3:PutObject",
|
||||
"s3:GetObject"
|
||||
],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::*",
|
||||
"arn:aws:s3:::*/*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Sid": "LambdaFunctionManagement",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"lambda:CreateFunction",
|
||||
"lambda:UpdateFunctionCode",
|
||||
"lambda:UpdateFunctionConfiguration",
|
||||
"lambda:DeleteFunction",
|
||||
"lambda:GetFunction",
|
||||
"lambda:GetFunctionConfiguration",
|
||||
"lambda:AddPermission",
|
||||
"lambda:RemovePermission"
|
||||
],
|
||||
"Resource": "arn:aws:lambda:*:YOUR_ACCOUNT_ID:function:*"
|
||||
},
|
||||
{
|
||||
"Sid": "LambdaLayerManagement",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"lambda:PublishLayerVersion",
|
||||
"lambda:DeleteLayerVersion",
|
||||
"lambda:GetLayerVersion",
|
||||
"lambda:ListLayerVersions"
|
||||
],
|
||||
"Resource": "arn:aws:lambda:*:YOUR_ACCOUNT_ID:layer:*"
|
||||
},
|
||||
{
|
||||
"Sid": "IAMRoleManagement",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"iam:CreateRole",
|
||||
"iam:DeleteRole",
|
||||
"iam:GetRole",
|
||||
"iam:PassRole",
|
||||
"iam:AttachRolePolicy",
|
||||
"iam:DetachRolePolicy",
|
||||
"iam:PutRolePolicy",
|
||||
"iam:DeleteRolePolicy",
|
||||
"iam:GetRolePolicy",
|
||||
"iam:ListRolePolicies",
|
||||
"iam:ListAttachedRolePolicies"
|
||||
],
|
||||
"Resource": "arn:aws:iam::YOUR_ACCOUNT_ID:role/*"
|
||||
},
|
||||
{
|
||||
"Sid": "KMSCreateKey",
|
||||
"Effect": "Allow",
|
||||
"Action": ["kms:CreateKey"],
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Sid": "KMSManageTaggedKeys",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"kms:DescribeKey",
|
||||
"kms:EnableKeyRotation",
|
||||
"kms:GetKeyPolicy",
|
||||
"kms:PutKeyPolicy",
|
||||
"kms:ScheduleKeyDeletion",
|
||||
"kms:CancelKeyDeletion",
|
||||
"kms:TagResource",
|
||||
"kms:UntagResource"
|
||||
],
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Sid": "DynamoDBTableManagement",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"dynamodb:CreateTable",
|
||||
"dynamodb:DeleteTable",
|
||||
"dynamodb:DescribeTable",
|
||||
"dynamodb:UpdateTable",
|
||||
"dynamodb:DescribeContinuousBackups",
|
||||
"dynamodb:DescribeTimeToLive"
|
||||
],
|
||||
"Resource": "arn:aws:dynamodb:*:YOUR_ACCOUNT_ID:table/*"
|
||||
},
|
||||
{
|
||||
"Sid": "EventBridgeManagement",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"events:PutRule",
|
||||
"events:DeleteRule",
|
||||
"events:DescribeRule",
|
||||
"events:PutTargets",
|
||||
"events:RemoveTargets",
|
||||
"events:ListTargetsByRule"
|
||||
],
|
||||
"Resource": "arn:aws:events:*:YOUR_ACCOUNT_ID:rule/*"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ As an Administrator, you can use the **AWS CLI** commands included in the notifi
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- IAM credentials with appropriate permissions (see [`IAM_PERMISSIONS.md`](../../IAM_PERMISSIONS.md)). This tutorial requires both admin and publisher permissions. In addition, the following permissions are required to deploy and destroy the CI/CD stack:
|
||||
- IAM credentials with appropriate permissions (see [`IAM_PERMISSIONS.md`](./IAM_PERMISSIONS.md)). In addition to Agent Registry related operations, the following permissions are being used:
|
||||
|
||||
| Service | Permissions |
|
||||
|:--------|:------------|
|
||||
|
||||
+19
-61
@@ -59,17 +59,19 @@
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Prerequisites\n",
|
||||
"- IAM credentials with appropriate permissions (see [`IAM_PERMISSIONS.md`](../../IAM_PERMISSIONS.md)). This tutorial requires both admin and publisher permissions. In addition, the following permissions are required to deploy and destroy the CI/CD stack:\n",
|
||||
"- IAM credentials with appropriate permissions (see [`IAM_PERMISSIONS.md`](./IAM_PERMISSIONS.md)). In addition to Agent Registry related operations, the following permissions are being used:\n",
|
||||
"\n",
|
||||
" | Service | Permissions |\n",
|
||||
" |:--------|:------------|\n",
|
||||
" | **Amazon S3** | `CreateBucket`, `HeadBucket`, `PutPublicAccessBlock`, `DeleteBucket`, `ListBucket`, `PutObject`, `GetObject`, `DeleteObject` |\n",
|
||||
" | **AWS CloudFormation** | `CreateStack`, `UpdateStack`, `DeleteStack`, `DescribeStacks`, `CreateChangeSet`, `ExecuteChangeSet`, `DescribeChangeSet`, `DeleteChangeSet` |\n",
|
||||
" | **AWS Lambda** | `CreateFunction`, `UpdateFunctionCode`, `UpdateFunctionConfiguration`, `GetFunction`, `DeleteFunction`, `PublishLayerVersion`, `DeleteLayerVersion`, `AddPermission`, `RemovePermission` |\n",
|
||||
" | **AWS IAM** | `CreateRole`, `GetRole`, `DeleteRole`, `PassRole`, `AttachRolePolicy`, `DetachRolePolicy`, `PutRolePolicy`, `DeleteRolePolicy` |\n",
|
||||
" | **AWS EventBridge** | `PutRule`, `DescribeRule`, `DeleteRule`, `PutTargets`, `RemoveTargets` |\n",
|
||||
" | **Amazon DynamoDB** | `CreateTable`, `DeleteTable`, `DescribeTable` |\n",
|
||||
" | **AWS CloudWatch Logs** | `CreateLogGroup`, `CreateLogStream`, `PutLogEvents`, `DeleteLogGroup` |- Python 3.9+ with `boto3` installed\n",
|
||||
"| Service | Permissions |\n",
|
||||
"|:--------|:------------|\n",
|
||||
"| **Amazon S3** | `CreateBucket`, `HeadBucket`, `PutPublicAccessBlock`, `DeleteBucket`, `ListBucket`, `PutObject`, `GetObject`, `DeleteObject` |\n",
|
||||
"| **AWS CloudFormation** | `CreateStack`, `UpdateStack`, `DeleteStack`, `DescribeStacks`, `CreateChangeSet`, `ExecuteChangeSet`, `DescribeChangeSet`, `DeleteChangeSet` |\n",
|
||||
"| **AWS Lambda** | `CreateFunction`, `UpdateFunctionCode`, `UpdateFunctionConfiguration`, `GetFunction`, `DeleteFunction`, `PublishLayerVersion`, `DeleteLayerVersion`, `AddPermission`, `RemovePermission` |\n",
|
||||
"| **AWS IAM** | `CreateRole`, `GetRole`, `DeleteRole`, `PassRole`, `AttachRolePolicy`, `DetachRolePolicy`, `PutRolePolicy`, `DeleteRolePolicy` |\n",
|
||||
"| **AWS EventBridge** | `PutRule`, `DescribeRule`, `DeleteRule`, `PutTargets`, `RemoveTargets` |\n",
|
||||
"| **Amazon DynamoDB** | `CreateTable`, `DeleteTable`, `DescribeTable` |\n",
|
||||
"| **AWS CloudWatch Logs** | `CreateLogGroup`, `CreateLogStream`, `PutLogEvents`, `DeleteLogGroup` |\n",
|
||||
"\n",
|
||||
"- Python 3.9+ with `boto3` installed\n",
|
||||
"\n",
|
||||
"- [uv](https://docs.astral.sh/uv/getting-started/installation/) package manager (for installing python dependencies)\n",
|
||||
"- A Slack workspace with an [incoming webhook](https://docs.slack.dev/messaging/sending-messages-using-incoming-webhooks/) configured. Note down the webhook URL and channel name.\n",
|
||||
@@ -98,6 +100,8 @@
|
||||
"import subprocess\n",
|
||||
"import botocore.exceptions\n",
|
||||
"import time\n",
|
||||
"import os\n",
|
||||
"from utils import wait_for_registry_ready, wait_for_record_draft\n",
|
||||
"\n",
|
||||
"print(f\"Boto3 version: {boto3.__version__}\")\n",
|
||||
"\n",
|
||||
@@ -159,19 +163,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#wait for registry to get to Ready status (takes around ~2 minutes)\n",
|
||||
"registryStatus = 'Checking'\n",
|
||||
"while registryStatus.lower() != 'ready':\n",
|
||||
" getRegistry = cp_client.get_registry(registryId=REGISTRY_ID)\n",
|
||||
"\n",
|
||||
" registryStatus = getRegistry['status']\n",
|
||||
"\n",
|
||||
" if registryStatus.lower() == 'ready':\n",
|
||||
" print(\"Verified: Registry is in Ready state\")\n",
|
||||
" else:\n",
|
||||
" print(f\"Registry is in {registryStatus} state. Waiting for it to be in Ready state\")\n",
|
||||
"\n",
|
||||
" time.sleep(10)"
|
||||
"# wait for registry to get to Ready status (takes around ~2 minutes)\n",
|
||||
"wait_for_registry_ready(cp_client, REGISTRY_ID)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -307,19 +300,8 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Wait for the record to be in Draft state\n",
|
||||
"recordStatus = 'Checking'\n",
|
||||
"while recordStatus.lower() != 'draft':\n",
|
||||
" getRegistryRecord = cp_client.get_registry_record(registryId=REGISTRY_ID, recordId=A2A_RECORD_ID)\n",
|
||||
" recordStatus = getRegistryRecord['status']\n",
|
||||
" metadata = getRegistryRecord.get(\"ResponseMetadata\", {})\n",
|
||||
"wait_for_record_draft(cp_client, REGISTRY_ID, A2A_RECORD_ID)\n",
|
||||
"\n",
|
||||
" if recordStatus.lower() == 'draft':\n",
|
||||
" print(\"Verified: Registry record is in Draft state. Ready to be submitted for Approval\")\n",
|
||||
" print(f\"Metadata | RequestId: {metadata['HTTPHeaders']['x-amzn-requestid']}, Timestamp: {metadata['HTTPHeaders']['date']}\")\n",
|
||||
" else:\n",
|
||||
" print(f\"Registry record is in {recordStatus} state. Waiting for it to be in Draft state\")\n",
|
||||
"\n",
|
||||
" time.sleep(2)\n",
|
||||
"submit_resp = cp_client.submit_registry_record_for_approval(registryId=REGISTRY_ID, recordId=A2A_RECORD_ID)\n",
|
||||
"print(\"Record submitted for approval\")\n",
|
||||
"\n",
|
||||
@@ -381,19 +363,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Wait for the record to be in Draft state\n",
|
||||
"recordStatus = 'Checking'\n",
|
||||
"while recordStatus.lower() != 'draft':\n",
|
||||
" getRegistryRecord = cp_client.get_registry_record(registryId=REGISTRY_ID, recordId=MCP_RECORD_ID)\n",
|
||||
" recordStatus = getRegistryRecord['status']\n",
|
||||
" metadata = getRegistryRecord.get(\"ResponseMetadata\", {})\n",
|
||||
"\n",
|
||||
" if recordStatus.lower() == 'draft':\n",
|
||||
" print(\"Verified: Registry record is in Draft state. Ready to be submitted for Approval\")\n",
|
||||
" print(f\"RequestId: {metadata['HTTPHeaders']['x-amzn-requestid']}, Timestamp: {metadata['HTTPHeaders']['date']}\")\n",
|
||||
" else:\n",
|
||||
" print(f\"Registry record is in {recordStatus} state. Waiting for it to be in Draft state\")\n",
|
||||
"\n",
|
||||
" time.sleep(2)\n",
|
||||
"wait_for_record_draft(cp_client, REGISTRY_ID, MCP_RECORD_ID)\n",
|
||||
"\n",
|
||||
"#Submit for approval\n",
|
||||
"submit_resp = cp_client.submit_registry_record_for_approval(registryId=REGISTRY_ID, recordId=MCP_RECORD_ID)\n",
|
||||
@@ -448,19 +418,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Wait for the record to be in Draft state\n",
|
||||
"recordStatus = 'Checking'\n",
|
||||
"while recordStatus.lower() != 'draft':\n",
|
||||
" getRegistryRecord = cp_client.get_registry_record(registryId=REGISTRY_ID, recordId=CUSTOM_RECORD_ID)\n",
|
||||
" recordStatus = getRegistryRecord['status']\n",
|
||||
" metadata = getRegistryRecord.get(\"ResponseMetadata\", {})\n",
|
||||
"\n",
|
||||
" if recordStatus.lower() == 'draft':\n",
|
||||
" print(\"Verified: Registry record is in Draft state. Ready to be submitted for Approval\")\n",
|
||||
" print(f\"RequestId: {metadata['HTTPHeaders']['x-amzn-requestid']}, Timestamp: {metadata['HTTPHeaders']['date']}\")\n",
|
||||
" else:\n",
|
||||
" print(f\"Registry record is in {recordStatus} state. Waiting for it to be in Draft state\")\n",
|
||||
"\n",
|
||||
" time.sleep(2)\n",
|
||||
"wait_for_record_draft(cp_client, REGISTRY_ID, CUSTOM_RECORD_ID)\n",
|
||||
"\n",
|
||||
"#Submit for approval\n",
|
||||
"submit_resp = cp_client.submit_registry_record_for_approval(registryId=REGISTRY_ID, recordId=CUSTOM_RECORD_ID)\n",
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
"""Utility helpers for Agent Registry polling operations."""
|
||||
|
||||
import time
|
||||
|
||||
|
||||
def wait_for_registry_ready(cp_client, registry_id, poll_interval=10):
|
||||
"""Poll until the registry reaches READY status."""
|
||||
status = "Checking"
|
||||
while status.lower() != "ready":
|
||||
resp = cp_client.get_registry(registryId=registry_id)
|
||||
status = resp["status"]
|
||||
if status.lower() == "ready":
|
||||
print("Verified: Registry is in Ready state")
|
||||
else:
|
||||
print(f"Registry is in {status} state. Waiting for it to be in Ready state")
|
||||
time.sleep(poll_interval)
|
||||
|
||||
|
||||
def wait_for_record_draft(cp_client, registry_id, record_id, poll_interval=2):
|
||||
"""Poll until the registry record reaches DRAFT status."""
|
||||
status = "Checking"
|
||||
while status.lower() != "draft":
|
||||
resp = cp_client.get_registry_record(registryId=registry_id, recordId=record_id)
|
||||
status = resp["status"]
|
||||
metadata = resp.get("ResponseMetadata", {})
|
||||
if status.lower() == "draft":
|
||||
print(
|
||||
"Verified: Registry record is in Draft state. "
|
||||
"Ready to be submitted for Approval"
|
||||
)
|
||||
headers = metadata.get("HTTPHeaders", {})
|
||||
request_id = headers.get("x-amzn-requestid", "")
|
||||
date = headers.get("date", "")
|
||||
print(f"RequestId: {request_id}, Timestamp: {date}")
|
||||
else:
|
||||
print(
|
||||
f"Registry record is in {status} state. "
|
||||
"Waiting for it to be in Draft state"
|
||||
)
|
||||
time.sleep(poll_interval)
|
||||
Reference in New Issue
Block a user