Skip to content
This repository has been archived by the owner on May 22, 2020. It is now read-only.

Commit

Permalink
Merge pull request #71 from justinsb/upup_terraform
Browse files Browse the repository at this point in the history
upup: support for terraform on AWS
  • Loading branch information
justinsb committed Jun 8, 2016
2 parents 18502e8 + 812e7d6 commit 999c5e0
Show file tree
Hide file tree
Showing 39 changed files with 1,193 additions and 265 deletions.
5 changes: 3 additions & 2 deletions upup/cmd/cloudup/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ func (c *CreateClusterCmd) Run() error {
"routeTable": &awstasks.RouteTable{},
"routeTableAssociation": &awstasks.RouteTableAssociation{},
"securityGroup": &awstasks.SecurityGroup{},
"securityGroupIngress": &awstasks.SecurityGroupIngress{},
"securityGroupRule": &awstasks.SecurityGroupRule{},
"subnet": &awstasks.Subnet{},
"vpc": &awstasks.VPC{},
"vpcDHDCPOptionsAssociation": &awstasks.VPCDHCPOptionsAssociation{},
Expand Down Expand Up @@ -409,7 +409,8 @@ func (c *CreateClusterCmd) Run() error {

case "terraform":
checkExisting = false
target = terraform.NewTerraformTarget(region, project, os.Stdout)
outDir := path.Join(c.StateDir, "terraform")
target = terraform.NewTerraformTarget(cloud, region, project, outDir)

case "dryrun":
target = fi.NewDryRunTarget(os.Stdout)
Expand Down
10 changes: 8 additions & 2 deletions upup/models/cloudup/_aws/master/_master_lb/master_lb.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,22 @@ securityGroup/api.{{ .ClusterName }}:
vpc: vpc/kubernetes-{{ .ClusterName }}
description: 'Security group for ELB in front of masters'

# Allow full egress
securityGroupRule/egress-api-lb:
securityGroup: securityGroup/api.{{ .ClusterName}
egress: true
cidr: 0.0.0.0/0

# HTTPS to the master ELB is allowed (for API access)
securityGroupIngress/https-external-to-api:
securityGroupRule/https-external-to-api:
securityGroup: securityGroup/api.{{ .ClusterName }}
cidr: 0.0.0.0/0
protocol: tcp
fromPort: 443
toPort: 443

# Allow HTTPS to the master from the master ELB
securityGroupIngress/https-elb-to-master:
securityGroupRule/https-elb-to-master:
securityGroup: securityGroup/kubernetes.master.{{ .ClusterName }}
sourceGroup: securityGroup/api.{{ .ClusterName }}
protocol: tcp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# We need to open security groups directly to the master nodes (instead of via the ELB)

# HTTPS to the master is allowed (for API access)
securityGroupIngress/https-external-to-master:
securityGroupRule/https-external-to-master:
securityGroup: securityGroup/kubernetes.master.{{ .ClusterName }}
cidr: 0.0.0.0/0
protocol: tcp
Expand Down
12 changes: 9 additions & 3 deletions upup/models/cloudup/_aws/master/master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,27 @@ securityGroup/kubernetes.master.{{ .ClusterName }}:
vpc: vpc/kubernetes.{{ .ClusterName }}
description: 'Security group for masters'

# Allow full egress
securityGroupRule/master-egress:
securityGroup: securityGroup/kubernetes.master.{{.ClusterName}}
egress: true
cidr: 0.0.0.0/0

# SSH is open to the world
securityGroupIngress/ssh-external-to-master:
securityGroupRule/ssh-external-to-master:
securityGroup: securityGroup/kubernetes.master.{{ .ClusterName }}
cidr: 0.0.0.0/0
protocol: tcp
fromPort: 22
toPort: 22

# Masters can talk to masters
securityGroupIngress/all-master-to-master:
securityGroupRule/all-master-to-master:
securityGroup: securityGroup/kubernetes.master.{{ .ClusterName }}
sourceGroup: securityGroup/kubernetes.master.{{ .ClusterName }}

# Masters can talk to nodes
securityGroupIngress/all-master-to-node:
securityGroupRule/all-master-to-node:
securityGroup: securityGroup/kubernetes.node.{{ .ClusterName }}
sourceGroup: securityGroup/kubernetes.master.{{ .ClusterName }}

Expand Down
12 changes: 9 additions & 3 deletions upup/models/cloudup/_aws/nodes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,27 @@ securityGroup/kubernetes.node.{{.ClusterName}}:
vpc: vpc/kubernetes.{{ .ClusterName }}
description: 'Security group for nodes'

# Allow full egress
securityGroupRule/node-egress:
securityGroup: securityGroup/kubernetes.node.{{.ClusterName}}
egress: true
cidr: 0.0.0.0/0

# SSH is open to the world
securityGroupIngress/ssh-external-to-node:
securityGroupRule/ssh-external-to-node:
securityGroup: securityGroup/kubernetes.node.{{.ClusterName}}
cidr: 0.0.0.0/0
protocol: tcp
fromPort: 22
toPort: 22

# Nodes can talk to nodes
securityGroupIngress/all-node-to-node:
securityGroupRule/all-node-to-node:
securityGroup: securityGroup/kubernetes.node.{{.ClusterName}}
sourceGroup: securityGroup/kubernetes.node.{{.ClusterName}}

# Nodes can talk masters nodes
securityGroupIngress/all-node-to-master:
securityGroupRule/all-node-to-master:
securityGroup: securityGroup/kubernetes.master.{{ .ClusterName }}
sourceGroup: securityGroup/kubernetes.node.{{.ClusterName}}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/golang/glog"
"k8s.io/kube-deploy/upup/pkg/fi"
"k8s.io/kube-deploy/upup/pkg/fi/cloudup/awsup"
"k8s.io/kube-deploy/upup/pkg/fi/cloudup/terraform"
"strings"
)

Expand Down Expand Up @@ -209,6 +210,8 @@ func (_ *AutoscalingGroup) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *Autos
}
}

// TODO: Use PropagateAtLaunch = false for tagging?

return nil //return output.AddAWSTags(cloud.Tags(), v, "vpc")
}

Expand Down Expand Up @@ -323,3 +326,123 @@ func renderAutoscalingLaunchConfigurationAWS(t *awsup.AWSAPITarget, name string,

return nil //return output.AddAWSTags(cloud.Tags(), v, "vpc")
}

type terraformASGTag struct {
Key *string `json:"key"`
Value *string `json:"value"`
PropagateAtLaunch *bool `json:"propagate_at_launch"`
}
type terraformAutoscalingGroup struct {
Name *string `json:"name,omitempty"`
LaunchConfigurationName *terraform.Literal `json:"launch_configuration,omitempty"`
MaxSize *int64 `json:"max_size,omitempty"`
MinSize *int64 `json:"min_size,omitempty"`
VPCZoneIdentifier []*terraform.Literal `json:"vpc_zone_identifier,omitempty"`
Tags []*terraformASGTag `json:"tag,omitempty"`
}

type terraformBlockDevice struct {
DeviceName *string `json:"device_name"`
VirtualName *string `json:"virtual_name"`
}

type terraformLaunchConfiguration struct {
NamePrefix *string `json:"name_prefix,omitempty"`
ImageID *string `json:"image_id,omitempty"`
InstanceType *string `json:"instance_type,omitempty"`
KeyName *terraform.Literal `json:"key_name,omitempty"`
IAMInstanceProfile *terraform.Literal `json:"iam_instance_profile,omitempty"`
SecurityGroups []*terraform.Literal `json:"security_groups,omitempty"`
AssociatePublicIpAddress *bool `json:"associate_public_ip_address,omitempty"`
UserData *terraform.Literal `json:"user_data,omitempty"`
EphemeralBlockDevice []*terraformBlockDevice `json:"ephemeral_block_device,omitempty"`
Lifecycle *terraformLifecycle `json:"lifecycle,omitempty"`
}

type terraformLifecycle struct {
CreateBeforeDestroy *bool `json:"create_before_destroy,omitempty"`
}

func (_ *AutoscalingGroup) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *AutoscalingGroup) error {
err := renderAutoscalingLaunchConfigurationTerraform(t, *e.Name, e)
if err != nil {
return err
}

tf := &terraformAutoscalingGroup{
Name: e.Name,
MinSize: e.MinSize,
MaxSize: e.MaxSize,
LaunchConfigurationName: terraform.LiteralProperty("aws_launch_configuration", *e.Name, "id"),
}

for _, s := range e.Subnets {
tf.VPCZoneIdentifier = append(tf.VPCZoneIdentifier, s.TerraformLink())
}

for k, v := range e.buildTags(t.Cloud) {
tf.Tags = append(tf.Tags, &terraformASGTag{
Key: fi.String(k),
Value: fi.String(v),
PropagateAtLaunch: fi.Bool(true),
})
}

return t.RenderResource("aws_autoscaling_group", *e.Name, tf)
}

func (e *AutoscalingGroup) TerraformLink() *terraform.Literal {
return terraform.LiteralProperty("aws_autoscaling_group", *e.Name, "id")
}

func renderAutoscalingLaunchConfigurationTerraform(t *terraform.TerraformTarget, namePrefix string, e *AutoscalingGroup) error {
cloud := t.Cloud.(*awsup.AWSCloud)

if e.ImageID == nil {
return fi.RequiredField("ImageID")
}
image, err := cloud.ResolveImage(*e.ImageID)
if err != nil {
return err
}

tf := &terraformLaunchConfiguration{
NamePrefix: &namePrefix,
ImageID: image.ImageId,
InstanceType: e.InstanceType,
}

if e.SSHKey != nil {
tf.KeyName = e.SSHKey.TerraformLink()
}

for _, sg := range e.SecurityGroups {
tf.SecurityGroups = append(tf.SecurityGroups, sg.TerraformLink())
}
tf.AssociatePublicIpAddress = e.AssociatePublicIP

if e.BlockDeviceMappings != nil {
tf.EphemeralBlockDevice = []*terraformBlockDevice{}
for _, b := range e.BlockDeviceMappings {
tf.EphemeralBlockDevice = append(tf.EphemeralBlockDevice, &terraformBlockDevice{
VirtualName: b.VirtualName,
DeviceName: b.DeviceName,
})
}
}

if e.UserData != nil {
tf.UserData, err = t.AddFile("aws_launch_configuration", *e.Name, "user_data", e.UserData)
if err != nil {
return err
}
}
if e.IAMInstanceProfile != nil {
tf.IAMInstanceProfile = e.IAMInstanceProfile.TerraformLink()
}

// So that we can update configurations
tf.Lifecycle = &terraformLifecycle{CreateBeforeDestroy: fi.Bool(true)}

return t.RenderResource("aws_launch_configuration", *e.Name, tf)
}
27 changes: 27 additions & 0 deletions upup/pkg/fi/cloudup/awstasks/dhcp_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/golang/glog"
"k8s.io/kube-deploy/upup/pkg/fi"
"k8s.io/kube-deploy/upup/pkg/fi/cloudup/awsup"
"k8s.io/kube-deploy/upup/pkg/fi/cloudup/terraform"
"strings"
)

//go:generate fitask -type=DHCPOptions
Expand Down Expand Up @@ -135,3 +137,28 @@ func (_ *DHCPOptions) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *DHCPOption

return t.AddAWSTags(*e.ID, t.Cloud.BuildTags(e.Name, nil))
}

type terraformDHCPOptions struct {
DomainName *string `json:"domain_name,omitempty"`
DomainNameServers []string `json:"domain_name_servers,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
}

func (_ *DHCPOptions) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *DHCPOptions) error {
cloud := t.Cloud.(*awsup.AWSCloud)

tf := &terraformDHCPOptions{
DomainName: e.DomainName,
Tags: cloud.BuildTags(e.Name, nil),
}

if e.DomainNameServers != nil {
tf.DomainNameServers = strings.Split(*e.DomainNameServers, ",")
}

return t.RenderResource("aws_vpc_dhcp_options", *e.Name, tf)
}

func (e *DHCPOptions) TerraformLink() *terraform.Literal {
return terraform.LiteralProperty("aws_vpc_dhcp_options", *e.Name, "id")
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/golang/glog"
"k8s.io/kube-deploy/upup/pkg/fi"
"k8s.io/kube-deploy/upup/pkg/fi/cloudup/awsup"
"k8s.io/kube-deploy/upup/pkg/fi/cloudup/terraform"
"strings"
)

Expand All @@ -16,7 +17,7 @@ type DNSName struct {
Name *string
ID *string
Zone *DNSZone
ResourceType string
ResourceType *string

TargetLoadBalancer *LoadBalancer
}
Expand All @@ -29,7 +30,11 @@ func (e *DNSName) Find(c *fi.Context) (*DNSName, error) {
return nil, nil
}
findName = strings.TrimSuffix(findName, ".")
findType := e.ResourceType

findType := fi.StringValue(e.ResourceType)
if findType == "" {
return nil, nil
}

request := &route53.ListResourceRecordSetsInput{
HostedZoneId: e.Zone.ID,
Expand Down Expand Up @@ -94,7 +99,7 @@ func (s *DNSName) CheckChanges(a, e, changes *DNSName) error {
func (_ *DNSName) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *DNSName) error {
rrs := &route53.ResourceRecordSet{
Name: e.Name,
Type: aws.String(e.ResourceType),
Type: e.ResourceType,
}

if e.TargetLoadBalancer != nil {
Expand Down Expand Up @@ -128,3 +133,41 @@ func (_ *DNSName) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *DNSName) error

return nil
}

type terraformRoute53Record struct {
Name *string `json:"name"`
Type *string `json:"type"`
TTL *string `json:"ttl"`
Records []string `json:"records"`

Alias *terraformAlias `json:"alias"`
ZoneID *terraform.Literal `json:"zone_id"`
}

type terraformAlias struct {
Name *string `json:"name"`
HostedZoneId *string `json:"zone_id"`
EvaluateTargetHealth *bool `json:"evaluate_target_health"`
}

func (_ *DNSName) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *DNSName) error {
tf := &terraformRoute53Record{
Name: e.Name,
ZoneID: e.Zone.TerraformLink(),
Type: e.ResourceType,
}

if e.TargetLoadBalancer != nil {
tf.Alias = &terraformAlias{
Name: e.TargetLoadBalancer.DNSName,
EvaluateTargetHealth: aws.Bool(false),
HostedZoneId: e.TargetLoadBalancer.HostedZoneId,
}
}

return t.RenderResource("aws_route53_record", *e.Name, tf)
}

func (e *DNSName) TerraformLink() *terraform.Literal {
return terraform.LiteralSelfLink("aws_route53_record", *e.Name)
}
Loading

0 comments on commit 999c5e0

Please sign in to comment.