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

Allow plugins to add CFN tags and outputs #1575

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions builtin/files/stack-templates/control-plane.json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
"PropagateAtLaunch": "true",
"Value": "true"
},
{{range $n, $r := .ExtraCfnTags}}
{{range $i, $j := $r}}
{{toJson $j}},
{{end}}
{{end}}
{
"Key": "Name",
"PropagateAtLaunch": "true",
Expand Down Expand Up @@ -719,5 +724,9 @@
"Description": "The name of this stack which is used by node pool stacks to import outputs from this stack",
"Value": { "Ref": "AWS::StackName" }
}
{{range $n, $r := .ExtraCfnOutputs}}
,
{{quote $n}}: {{toJSON $r}}
{{end}}
}
}
4 changes: 4 additions & 0 deletions builtin/files/stack-templates/etcd.json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -605,5 +605,9 @@
"Description": "The name of this stack which is used by node pool stacks to import outputs from this stack",
"Value": { "Ref": "AWS::StackName" }
}
{{range $n, $r := .ExtraCfnOutputs}}
,
{{quote $n}}: {{toJSON $r}}
{{end}}
}
}
4 changes: 4 additions & 0 deletions builtin/files/stack-templates/network.json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -910,5 +910,9 @@
"Description": "The name of this stack which is used by node pool stacks to import outputs from this stack",
"Value": { "Ref": "AWS::StackName" }
}
{{range $n, $r := .ExtraCfnOutputs}}
,
{{quote $n}}: {{toJSON $r}}
{{end}}
}
}
9 changes: 9 additions & 0 deletions builtin/files/stack-templates/node-pool.json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@
"PropagateAtLaunch": "true",
"Value": "owned"
},
{{range $n, $r := .ExtraCfnTags}}
{{range $i, $j := $r}}
{{toJson $j}},
{{end}}
{{end}}
{
"Key": "kube-aws:node-pool:name",
"PropagateAtLaunch": "true",
Expand Down Expand Up @@ -622,5 +627,9 @@
"Description": "The name of this stack",
"Value": { "Ref": "AWS::StackName" }
}
{{range $n, $r := .ExtraCfnOutputs}}
,
{{quote $n}}: {{toJSON $r}}
{{end}}
}
}
4 changes: 4 additions & 0 deletions core/root/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ type Cluster struct {
nodePoolStacks []*model.Stack

ExtraCfnResources map[string]interface{}
ExtraCfnTags map[string]interface{}
ExtraCfnOutputs map[string]interface{}

opts options
session *session.Session
Expand Down Expand Up @@ -249,6 +251,8 @@ func (cl *Cluster) ensureNestedStacksLoaded() error {
}

cl.ExtraCfnResources = extra.Resources
cl.ExtraCfnTags = extra.Tags
cl.ExtraCfnOutputs = extra.Outputs

return nil
}
Expand Down
8 changes: 8 additions & 0 deletions core/root/template_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ func (p TemplateParams) ExtraCfnResources() map[string]interface{} {
return p.cluster.ExtraCfnResources
}

func (p TemplateParams) ExtraCfnOutputs() map[string]interface{} {
return p.cluster.ExtraCfnOutputs
}

func (p TemplateParams) ExtraCfnTags() map[string]interface{} {
return p.cluster.ExtraCfnTags
}

