Skip to content

Commit

Permalink
aws-vpc: add support for multiple route tables
Browse files Browse the repository at this point in the history
Resolving conflicts for pull request #561 and adding documentation.
  • Loading branch information
Tom Taylor authored and t0mmyt committed May 9, 2017
1 parent 9eecece commit 4427ede
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 23 deletions.
11 changes: 10 additions & 1 deletion Documentation/aws-vpc-backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,20 @@ First, SSH into `demo-instance-1`:
```
$ etcd --advertise-client-urls http://$INTERNAL_IP:2379 --listen-client-urls http://0.0.0.0:2379
```
- Publish configuration in etcd (ensure that the network range does not overlap with the one configured for the VPC)
- Publish configuration in etcd (ensure that the network range does not overlap with the one configured for the VPC). This will
attempt to automatically determine your route table.

```
$ etcdctl set /coreos.com/network/config '{"Network":"10.20.0.0/16", "Backend": {"Type": "aws-vpc"}}'
```

- If you want to manually specify your route table ID or if you want to update multiple route tables, e.g. for a deployment across multiple availability zones, use either a string for one or an array for one or more route tables like this.

```
$ etcdctl set /coreos.com/network/config '{"Network":"10.20.0.0/16", "Backend": {"Type": "aws-vpc", "RouteTableID": ["rtb-abc00001","rtb-abc00002","rtb-abc00003"]} }'}}'
```


