github.com/mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/tools/gen.go (about) 1 /* 2 Copyright 2018 Mirantis 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package tools 18 19 import ( 20 "errors" 21 "io" 22 23 "github.com/spf13/cobra" 24 apps "k8s.io/api/apps/v1" 25 v1 "k8s.io/api/core/v1" 26 "k8s.io/apimachinery/pkg/runtime" 27 28 "github.com/Mirantis/virtlet/pkg/config" 29 "github.com/Mirantis/virtlet/pkg/version" 30 ) 31 32 const ( 33 sourceYamlFile = "deploy/data/virtlet-ds.yaml" 34 virtletImage = "mirantis/virtlet" 35 ) 36 37 // genCommand is used to generate Kubernetes YAML for Virtlet deployment 38 type genCommand struct { 39 out io.Writer 40 dev bool 41 compat bool 42 crd bool 43 tag string 44 } 45 46 // NewGenCmd returns a cobra.Command that generates Kubernetes YAML for Virtlet 47 // deployment. 48 func NewGenCmd(out io.Writer) *cobra.Command { 49 g := &genCommand{out: out} 50 cmd := &cobra.Command{ 51 Use: "gen", 52 Short: "Generate Kubernetes YAML for Virtlet deployment", 53 Long: "This command produces YAML suitable for use with kubectl apply -f -", 54 RunE: func(cmd *cobra.Command, args []string) error { 55 if len(args) != 0 { 56 return errors.New("This command does not accept arguments") 57 } 58 return g.Run() 59 }, 60 } 61 cmd.Flags().BoolVar(&g.dev, "dev", false, "Development mode for use with kubeadm-dind-cluster") 62 cmd.Flags().BoolVar(&g.compat, "compat", false, "Produce YAML that's compatible with older Kubernetes versions") 63 cmd.Flags().BoolVar(&g.crd, "crd", false, "Dump CRD definitions only") 64 cmd.Flags().StringVar(&g.tag, "tag", version.Get().ImageTag, "Set virtlet image tag") 65 return cmd 66 } 67 68 func (g *genCommand) getYaml() ([]byte, error) { 69 var objs []runtime.Object 70 if !g.crd { 71 bs, err := Asset(sourceYamlFile) 72 if err != nil { 73 return bs, err 74 } 75 76 if objs, err = LoadYaml(bs); err != nil { 77 return nil, err 78 } 79 if len(objs) == 0 { 80 return nil, errors.New("source yaml is empty") 81 } 82 83 ds, ok := objs[0].(*apps.DaemonSet) 84 if !ok { 85 return nil, errors.New("the first object is not a DaemonSet") 86 } 87 if g.dev { 88 applyDev(ds) 89 } 90 if g.compat { 91 applyCompat(ds) 92 } 93 if g.tag != "" { 94 applyTag(ds, g.tag) 95 } 96 } 97 98 objs = append(objs, config.GetCRDDefinitions()...) 99 return ToYaml(objs) 100 } 101 102 // Run executes the command. 103 func (g *genCommand) Run() error { 104 bs, err := g.getYaml() 105 if err != nil { 106 return err 107 } 108 if _, err := g.out.Write(bs); err != nil { 109 return err 110 } 111 return nil 112 } 113 114 func walkContainers(ds *apps.DaemonSet, toCall func(c *v1.Container)) { 115 initContainers := ds.Spec.Template.Spec.InitContainers 116 for n := range initContainers { 117 toCall(&initContainers[n]) 118 } 119 containers := ds.Spec.Template.Spec.Containers 120 for n := range containers { 121 toCall(&containers[n]) 122 } 123 } 124 125 func walkMounts(ds *apps.DaemonSet, toCall func(m *v1.VolumeMount)) { 126 walkContainers(ds, func(c *v1.Container) { 127 for i := range c.VolumeMounts { 128 toCall(&c.VolumeMounts[i]) 129 } 130 }) 131 } 132 133 func applyDev(ds *apps.DaemonSet) { 134 ds.Spec.Template.Spec.Volumes = append(ds.Spec.Template.Spec.Volumes, v1.Volume{ 135 Name: "dind", 136 VolumeSource: v1.VolumeSource{ 137 HostPath: &v1.HostPathVolumeSource{ 138 Path: "/dind", 139 }, 140 }, 141 }) 142 volMount := v1.VolumeMount{ 143 Name: "dind", 144 MountPath: "/dind", 145 } 146 walkContainers(ds, func(c *v1.Container) { 147 c.VolumeMounts = append(c.VolumeMounts, volMount) 148 }) 149 } 150 151 func applyCompat(ds *apps.DaemonSet) { 152 walkMounts(ds, func(v *v1.VolumeMount) { 153 if v.Name == "run" || v.Name == "k8s-pods-dir" { 154 v.MountPath += ":shared" 155 v.MountPropagation = nil 156 } 157 }) 158 } 159 160 func applyTag(ds *apps.DaemonSet, tag string) { 161 walkContainers(ds, func(c *v1.Container) { 162 if c.Image == virtletImage { 163 c.Image += ":" + tag 164 } 165 }) 166 }