Skip to content

fix: allow importing public subnets with no MapPublicIPOnLaunch#2457

Merged
mergify[bot] merged 7 commits intoaws:mainlinefrom
iamhopaul123:better-public-subnet-import
Jun 18, 2021
Merged

fix: allow importing public subnets with no MapPublicIPOnLaunch#2457
mergify[bot] merged 7 commits intoaws:mainlinefrom
iamhopaul123:better-public-subnet-import

Conversation

@iamhopaul123
Copy link
Copy Markdown
Contributor

fixes #1724, fixes #2287

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@iamhopaul123 iamhopaul123 requested a review from a team as a code owner June 14, 2021 20:07
@iamhopaul123 iamhopaul123 requested a review from huanjani June 14, 2021 20:07
@efekarakus efekarakus changed the title chore: allow importing public subnets with no MapPublicIPOnLaunch fix: allow importing public subnets with no MapPublicIPOnLaunch Jun 14, 2021
type ListVPCSubnetsOpts func([]*ec2.Subnet) []*ec2.Subnet

// FilterForPublicSubnets is used to filter to get public subnets.
func FilterForPublicSubnets() ListVPCSubnetsOpts {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we not be figuring out if a subnet has an internet gateway? so that we filter out the ones that are not relevant

Copy link
Copy Markdown
Contributor Author

@iamhopaul123 iamhopaul123 Jun 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be very difficult to tell since we need to check

  1. if the VPC has an internet gateway attached to it
  2. describe the route table check if it has route to the internet gateway and check if the route table is associated with the subnet (we would need to do it for every subnet within the VPC)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the drawback that this is too fragile? If we can provide a good experience by making these API calls and if there are no valid subnets, prompt customers what changes they'd need to make to their subnet in order for it to be useful to Copilot?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not too bad I think. We can describe the route tables for a given VPC from the user:

$ aws ec2 describe-route-tables --filters Name=vpc-id,Values=vpc-03e4614a3d0217256

In the response we'll look for SubnetId under Associations and for Routes to have a GatewayId that starts with igw-:

View JSON response
"Associations": [
  {
      "Main": false,
      "RouteTableAssociationId": "rtbassoc-096f8559b5e31d9d3",
      "RouteTableId": "rtb-073d682766628c37f",
      "SubnetId": "subnet-018ccb78d353cec9b",
      "AssociationState": {
          "State": "associated"
      }
  },
  {
      "Main": false,
      "RouteTableAssociationId": "rtbassoc-0ebf8e431225c1b20",
      "RouteTableId": "rtb-073d682766628c37f",
      "SubnetId": "subnet-005dc83a6473feee7",
      "AssociationState": {
          "State": "associated"
      }
  }
],
"PropagatingVgws": [],
"RouteTableId": "rtb-073d682766628c37f",
"Routes": [
  {
      "DestinationCidrBlock": "10.0.0.0/16",
      "GatewayId": "local",
      "Origin": "CreateRouteTable",
      "State": "active"
  },
  {
      "DestinationCidrBlock": "0.0.0.0/0",
      "GatewayId": "igw-058421418aeacb2f0",
      "Origin": "CreateRoute",
      "State": "active"
  }
]

The only downside is we won't have tags associated with the subnets, but we can make two network calls to get that info.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok addressed!

Comment thread internal/pkg/cli/env_init.go Outdated
log.Errorf(`No existing private subnets were found in VPC %s. You can either:
- Create new private subnets and then import them.
log.Errorf(`No existing subnets were found in VPC %s. You can either:
- Create new subnets and then import them as private subnets.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see it a bit confusing to say 'import them as private subnets', since whether they're private subnets doesn't depend on how they import them 🤔

@iamhopaul123 iamhopaul123 force-pushed the better-public-subnet-import branch from 83cdd88 to 27e70aa Compare June 14, 2021 22:38
type ListVPCSubnetsOpts func([]*ec2.Subnet) []*ec2.Subnet

// FilterForPublicSubnets is used to filter to get public subnets.
func FilterForPublicSubnets() ListVPCSubnetsOpts {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the drawback that this is too fragile? If we can provide a good experience by making these API calls and if there are no valid subnets, prompt customers what changes they'd need to make to their subnet in order for it to be useful to Copilot?

@efekarakus efekarakus added the do-not-merge Pull requests that mergify shouldn't merge until the requester allows it. label Jun 16, 2021
@iamhopaul123 iamhopaul123 removed the do-not-merge Pull requests that mergify shouldn't merge until the requester allows it. label Jun 16, 2021
@iamhopaul123 iamhopaul123 force-pushed the better-public-subnet-import branch from 27e70aa to bd0c59e Compare June 16, 2021 23:31
Comment thread internal/pkg/aws/ec2/ec2.go Outdated
Private []VPCResource
}

// ListVPCSubnets lists all subnets given a VPC ID. Note that public subnets
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// ListVPCSubnets lists all subnets given a VPC ID. Note that public subnets
// ListVPCSubnets lists all subnets with a given VPC ID. Note that public subnets

Comment thread internal/pkg/aws/ec2/ec2.go Outdated
}

// ListVPCSubnets lists all subnets given a VPC ID. Note that public subnets
// are subnets associated with a route table that routed by an internet gateway.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the wording of my fix is kinda weird but maybe a little clearer?

Suggested change
// are subnets associated with a route table that routed by an internet gateway.
// are subnets associated with an internet gateway through a route table.

Comment thread internal/pkg/aws/ec2/ec2.go Outdated

// ListVPCSubnets lists all subnets given a VPC ID. Note that public subnets
// are subnets associated with a route table that routed by an internet gateway.
// And the rest subnets are private subnets.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// And the rest subnets are private subnets.
// And the rest of the subnets are private.

Comment thread internal/pkg/cli/env_init.go Outdated
log.Warningf(`No existing public subnets were found in VPC %s.
If you proceed without public subnets, you will not be able to deploy Load Balanced Web Services in this environment.
log.Warningf(`No existing subnets were found in VPC %s.
If you proceed without specifying public subnets, you will not be able to deploy Load Balanced Web Services in this environment.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we say "specifying two public subnets"?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah maybe "without at least two public subnets"

@huanjani huanjani added the do-not-merge Pull requests that mergify shouldn't merge until the requester allows it. label Jun 17, 2021
Copy link
Copy Markdown
Contributor

@huanjani huanjani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Just some tiny wording nits. Feel free to remove DNM label when those are addressed (or ignored) 😄 .

Comment thread internal/pkg/aws/ec2/ec2.go Outdated
Comment on lines +62 to +63
// VPCResource contains the ID and name of a VPCResource.
type VPCResource struct {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this rename? I liked reading ec2.VPC and ec2.Subnets better

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see you wanted to use ID and Name across resources, what do you thikn of this alternative:

type resource struct {
   ID     string
   Name   string
}

type VPC resource

Comment on lines +164 to +168
// VPCSubnets are all subnets within a VPC.
type VPCSubnets struct {
Public []VPCResource
Private []VPCResource
}
Copy link
Copy Markdown
Contributor

@efekarakus efekarakus Jun 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 this is confusing, why is a subnet composed of VPC resources?

What do you think of refactoring to:

type Subnet struct {
   resource
   Public  bool
   VPCID   string
}

func (c *EC2) ListVPCSubnets(vpcID string) ([]Subnet, error) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm following the logic here #2457 (comment) i think it might be clearer to just have

// VPCSubnets are all subnets within a VPC.
type VPCSubnets struct {
	Public  []Subnet
	Private []Subnet
}

Comment thread internal/pkg/aws/ec2/ec2.go Outdated
Comment on lines +284 to +288
inputFilters := toEC2Filter(filters)
var routeTables []*ec2.RouteTable
input := &ec2.DescribeRouteTablesInput{
Filters: inputFilters,
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
inputFilters := toEC2Filter(filters)
var routeTables []*ec2.RouteTable
input := &ec2.DescribeRouteTablesInput{
Filters: inputFilters,
}
var routeTables []*ec2.RouteTable
input := &ec2.DescribeRouteTablesInput{
Filters: toEC2Filter(filters),
}

Comment thread internal/pkg/cli/env_init.go Outdated
log.Warningf(`No existing public subnets were found in VPC %s.
If you proceed without public subnets, you will not be able to deploy Load Balanced Web Services in this environment.
log.Warningf(`No existing subnets were found in VPC %s.
If you proceed without specifying public subnets, you will not be able to deploy Load Balanced Web Services in this environment.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah maybe "without at least two public subnets"

Comment thread internal/pkg/term/selector/ec2.go Outdated
// PublicSubnets has the user multiselect public subnets given the VPC ID.
func (s *EC2Select) PublicSubnets(prompt, help, vpcID string) ([]string, error) {
return s.subnet(prompt, help, vpcID, ec2.FilterForPublicSubnets())
return s.subnet(prompt, help, vpcID, true)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

boolean params are usually a codesmell because it's not clear what the boolean stands for: https://martinfowler.com/bliki/FlagArgument.html

return s.selectPublicSubnets(prompt, help, vpcID)
return s.selectPrivateSubnets(prompt, help, vpcID)

func (s *EC2Select) selectPublicSubnets(prompt, help, vpcID string) ([]string, error) {
   subnets, err := s.ec2.ListVPCSubnets(vpcID)
   if err != nil { ... }
   publicSubnets := .... // for-loop and filter on .Public
   
   return s.selectSubnets(prompt, help, publicSubnets) // This method is common for s.selectPrivateSubnets
}

@iamhopaul123 iamhopaul123 force-pushed the better-public-subnet-import branch from d18b6d1 to 86be194 Compare June 17, 2021 23:44
Copy link
Copy Markdown
Contributor

@efekarakus efekarakus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to merge after the nit!

// VPC contains the ID and name of a VPC.
type VPC struct {
// Resource contains the ID and name of a EC2 resource.
type Resource struct {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need to be public?
You can still access the public fields even if the embedded struct is private so you should be able to do vpc.ID

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iamhopaul123 iamhopaul123 removed the do-not-merge Pull requests that mergify shouldn't merge until the requester allows it. label Jun 18, 2021
@mergify mergify Bot merged commit cc8ecfc into aws:mainline Jun 18, 2021
thrau pushed a commit to localstack/copilot-cli-local that referenced this pull request Dec 9, 2022
…2457)

<!-- Provide summary of changes -->
fixes aws#1724, fixes aws#2287
<!-- Issue number, if available. E.g. "Fixes aws#31", "Addresses aws#42, 77" -->

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Import VPC with Public Subnets copilot env init does not see existing subnets.

6 participants