- Fetch the latest release using wget from [here](https://github.com/coreos/flannel/releases/download/v0.7.0/flannel-v0.7.0-linux-amd64.tar.gz)
- Run flannel daemon:

Expand Down
80 changes: 58 additions & 22 deletions backend/awsvpc/awsvpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,42 @@ func (be *AwsVpcBackend) Run(ctx context.Context) {
<-ctx.Done()
}

type backendConfig struct {
RouteTableID interface{} `json:"RouteTableID"`
}

func (conf *backendConfig) routeTables() ([]string, error) {
if table, ok := conf.RouteTableID.(string); ok {
log.Info(fmt.Sprintf("RouteTableID configured as string: %s", table))
return []string{table}, nil
}
if rawTables, ok := conf.RouteTableID.([]interface{}); ok {
log.Info(fmt.Sprintf("RouteTableID configured as slice: %+v", rawTables))
tables := make([]string, len(rawTables))
for idx, t := range rawTables {
table, ok := t.(string)
if !ok {
return nil, fmt.Errorf("Unexpected type in RouteTableID slice. Must be strings.")
}
tables[idx] = table
}
return tables, nil
}
return nil, fmt.Errorf("Unexpected RouteTableID type. Must be string or array of strings.")
}

func (conf *backendConfig) routeTableConfigured() bool {
configured := conf.RouteTableID != nil
log.Info(fmt.Sprintf("Route table configured: %t", configured))
return configured
}

func (be *AwsVpcBackend) RegisterNetwork(ctx context.Context, config *subnet.Config) (backend.Network, error) {
// Parse our configuration
cfg := struct {
RouteTableID string
}{}
var cfg backendConfig

if len(config.Backend) > 0 {
log.Info("Backend configured as: %s", string(config.Backend))
if err := json.Unmarshal(config.Backend, &cfg); err != nil {
return nil, fmt.Errorf("error decoding VPC backend config: %v", err)
}
Expand Down Expand Up @@ -108,7 +137,7 @@ func (be *AwsVpcBackend) RegisterNetwork(ctx context.Context, config *subnet.Con
log.Warningf("failed to disable SourceDestCheck on %s: %s.\n", *eni.NetworkInterfaceId, err)
}

if cfg.RouteTableID == "" {
if !cfg.routeTableConfigured() {
if cfg.RouteTableID, err = be.detectRouteTableID(eni, ec2c); err != nil {
return nil, err
}
Expand All @@ -120,29 +149,36 @@ func (be *AwsVpcBackend) RegisterNetwork(ctx context.Context, config *subnet.Con
log.Errorf("Error fetching network config: %v", err)
}

err = be.cleanupBlackholeRoutes(cfg.RouteTableID, networkConfig.Network, ec2c)
tables, err := cfg.routeTables()
if err != nil {
log.Errorf("Error cleaning up blackhole routes: %v", err)
return nil, err
}

matchingRouteFound, err := be.checkMatchingRoutes(cfg.RouteTableID, l.Subnet.String(), eni.NetworkInterfaceId, ec2c)
if err != nil {
log.Errorf("Error describing route tables: %v", err)
}
for _, routeTableID := range tables {
err = be.cleanupBlackholeRoutes(routeTableID, networkConfig.Network, ec2c)
if err != nil {
log.Errorf("Error cleaning up blackhole routes: %v", err)
}

if !matchingRouteFound {
cidrBlock := l.Subnet.String()
deleteRouteInput := &ec2.DeleteRouteInput{RouteTableId: &cfg.RouteTableID, DestinationCidrBlock: &cidrBlock}
if _, err := ec2c.DeleteRoute(deleteRouteInput); err != nil {
if ec2err, ok := err.(awserr.Error); !ok || ec2err.Code() != "InvalidRoute.NotFound" {
// an error other than the route not already existing occurred
return nil, fmt.Errorf("error deleting existing route for %s: %v", l.Subnet.String(), err)
}
matchingRouteFound, err := be.checkMatchingRoutes(routeTableID, l.Subnet.String(), eni.NetworkInterfaceId, ec2c)
if err != nil {
log.Errorf("Error describing route tables: %v", err)
}

// Add the route for this machine's subnet
if err := be.createRoute(cfg.RouteTableID, l.Subnet.String(), eni.NetworkInterfaceId, ec2c); err != nil {
return nil, fmt.Errorf("unable to add route %s: %v", l.Subnet.String(), err)
if !matchingRouteFound {
cidrBlock := l.Subnet.String()
deleteRouteInput := &ec2.DeleteRouteInput{RouteTableId: &routeTableID, DestinationCidrBlock: &cidrBlock}
if _, err := ec2c.DeleteRoute(deleteRouteInput); err != nil {
if ec2err, ok := err.(awserr.Error); !ok || ec2err.Code() != "InvalidRoute.NotFound" {
// an error other than the route not already existing occurred
return nil, fmt.Errorf("error deleting existing route for %s: %v", l.Subnet.String(), err)
}
}

// Add the route for this machine's subnet
if err := be.createRoute(routeTableID, l.Subnet.String(), eni.NetworkInterfaceId, ec2c); err != nil {
return nil, fmt.Errorf("unable to add route %s: %v", l.Subnet.String(), err)
}
}
}

Expand Down Expand Up @@ -220,7 +256,7 @@ func (be *AwsVpcBackend) createRoute(routeTableID, subnet string, eniID *string,
if _, err := ec2c.CreateRoute(route); err != nil {
return err
}
log.Infof("Route added %s - %s.\n", subnet, *eniID)
log.Infof("Route added to table %s: %s - %s.\n", routeTableID, subnet, *eniID)
return nil
}

Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ func main() {
log.Error("Failed to create SubnetManager: ", err)
os.Exit(1)
}
log.Info(fmt.Sprintf("Created subnet manager: %+v", sm))

// Register for SIGINT and SIGTERM
log.Info("Installing signal handlers")
Expand Down
1 change: 1 addition & 0 deletions subnet/kube/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func NewSubnetManager() (subnet.Manager, error) {
if err != nil {
return nil, fmt.Errorf("error parsing subnet config: %s", err)
}

sm, err := newKubeSubnetManager(c, sc, nodeName)
if err != nil {
return nil, fmt.Errorf("error creating network manager: %s", err)
Expand Down

0 comments on commit 4427ede

Please sign in to comment.