Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling AWS::NoValue in Api resources #1435

Closed
abstiles opened this issue Feb 6, 2020 · 14 comments
Closed

Handling AWS::NoValue in Api resources #1435

abstiles opened this issue Feb 6, 2020 · 14 comments

Comments

@abstiles
Copy link

abstiles commented Feb 6, 2020

Description:

I was hoping to make use of the new Domain property on Api resources, but conditionally based on a template parameter. Attempting to set the Domain to !Ref AWS::NoValue (for the case where no DomainName is desired) fails with a message that suggests it's not removing the Domain property and is expecting real configuration in it. Here's what I tried in the Api configuration:

Domain:
  !If
  - HasDomainName
  - DomainName: !Ref DomainName
    CertificateArn: !Ref DomainCertificateArn
  - !Ref AWS::NoValue

And the message I got:

Transform AWS::Serverless-2016-10-31 failed with: Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [EventApi] is invalid. Custom Domains only works if both DomainName and CertificateArn are provided

Steps to reproduce the issue:

  1. Create an AWS::Serverless::Api resource with Domain property specified as in above example with HasDomainName condition (evaluating to false).
  2. Deploy the SAM template.
  3. Check the results.

Observed result:

Deploy fails with message: "Custom Domains only works if both DomainName and CertificateArn are provided"

Expected result:

DomainName and BasePathMapping resources created as if I had applied the conditional on each of them, such as:

ApiCustomDomain:
  Type: AWS::ApiGateway::DomainName
  Condition: HasDomainName
  Properties:
    DomainName: !Ref DomainName
    RegionalCertificateArn: !Ref DomainCertificateArn
    EndpointConfiguration:
      Types:
        - REGIONAL

ApiBasePath:
  Type: AWS::ApiGateway::BasePathMapping
  Condition: HasDomainName
  Properties:
    DomainName: !Ref ApiCustomDomain
    RestApiId: !Ref EventApi
    Stage: !Ref EventApi.Stage
@teemuniiranen
Copy link

teemuniiranen commented Aug 17, 2020

Any progress with this? Is there a workaround other that manually setting the domain name and certificate in the AWS console for those you want it?

@teemuniiranen
Copy link

I think the same is true for Auth / ResourcePolicy as well.

@nicovalencia
Copy link

I tried this every way I could think of:

  • Moving the conditional to each function (RestApiId does not support AWS::NoValue)
  • Adding all Parameters under the conditional
  • Using a mix of Mappings and higher level conditionals

We ended up needing to add a (manual or scripted) pre-deploy step that just removes the entire Domain config part if a domain isn't desired. I'd love to see a way to conditionally set a domain on an API.

@elbayaaa elbayaaa added area/resource/http-api stage/pm-review Waiting for review by our Product Manager, please don't work on this yet type/bug labels Feb 12, 2021
@elbayaaa
Copy link
Contributor

Thanks a lot guys. I was able to reproduce the issue. the problem is in this peace of code. We raise an exception if the Domain is provided but without DomainName or CertificateArn. When passing AWS::NoValue we receive a Domain={'Ref': 'AWS::NoValue'} that is why the exception is raised.

I'm labeling this for internal review as this is a common issue affecting many other areas as well.

@holt-calder
Copy link

holt-calder commented Feb 16, 2021

I believe the error extends beyond just AWS::NoValue. I am trying to conditionally set the Domain configuration to support a Gov Cloud deployment and get the same error despite each option in the condition containing the DomainName and CertificateARN. Template below for reference:

      Domain:
        !If
        - GovCloudCondition
        - DomainName: !Ref DomainName
          CertificateArn: !Ref CertificateARN
          EndpointConfiguration: REGIONAL
        - CertificateArn: !Ref CertificateARN
          DomainName: !Ref DomainName
          EndpointConfiguration: EDGE

That yields the same error above:

[Error found when transforming the template] Error transforming template: Resource with id [SageMakerApi] is invalid. Custom Domains only works if both DomainName and CertificateArn are provided

@elbayaaa elbayaaa removed the stage/pm-review Waiting for review by our Product Manager, please don't work on this yet label Feb 17, 2021
@ermanno
Copy link
Member

ermanno commented May 19, 2021