func (p TemplateParams) ClusterName() string {
return p.cluster.controlPlaneStack.ClusterName
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/api/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ type Stacks struct {
type Stack struct {
Resources `yaml:"resources,omitempty"`
Outputs `yaml:"outputs,omitempty"`
Tags `yaml:"tags,omitempty"`
}

type Resources struct {
Expand All @@ -114,6 +115,10 @@ type Outputs struct {
provisioner.RemoteFileSpec `yaml:",inline"`
}

type Tags struct {
provisioner.RemoteFileSpec `yaml:",inline"`
}

type Helm struct {
// Releases is a list of helm releases to be maintained on the cluster.
// Note that the list is sorted by their names by kube-aws so that it won't result in unnecessarily node replacements.
Expand Down
6 changes: 6 additions & 0 deletions pkg/model/stack_new.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ func NewControlPlaneStack(conf *Config, opts api.StackTemplateOptions, extras cl
return fmt.Errorf("failed to load control-plane stack extras from plugins: %v", err)
}
stack.ExtraCfnResources = extraStack.Resources
stack.ExtraCfnTags = extraStack.Tags
stack.ExtraCfnOutputs = extraStack.Outputs

extraController, err := extras.Controller(conf)
if err != nil {
Expand Down Expand Up @@ -130,6 +132,7 @@ func NewNetworkStack(conf *Config, nodePools []*Stack, opts api.StackTemplateOpt
return fmt.Errorf("failed to load network stack extras from plugins: %v", err)
}
stack.ExtraCfnResources = extraStack.Resources
stack.ExtraCfnOutputs = extraStack.Outputs
return nil
},
)
Expand Down Expand Up @@ -173,6 +176,7 @@ func NewEtcdStack(conf *Config, opts api.StackTemplateOptions, extras clusterext
return fmt.Errorf("failed to load etcd stack extras from plugins: %v", err)
}
stack.ExtraCfnResources = extraStack.Resources
stack.ExtraCfnOutputs = extraStack.Outputs

extraEtcd, err := extras.Etcd()
if err != nil {
Expand Down Expand Up @@ -211,6 +215,8 @@ func NewWorkerStack(conf *Config, npconf *NodePoolConfig, opts api.StackTemplate
return fmt.Errorf("failed to load node pool stack extras from plugins: %v", err)
}
stack.ExtraCfnResources = extraStack.Resources
stack.ExtraCfnTags = extraStack.Tags
stack.ExtraCfnOutputs = extraStack.Outputs

extraWorker, err := extras.Worker(conf)
if err != nil {
Expand Down
7 changes: 5 additions & 2 deletions pkg/model/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ type Stack struct {
UserData map[string]api.UserData
CfnInitConfigSets map[string]interface{}
ExtraCfnResources map[string]interface{}
AssetsConfig *credential.CompactAssets
assets cfnstack.Assets
ExtraCfnTags map[string]interface{}
ExtraCfnOutputs map[string]interface{}

AssetsConfig *credential.CompactAssets
assets cfnstack.Assets
}

type ec2Service interface {
Expand Down
22 changes: 22 additions & 0 deletions plugin/clusterextension/extras.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ func NewExtras() ClusterExtension {

type stack struct {
Resources map[string]interface{}
Outputs map[string]interface{}
Tags map[string]interface{}
}

func (e ClusterExtension) KeyPairSpecs() []api.KeyPairSpec {
Expand Down Expand Up @@ -114,6 +116,8 @@ func (e ClusterExtension) foreachEnabledPlugins(do func(p *api.Plugin, pc *api.P

func (e ClusterExtension) stackExt(name string, config interface{}, src func(p *api.Plugin) api.Stack) (*stack, error) {
resources := map[string]interface{}{}
outputs := map[string]interface{}{}
tags := map[string]interface{}{}

err := e.foreachEnabledPlugins(func(p *api.Plugin, pc *api.PluginConfig) error {
values := pluginutil.MergeValues(p.Spec.Cluster.Values, pc.Values)
Expand All @@ -128,6 +132,22 @@ func (e ClusterExtension) stackExt(name string, config interface{}, src func(p *
resources[k] = v
}

m, err = render.MapFromJsonContents(src(p).Outputs.RemoteFileSpec)
if err != nil {
return fmt.Errorf("failed to load additional outputs for %s stack: %v", name, err)
}
for k, v := range m {
outputs[k] = v
}

m, err = render.MapFromJsonContents(src(p).Tags.RemoteFileSpec)
if err != nil {
return fmt.Errorf("failed to load additional tags for %s stack: %v", name, err)
}
for k, v := range m {
tags[k] = v
}

return nil
})

Expand All @@ -137,6 +157,8 @@ func (e ClusterExtension) stackExt(name string, config interface{}, src func(p *

return &stack{
Resources: resources,
Outputs: outputs,
Tags: tags,
}, nil
}

Expand Down
76 changes: 76 additions & 0 deletions test/integration/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,25 @@ spec:
}
}
}
tags:
content: |
{
"Tags": [
{
"Key": "control/tag",
"PropagateAtLaunch": "false",
"Value": ""
}
]
}
outputs:
content: |
{
"ControlStack": {
"Description": "ControlStack",
"Value": "ControlOutput"
}
}
nodePool:
resources:
content: |
Expand All @@ -109,6 +128,25 @@ spec:
}
}
}
tags:
content: |
{
"Tags": [
{
"Key": "nodepool/tag",
"PropagateAtLaunch": "false",
"Value": ""
}
]
}
outputs:
content: |
{
"NodeStack": {
"Description": "NodeStack",
"Value": "NodeOutput"
}
}
root:
resources:
content: |
Expand All @@ -131,6 +169,14 @@ spec:
}
}
}
outputs:
content: |
{
"EtcdStack": {
"Description": "EtcdStack",
"Value": "EtcdOutput"
}
}
network:
resources:
content: |
Expand All @@ -142,6 +188,14 @@ spec:
}
}
}
outputs:
content: |
{
"NetworkStack": {
"Description": "NetworkStack",
"Value": "NetworkOutput"
}
}
kubernetes:
apiserver:
flags:
Expand Down Expand Up @@ -464,6 +518,28 @@ spec:
t.Errorf("Invalid worker node pool stack template: missing iam policy statement ec2:*: %v", nodePoolStackTemplate)
}

// A kube-aws plugin can inject control plane and node pool tags
if !strings.Contains(controlPlaneStackTemplate, `"Key":"control/tag"`) {
t.Errorf("Invalid control-plane stack template: missing tag control/tag: %v", controlPlaneStackTemplate)
}
if !strings.Contains(nodePoolStackTemplate, `"Key":"nodepool/tag"`) {
t.Errorf("Invalid node-pool stack template: missing tag nodepool/tag: %v", nodePoolStackTemplate)
}

// A kube-aws plugin can inject cfn outputs
if !strings.Contains(controlPlaneStackTemplate, `"Value":"ControlOutput"`) {
t.Errorf("Invalid control-plane stack template: missing output ControlOutput: %v", controlPlaneStackTemplate)
}
if !strings.Contains(nodePoolStackTemplate, `"Value":"NodeOutput"`) {
t.Errorf("Invalid node-pool stack template: missing output NodeOutput: %v", nodePoolStackTemplate)
}
if !strings.Contains(etcdStackTemplate, `"Value":"EtcdOutput"`) {
t.Errorf("Invalid etcd stack template: missing output EtcdOutput: %v", etcdStackTemplate)
}
if !strings.Contains(networkStackTemplate, `"Value":"NetworkOutput"`) {
t.Errorf("Invalid network stack template: missing output Network: %v", networkStackTemplate)
}

// A kube-aws plugin can inject node labels
if !strings.Contains(controllerUserdataS3Part, "role=controller") {
t.Error("missing controller node label: role=controller")
Expand Down