diff --git a/api/PclusterApiHandler.py b/api/PclusterApiHandler.py
index c29714ab2..2e3974878 100644
--- a/api/PclusterApiHandler.py
+++ b/api/PclusterApiHandler.py
@@ -33,12 +33,13 @@
AUTH_PATH = os.getenv("AUTH_PATH")
API_BASE_URL = os.getenv("API_BASE_URL")
API_VERSION = os.getenv("API_VERSION", "3.1.0")
+DEFAULT_API_VERSION = '3.12.0'
API_USER_ROLE = os.getenv("API_USER_ROLE")
OIDC_PROVIDER = os.getenv("OIDC_PROVIDER")
CLIENT_ID = os.getenv("CLIENT_ID")
CLIENT_SECRET = os.getenv("CLIENT_SECRET")
SECRET_ID = os.getenv("SECRET_ID")
-SITE_URL = os.getenv("SITE_URL", API_BASE_URL)
+SITE_URL = os.getenv("SITE_URL")
SCOPES_LIST = os.getenv("SCOPES_LIST")
REGION = os.getenv("AWS_DEFAULT_REGION")
TOKEN_URL = os.getenv("TOKEN_URL", f"{AUTH_PATH}/oauth2/token")
@@ -62,6 +63,13 @@
if not JWKS_URL:
JWKS_URL = os.getenv("JWKS_URL",
f"https://cognito-idp.{REGION}.amazonaws.com/{USER_POOL_ID}/" ".well-known/jwks.json")
+API_BASE_URL_MAPPING = {}
+
+# for url in API_BASE_URL.split(","):
+# if url:
+# pair=url.split("=")
+# API_BASE_URL_MAPPING[pair[0]] = pair[1]
+
def jwt_decode(token, audience=None, access_token=None):
@@ -165,7 +173,7 @@ def authenticate(groups):
if (not groups):
return abort(403)
-
+
jwt_roles = set(decoded.get(USER_ROLES_CLAIM, []))
groups_granted = groups.intersection(jwt_roles)
if len(groups_granted) == 0:
@@ -191,7 +199,7 @@ def get_scopes_list():
def get_redirect_uri():
return f"{SITE_URL}/login"
-
+
# Local Endpoints
@@ -233,9 +241,9 @@ def ec2_action():
def get_cluster_config_text(cluster_name, region=None):
url = f"/v3/clusters/{cluster_name}"
if region:
- info_resp = sigv4_request("GET", API_BASE_URL, url, params={"region": region})
+ info_resp = sigv4_request("GET", API_BASE_URL_MAPPING['3.12.0'], url, params={"region": region})
else:
- info_resp = sigv4_request("GET", API_BASE_URL, url)
+ info_resp = sigv4_request("GET", API_BASE_URL_MAPPING['3.12.0'], url)
if info_resp.status_code != 200:
abort(info_resp.status_code)
@@ -365,7 +373,7 @@ def sacct():
user,
f"sacct {sacct_args} --json "
+ "| jq -c .jobs[0:120]\\|\\map\\({name,user,partition,state,job_id,exit_code\\}\\)",
- )
+ )
if type(accounting) is tuple:
return accounting
else:
@@ -484,7 +492,7 @@ def get_dcv_session():
def get_custom_image_config():
- image_info = sigv4_request("GET", API_BASE_URL, f"/v3/images/custom/{request.args.get('image_id')}").json()
+ image_info = sigv4_request("GET", API_BASE_URL_MAPPING['3.12.0'], f"/v3/images/custom/{request.args.get('image_id')}").json()
configuration = requests.get(image_info["imageConfiguration"]["url"])
return configuration.text
@@ -596,9 +604,9 @@ def _get_identity_from_token(decoded, claims):
identity["username"] = decoded["username"]
for claim in claims:
- if claim in decoded:
- identity["attributes"][claim] = decoded[claim]
-
+ if claim in decoded:
+ identity["attributes"][claim] = decoded[claim]
+
return identity
def get_identity():
@@ -735,6 +743,10 @@ def _get_params(_request):
params.pop("path")
return params
+def _get_version(v):
+
+ return DEFAULT_API_VERSION
+
pc = Blueprint('pc', __name__)
@@ -742,7 +754,7 @@ def _get_params(_request):
@authenticated({'admin'})
@validated(params=PCProxyArgs)
def pc_proxy_get():
- response = sigv4_request(request.method, API_BASE_URL, request.args.get("path"), _get_params(request))
+ response = sigv4_request(request.method, API_BASE_URL_MAPPING[_get_version('3.12.0')], request.args.get("path"), _get_params(request))
return response.json(), response.status_code
@pc.route('/', methods=['POST','PUT','PATCH','DELETE'], strict_slashes=False)
@@ -756,5 +768,5 @@ def pc_proxy():
except:
pass
- response = sigv4_request(request.method, API_BASE_URL, request.args.get("path"), _get_params(request), body=body)
+ response = sigv4_request(request.method, API_BASE_URL_MAPPING[_get_version('3.12.0')], request.args.get("path"), _get_params(request), body=body)
return response.json(), response.status_code
diff --git a/frontend/locales/en/strings.json b/frontend/locales/en/strings.json
index 855dd9e54..d40bdd7e0 100644
--- a/frontend/locales/en/strings.json
+++ b/frontend/locales/en/strings.json
@@ -527,6 +527,12 @@
"alreadyExists": "Cluster with name {{clusterName}} already exists. Choose a unique name.",
"doesntMatchRegex": "Cluster name '{{clusterName}}' doesn't match the the required format. Enter a name that starts with an alphabetical character and has up to 60 characters. If Slurm accounting is configured, the name can have up to 40 characters. Valid characters: A-Z, a-z, 0-9, and - (hyphen)"
},
+ "version": {
+ "label": "Version",
+ "description": "The ParallelCluster version that will be used for the cluster.",
+ "placeholder": "Enter your cluster version",
+ "cannotBeBlank": "Cluster version must not be blank."
+ },
"region": {
"label": "Region",
"description": "The AWS Region for the cluster.",
diff --git a/frontend/src/__tests__/CreateCluster.test.ts b/frontend/src/__tests__/CreateCluster.test.ts
index 34f5ef6a8..ef73b2bcf 100644
--- a/frontend/src/__tests__/CreateCluster.test.ts
+++ b/frontend/src/__tests__/CreateCluster.test.ts
@@ -8,6 +8,7 @@ const mockRequest = executeRequest as jest.Mock
describe('given a CreateCluster command and a cluster configuration', () => {
const clusterName = 'any-name'
+ const clusterVersion = 'some-version'
const clusterConfiguration = 'Imds:\n ImdsSupport: v2.0'
const mockRegion = 'some-region'
const mockSelectedRegion = 'some-region'
@@ -37,11 +38,12 @@ describe('given a CreateCluster command and a cluster configuration', () => {
clusterConfiguration,
mockRegion,
mockSelectedRegion,
+ clusterVersion,
)
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith(
'post',
- 'api?path=/v3/clusters®ion=some-region',
+ 'api?path=/v3/clusters®ion=some-region&version=some-version',
expectedBody,
expect.any(Object),
expect.any(Object),
@@ -55,6 +57,7 @@ describe('given a CreateCluster command and a cluster configuration', () => {
clusterConfiguration,
mockRegion,
mockSelectedRegion,
+ clusterVersion,
false,
mockSuccessCallback,
)
@@ -71,12 +74,13 @@ describe('given a CreateCluster command and a cluster configuration', () => {
clusterConfiguration,
mockRegion,
mockSelectedRegion,
+ clusterVersion,
mockDryRun,
)
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith(
'post',
- 'api?path=/v3/clusters&dryrun=true®ion=some-region',
+ 'api?path=/v3/clusters&dryrun=true®ion=some-region&version=some-version',
expect.any(Object),
expect.any(Object),
expect.any(Object),
@@ -106,6 +110,7 @@ describe('given a CreateCluster command and a cluster configuration', () => {
clusterConfiguration,
mockRegion,
mockSelectedRegion,
+ clusterVersion,
false,
undefined,
mockErrorCallback,
@@ -128,6 +133,7 @@ describe('given a CreateCluster command and a cluster configuration', () => {
'Imds:\n ImdsSupport: v2.0',
mockRegion,
mockSelectedRegion,
+ clusterVersion,
)
expect(mockRequest).toHaveBeenCalledWith(
@@ -154,6 +160,7 @@ describe('given a CreateCluster command and a cluster configuration', () => {
'Imds:\n ImdsSupport: v2.0\nTags:\n - Key: foo\n Value: bar',
mockRegion,
mockSelectedRegion,
+ clusterVersion,
)
expect(mockRequest).toHaveBeenCalledWith(
@@ -180,6 +187,7 @@ describe('given a CreateCluster command and a cluster configuration', () => {
"Imds:\n ImdsSupport: v2.0\nTags:\n - Key: parallelcluster-ui\n Value: 'true'",
mockRegion,
mockSelectedRegion,
+ clusterVersion,
)
expect(mockRequest).not.toHaveBeenCalledWith(
diff --git a/frontend/src/model.tsx b/frontend/src/model.tsx
index b7959d5cf..eff4d07cc 100644
--- a/frontend/src/model.tsx
+++ b/frontend/src/model.tsx
@@ -103,6 +103,7 @@ function CreateCluster(
clusterConfig: string,
region: string,
selectedRegion: string,
+ version: string,
dryrun = false,
successCallback?: Callback,
errorCallback?: Callback,
@@ -110,6 +111,7 @@ function CreateCluster(
var url = 'api?path=/v3/clusters'
url += dryrun ? '&dryrun=true' : ''
url += region ? `®ion=${region}` : ''
+ url += version ? `&version=${version}` : ''
var body = {
clusterName: clusterName,
clusterConfiguration: mapAndApplyTags(clusterConfig),
@@ -159,12 +161,14 @@ function UpdateCluster(
clusterConfig: any,
dryrun = false,
forceUpdate: any,
+ version: any,
successCallback?: Callback,
errorCallback?: Callback,
) {
var url = `api?path=/v3/clusters/${clusterName}`
url += dryrun ? '&dryrun=true' : ''
url += forceUpdate ? '&forceUpdate=true' : ''
+ url += version ? `&version=${version}` : ''
var body = {clusterConfiguration: clusterConfig}
request('put', url, body)
.then((response: any) => {
diff --git a/frontend/src/old-pages/Clusters/Actions.tsx b/frontend/src/old-pages/Clusters/Actions.tsx
index 66765a1f1..45a33a23d 100644
--- a/frontend/src/old-pages/Clusters/Actions.tsx
+++ b/frontend/src/old-pages/Clusters/Actions.tsx
@@ -74,8 +74,8 @@ export default function Actions() {
clusterStatus === ClusterStatus.CreateInProgress ||
clusterStatus === ClusterStatus.DeleteInProgress ||
clusterStatus === ClusterStatus.UpdateInProgress ||
- clusterStatus === ClusterStatus.CreateFailed ||
- clusterVersion !== apiVersion
+ clusterStatus === ClusterStatus.CreateFailed
+ // !apiVersion.split(",").includes(clusterVersion)
const isStartFleetDisabled = fleetStatus !== 'STOPPED'
const isStopFleetDisabled = fleetStatus !== 'RUNNING'
const isDeleteDisabled =
diff --git a/frontend/src/old-pages/Clusters/Details.tsx b/frontend/src/old-pages/Clusters/Details.tsx
index a94faafe8..49b226648 100644
--- a/frontend/src/old-pages/Clusters/Details.tsx
+++ b/frontend/src/old-pages/Clusters/Details.tsx
@@ -56,9 +56,9 @@ export default function ClusterTabs() {
return cluster ? (
<>
- {cluster.version !== apiVersion ? (
- {t('cluster.editAlert')}
- ) : null}
+ {/*{!apiVersion.split(",").includes(cluster.version) ? (*/}
+ {/* {t('cluster.editAlert')}*/}
+ {/*) : null}*/}
+ {/**/}
=
+ useCallback(({detail}) => {
+ setState(clusterVersionPath, detail.value)
+ }, [])
+
+ return (
+
+
+
+ )
+}
diff --git a/frontend/src/old-pages/Configure/Create.tsx b/frontend/src/old-pages/Configure/Create.tsx
index 032fb5831..8364a37f9 100644
--- a/frontend/src/old-pages/Configure/Create.tsx
+++ b/frontend/src/old-pages/Configure/Create.tsx
@@ -96,6 +96,7 @@ function handleCreate(
const dryRun = false
const region = getState(['app', 'wizard', 'config', 'Region'])
const selectedRegion = getState(['app', 'selectedRegion'])
+ const version = getState(['app', 'wizard', 'version'])
setClusterLoadingMsg(clusterName, editing, dryRun)
setState(wizardSubmissionLoading, true)
@@ -120,6 +121,7 @@ function handleCreate(
UpdateCluster(
clusterName,
clusterConfig,
+ version,
dryRun,
forceUpdate,
successHandler,
@@ -131,6 +133,7 @@ function handleCreate(
clusterConfig,
region,
selectedRegion,
+ version,
dryRun,
successHandler,
errHandler,
@@ -145,6 +148,7 @@ function handleDryRun() {
const clusterConfig = getState(configPath) || ''
const region = getState(['app', 'wizard', 'config', 'Region'])
const selectedRegion = getState(['app', 'selectedRegion'])
+ const version = getState(['app', 'wizard', 'version'])
const dryRun = true
setClusterLoadingMsg(clusterName, editing, dryRun)
setState(wizardSubmissionLoading, true)
@@ -163,6 +167,7 @@ function handleDryRun() {
UpdateCluster(
clusterName,
clusterConfig,
+ version,
dryRun,
forceUpdate,
successHandler,
@@ -174,6 +179,7 @@ function handleDryRun() {
clusterConfig,
region,
selectedRegion,
+ version,
dryRun,
successHandler,
errHandler,
diff --git a/infrastructure/parallelcluster-ui.yaml b/infrastructure/parallelcluster-ui.yaml
index a49bf262d..327d2ea7a 100644
--- a/infrastructure/parallelcluster-ui.yaml
+++ b/infrastructure/parallelcluster-ui.yaml
@@ -1,3 +1,4 @@
+Transform: 'AWS::LanguageExtensions'
Parameters:
AdminUserEmail:
Description: Email address of administrative user to setup by default (only with new Cognito instances).
@@ -161,17 +162,6 @@ Conditions:
- !Not [!Equals [!Ref SNSRole, ""]]
UseNewCognito:
!Not [ Condition: UseExistingCognito]
- UseNonDockerizedPCAPI:
- !Not [ Condition: UseDockerizedPCAPI]
- UseDockerizedPCAPI: !And
- - !Equals ['3', !Select [ 0, !Split ['.', !Ref Version] ] ] # Check PC version major is 3 and PC version minor is 0-5
- - !Or
- - !Equals ['0', !Select [ 1, !Split ['.', !Ref Version] ] ]
- - !Equals ['1', !Select [ 1, !Split ['.', !Ref Version] ] ]
- - !Equals ['2', !Select [ 1, !Split ['.', !Ref Version] ] ]
- - !Equals ['3', !Select [ 1, !Split ['.', !Ref Version] ] ]
- - !Equals ['4', !Select [ 1, !Split ['.', !Ref Version] ] ]
- - !Equals ['5', !Select [ 1, !Split ['.', !Ref Version] ] ]
InGovCloud: !Equals ['us-gov-west-1', !Ref "AWS::Region"]
UsePermissionBoundary: !Not [!Equals [!Ref PermissionsBoundaryPolicy, '']]
UsePermissionBoundaryPCAPI: !Not [!Equals [!Ref PermissionsBoundaryPolicyPCAPI, '']]
@@ -208,36 +198,178 @@ Resources:
TimeoutInMinutes: 10
- ParallelClusterApi:
- Type: AWS::CloudFormation::Stack
+ Fn::ForEach::ParallelClusterApi:
+ - ApiVersion
+ - !Split [",", !Ref Version]
+ - ParallelClusterApi&{ApiVersion}:
+ Type: AWS::CloudFormation::Stack
+ Properties:
+ Parameters:
+ PermissionsBoundaryPolicy: !If [ UsePermissionBoundaryPCAPI, !Ref PermissionsBoundaryPolicyPCAPI, !Ref AWS::NoValue ]
+ IAMRoleAndPolicyPrefix: !If [ UseIAMRoleAndPolicyPrefix, !Ref IAMRoleAndPolicyPrefix, !Ref AWS::NoValue ]
+ ParallelClusterFunctionAdditionalPolicies: !If [ UseAdditionalPoliciesPCAPI, !Ref AdditionalPoliciesPCAPI, !Ref AWS::NoValue ]
+ ApiDefinitionS3Uri: !Sub s3://${AWS::Region}-aws-parallelcluster/parallelcluster/${ApiVersion}/api/ParallelCluster.openapi.yaml
+ CreateApiUserRole: False
+ EnableIamAdminAccess: True
+ VpcEndpointId: !If [ IsPrivate, !Ref VpcEndpointId, !Ref AWS::NoValue ]
+ TemplateURL: !Sub https://${AWS::Region}-aws-parallelcluster.s3.${AWS::Region}.amazonaws.com/parallelcluster/${ApiVersion}/api/parallelcluster-api.yaml
+ TimeoutInMinutes: 30
+ Tags:
+ - Key: 'parallelcluster:api-id'
+ Value: !Ref ApiGatewayRestApi
+
+# ParallelClusterApi:
+# Type: AWS::CloudFormation::Stack
+# Properties:
+# Parameters:
+# PermissionsBoundaryPolicy: !If [ UsePermissionBoundaryPCAPI, !Ref PermissionsBoundaryPolicyPCAPI, !Ref AWS::NoValue ]
+# IAMRoleAndPolicyPrefix: !If [ UseIAMRoleAndPolicyPrefix, !Ref IAMRoleAndPolicyPrefix, !Ref AWS::NoValue ]
+# ParallelClusterFunctionAdditionalPolicies: !If [ UseAdditionalPoliciesPCAPI, !Ref AdditionalPoliciesPCAPI, !Ref AWS::NoValue ]
+# ApiDefinitionS3Uri: !Sub s3://${AWS::Region}-aws-parallelcluster/parallelcluster/${Version}/api/ParallelCluster.openapi.yaml
+# CreateApiUserRole: False
+# EnableIamAdminAccess: True
+# VpcEndpointId: !If [ IsPrivate, !Ref VpcEndpointId, !Ref AWS::NoValue ]
+# ImageBuilderSubnetId: !If
+# - UseNonDockerizedPCAPI
+# - !Ref AWS::NoValue
+# - Fn::If:
+# - NonDefaultVpc
+# - !Ref ImageBuilderSubnetId
+# - !Ref AWS::NoValue
+# ImageBuilderVpcId: !If
+# - UseNonDockerizedPCAPI
+# - !Ref AWS::NoValue
+# - Fn::If:
+# - NonDefaultVpc
+# - !Ref ImageBuilderVpcId
+# - !Ref AWS::NoValue
+# TemplateURL: !Sub https://${AWS::Region}-aws-parallelcluster.s3.${AWS::Region}.amazonaws.com/parallelcluster/${Version}/api/parallelcluster-api.yaml
+# TimeoutInMinutes: 30
+
+ ApiVersionMap:
+ Type: Custom::ApiVersionMap
Properties:
- Parameters:
- PermissionsBoundaryPolicy: !If [ UsePermissionBoundaryPCAPI, !Ref PermissionsBoundaryPolicyPCAPI, !Ref AWS::NoValue ]
- IAMRoleAndPolicyPrefix: !If [ UseIAMRoleAndPolicyPrefix, !Ref IAMRoleAndPolicyPrefix, !Ref AWS::NoValue ]
- ParallelClusterFunctionAdditionalPolicies: !If [ UseAdditionalPoliciesPCAPI, !Ref AdditionalPoliciesPCAPI, !Ref AWS::NoValue ]
- ApiDefinitionS3Uri: !Sub s3://${AWS::Region}-aws-parallelcluster/parallelcluster/${Version}/api/ParallelCluster.openapi.yaml
- CreateApiUserRole: False
- EnableIamAdminAccess: True
- VpcEndpointId: !If [ IsPrivate, !Ref VpcEndpointId, !Ref AWS::NoValue ]
- ImageBuilderSubnetId: !If
- - UseNonDockerizedPCAPI
- - !Ref AWS::NoValue
- - Fn::If:
- - NonDefaultVpc
- - !Ref ImageBuilderSubnetId
- - !Ref AWS::NoValue
- ImageBuilderVpcId: !If
- - UseNonDockerizedPCAPI
- - !Ref AWS::NoValue
- - Fn::If:
- - NonDefaultVpc
- - !Ref ImageBuilderVpcId
- - !Ref AWS::NoValue
- TemplateURL: !Sub https://${AWS::Region}-aws-parallelcluster.s3.${AWS::Region}.amazonaws.com/parallelcluster/${Version}/api/parallelcluster-api.yaml
- TimeoutInMinutes: 30
+ ServiceToken: !GetAtt ApiVersionMapFunction.Arn
+ Version: !Ref Version
+ ApiGatewayRestApiId: !Ref ApiGatewayRestApi
+
+ ApiVersionMapFunction:
+ Type: AWS::Lambda::Function
+ Properties:
+ Handler: index.handler
+ Runtime: python3.12
+ TracingConfig:
+ Mode: Active
+ Role: !GetAtt ApiVersionMapFunctionRole.Arn
+ Code:
+ ZipFile: |
+ import boto3
+ import cfnresponse
+ import os
+ import re
+ import time
+
+ def handler(event, context):
+ response_data = {}
+ response_status = cfnresponse.SUCCESS
+ reason = None
+ try:
+
+ if event['RequestType'] in ['Create', 'Update']:
+ response_data["Message"] = "Resource creation successful!"
+ cfn = boto3.client('cloudformation')
+ result = ""
+
+ api_id = event['ResourceProperties'].get('ApiGatewayRestApiId')
+ print(f"ApiGatewayRestApiId: {api_id}")
+ versions = event['ResourceProperties'].get('Version').split(",")
+ print(f"Versions: {versions}")
+
+ paginator = cfn.get_paginator('list_stacks')
+ for page in paginator.paginate(
+ StackStatusFilter=['CREATE_COMPLETE', 'UPDATE_COMPLETE', 'CREATE_IN_PROGRESS']
+ ):
+ for stack in page['StackSummaries']:
+ try:
+ # Check if stack name matches the pattern
+ print(f"Checking stack {stack['StackName']}")
+
+ for version in versions:
+ clean_version = version.replace('.','')
+ pattern = f'.*-ParallelClusterApi{clean_version}-[^-]*$'
+ stack_pattern = re.compile(pattern)
+ match = stack_pattern.match(stack['StackName'])
+ if not match:
+ continue
+
+ # Get stack details including tags
+ stack_response = cfn.describe_stacks(
+ StackName=stack['StackName']
+ )
+
+ stack_tags = stack_response['Stacks'][0].get('Tags', [])
+ print(f"Match: {match}, tags: {stack_tags}")
+ # Check if stack has the specific tag and value
+ for tag in stack_tags:
+ if (tag.get('Key') == 'parallelcluster:api-id' and
+ tag.get('Value') == api_id):
+ # Get stack outputs
+ waiter = cfn.get_waiter('stack_create_complete')
+ waiter.wait(StackName=stack['StackName'])
+ stack_response = cfn.describe_stacks(
+ StackName=stack['StackName']
+ )
+ print(f"Found stack {stack['StackName']} with outputs: {stack_response['Stacks'][0]['Outputs']}")
+
+ for output in stack_response['Stacks'][0]['Outputs']:
+ if output['OutputKey'] == 'ParallelClusterApiInvokeUrl':
+ # Construct the result string
+ result = f"{result}{version}={output['OutputValue']},"
+ print(f"Version={version}, ApiURL={output['OutputValue']}")
+ break
+
+ except Exception as e:
+ print(f"Error processing stack {stack['StackName']}: {str(e)}")
+ continue
+ print(f"Result: {result}")
+
+ response_data = {"ApiVersionMapping": result}
+ cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data, result)
+
+ except Exception as e:
+ response_status = cfnresponse.FAILED
+ reason = "Failed {}: {}".format(event["RequestType"], e)
+ cfnresponse.send(event, context, response_status, response_data, reason)
+
+ Timeout: 300
+ MemorySize: 128
+
+ ApiVersionMapFunctionRole:
+ Type: AWS::IAM::Role
+ Properties:
+ AssumeRolePolicyDocument:
+ Version: '2012-10-17'
+ Statement:
+ - Effect: Allow
+ Principal:
+ Service: lambda.amazonaws.com
+ Action: sts:AssumeRole
+ ManagedPolicyArns:
+ - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
+ Policies:
+ - PolicyName: CloudFormationAccess
+ PolicyDocument:
+ Version: '2012-10-17'
+ Statement:
+ - Effect: Allow
+ Action:
+ - cloudformation:ListStacks
+ - cloudformation:DescribeStacks
+ Resource: '*'
ParallelClusterUIFun:
Type: AWS::Lambda::Function
+ DependsOn: ApiVersionMap
Properties:
Role: !GetAtt ParallelClusterUIUserRole.Arn
PackageType: Image
@@ -256,7 +388,7 @@ Resources:
- !Ref AWS::NoValue
Environment:
Variables:
- API_BASE_URL: !GetAtt [ ParallelClusterApi, Outputs.ParallelClusterApiInvokeUrl ]
+ API_BASE_URL: !GetAtt ApiVersionMap.ApiVersionMapping
API_VERSION: !Ref Version
SITE_URL: !If
- UseCustomDomain
@@ -580,7 +712,7 @@ Resources:
PermissionsBoundary: !If [UsePermissionBoundary, !Ref PermissionsBoundaryPolicy, !Ref 'AWS::NoValue']
PrivateEcrRepository:
- DependsOn: ParallelClusterApi
+ DependsOn: ParallelClusterApi3120
Type: AWS::ECR::Repository
Properties:
RepositoryName: !Sub
@@ -897,9 +1029,8 @@ Resources:
- Action:
- execute-api:Invoke
Effect: Allow
- Resource: !Sub
- - arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${PCApiGateway}/*/*
- - { PCApiGateway: !Select [2, !Split ['/', !Select [0, !Split ['.', !GetAtt [ ParallelClusterApi, Outputs.ParallelClusterApiInvokeUrl ]]]]] }
+ Resource: !Sub "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:*/*/*"
+# - { PCApiGateway: !Select [2, !Split ['/', !Select [0, !Split ['.', !GetAtt [ ParallelClusterApi3120, Outputs.ParallelClusterApiInvokeUrl ]]]]] }
CognitoPolicy:
Type: AWS::IAM::ManagedPolicy