Hi, is there any new on this? I am writing a SAM template, and am forced to define three AWS::Serverless::Api resources conditionally to handle cases such as:

  • The user wants to specify a vpc endpoint or not (create PRIVATE/REGIONAL API)
  • The user wants to specify a custom domain name or not

Ideally I would like to define a single resource and conditionally add a Domain or an Auth/ResourcePolicy, etc.

@elbayaaa
Copy link
Contributor

Unfortunately, no progress I'm aware of at the time. Conditionally defining AWS::Serverless::Api resources seems to be the current work around. I think if you define your template in yaml, you can eliminate some of the duplication by using "Anchors" and "References".

@plondino
Copy link

Hi @elbayaaa I am curious how you are able to conditionally define multiple AWS::Serverless::Api and select between them based on issue #1470. If I have an AWS::Serverless::Function that uses the REST API for events, and I don't want one to use a domain (for example), do I have to define multiple lambda functions, one for each environment?

@singhsoldier13
Copy link

Having the same issue when defining conditional domains. Any workaround?

@mclounie
Copy link

mclounie commented Aug 6, 2021

Having a similar issue as holt-cader trying to define conditional EndpointConfiguration. Intrinsic functions do not work inside Domain per AWS support. Hoping this gets resolved.

"""In the above snippet you are using “EndpointConfiguration” which further holds the condition under “DomainName” . Domain property was unable to to accept value through Intrinsic Function ’If' and from the testing I have performed

It seems there is no issue with your template but this feature is not being supported by AWS till now."""

   Domain:
      DomainName: www.example.com
      CertificateArn: !Sub 'my:::arn'
      EndpointConfiguration:
        !If
          - IsCA
          - EDGE
          - REGIONAL

"FAILED" Status: FAILED. Reason: Transform AWS::Serverless-2016-10-31 failed with: Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [FormApiGateway] is invalid. EndpointConfiguration for Custom Domains must be one of ['EDGE', 'REGIONAL', 'PRIVATE']."

@foxbox-doug
Copy link

I thought I found a work-around but actually found another bug. I created 2 APIs so the entire API definition was dependent on my condition. Unfortunately, the following fails validation with sam validate:

  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Events:
        MyApi:
          Type: Api
          Properties:
            RestApiId: !If [ IsNotDev, !Ref ValidApiRef1, !Ref ValidApiRef2 ]
            Path: /site-customization
            Method: POST

Here is the error:

Error: [InvalidResourceException('MyFunction', 'Event with id [MyApi] is invalid. Api Event must reference an Api in the same template.')] ('MyFunction', 'Event with id [MyApi] is invalid. Api Event must reference an Api in the same template.')

@rrobby86
Copy link

rrobby86 commented Mar 4, 2022

I faced the same problem for an HTTP API and found a work-around which seems to be fine: set the custom domain using "native" CloudFormation resources in place of SAM "Domain" attribute. I don't know if something similar can also work for REST APIs, I post it here anyway as this topic appears to be the most related to my problem.

Resources:

  Api:
    Type: AWS::Serverless::HttpApi
    # put any necessary properties excluding the domain
  
  ApiDomain:
    Type: AWS::ApiGatewayV2::DomainName
    Condition: HasDomainName
    Properties:
      DomainName: !Ref DomainName
      DomainNameConfigurations:
        - CertificateArn: !Ref DomainCertificateArn
  
  ApiDomainMapping:
    Type: AWS::ApiGatewayV2::ApiMapping
    Condition: HasDomainName
    Properties:
      ApiId: !Ref Api
      Stage: $default  # unless a different StageName is used in Api
      DomainName: !Ref ApiDomain

@hoffa
Copy link
Contributor

hoffa commented Oct 17, 2022

You might be able to get this to work by adding AWS::LanguageExtensions to Transform as such:

Transform:
  - AWS::LanguageExtensions
  - AWS::Serverless-2016-10-31

AWS::LanguageExtensions resolves intrinsic functions if the value is known when Transforms are run.

See #2533 for more information.

@hoffa
Copy link
Contributor

hoffa commented Nov 3, 2022

Closing in favor of #2533.

@hoffa hoffa closed this as completed Nov 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests