github.skymusic.top/operator-framework/operator-sdk@v0.8.2/cmd/operator-sdk/migrate/cmd.go (about) 1 // Copyright 2019 The Operator-SDK Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package migrate 16 17 import ( 18 "fmt" 19 "os" 20 "path/filepath" 21 22 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold" 23 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold/ansible" 24 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold/helm" 25 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold/input" 26 "github.com/operator-framework/operator-sdk/internal/util/projutil" 27 28 "github.com/pkg/errors" 29 log "github.com/sirupsen/logrus" 30 "github.com/spf13/cobra" 31 ) 32 33 var ( 34 depManager string 35 headerFile string 36 ) 37 38 // NewCmd returns a command that will add source code to an existing non-go operator 39 func NewCmd() *cobra.Command { 40 newCmd := &cobra.Command{ 41 Use: "migrate", 42 Short: "Adds source code to an operator", 43 Long: `operator-sdk migrate adds a main.go source file and any associated source files for an operator that is not of the "go" type.`, 44 RunE: migrateRun, 45 } 46 47 newCmd.Flags().StringVar(&depManager, "dep-manager", "modules", `Dependency manager the new project will use (choices: "dep", "modules")`) 48 newCmd.Flags().StringVar(&headerFile, "header-file", "", "Path to file containing headers for generated Go files. Copied to hack/boilerplate.go.txt") 49 50 return newCmd 51 } 52 53 // migrateRun determines the current operator type and runs the corresponding 54 // migrate function. 55 func migrateRun(cmd *cobra.Command, args []string) error { 56 projutil.MustInProjectRoot() 57 58 _ = projutil.CheckAndGetProjectGoPkg() 59 60 opType := projutil.GetOperatorType() 61 switch opType { 62 case projutil.OperatorTypeAnsible: 63 return migrateAnsible() 64 case projutil.OperatorTypeHelm: 65 return migrateHelm() 66 } 67 return fmt.Errorf("operator of type %s cannot be migrated", opType) 68 } 69 70 // migrateAnsible runs the migration process for an ansible-based operator 71 func migrateAnsible() error { 72 wd := projutil.MustGetwd() 73 74 cfg := &input.Config{ 75 Repo: projutil.CheckAndGetProjectGoPkg(), 76 AbsProjectPath: wd, 77 ProjectName: filepath.Base(wd), 78 } 79 80 dockerfile := ansible.DockerfileHybrid{ 81 Watches: true, 82 Roles: true, 83 } 84 _, err := os.Stat(ansible.PlaybookYamlFile) 85 switch { 86 case err == nil: 87 dockerfile.Playbook = true 88 case os.IsNotExist(err): 89 log.Info("No playbook was found, so not including it in the new Dockerfile") 90 default: 91 return fmt.Errorf("error trying to stat %s: (%v)", ansible.PlaybookYamlFile, err) 92 } 93 if err := renameDockerfile(); err != nil { 94 return err 95 } 96 97 s := &scaffold.Scaffold{} 98 if headerFile != "" { 99 err = s.Execute(cfg, &scaffold.Boilerplate{BoilerplateSrcPath: headerFile}) 100 if err != nil { 101 return fmt.Errorf("boilerplate scaffold failed: (%v)", err) 102 } 103 s.BoilerplatePath = headerFile 104 } 105 106 if err := scaffoldAnsibleDepManager(s, cfg); err != nil { 107 return errors.Wrap(err, "migrate Ansible dependency manager file scaffold failed") 108 } 109 110 err = s.Execute(cfg, 111 &ansible.Main{}, 112 &dockerfile, 113 &ansible.Entrypoint{}, 114 &ansible.UserSetup{}, 115 &ansible.K8sStatus{}, 116 &ansible.AoLogs{}, 117 ) 118 if err != nil { 119 return fmt.Errorf("migrate ansible scaffold failed: (%v)", err) 120 } 121 return nil 122 } 123 124 // migrateHelm runs the migration process for a helm-based operator 125 func migrateHelm() error { 126 wd := projutil.MustGetwd() 127 128 cfg := &input.Config{ 129 Repo: projutil.CheckAndGetProjectGoPkg(), 130 AbsProjectPath: wd, 131 ProjectName: filepath.Base(wd), 132 } 133 134 if err := renameDockerfile(); err != nil { 135 return err 136 } 137 138 s := &scaffold.Scaffold{} 139 if headerFile != "" { 140 err := s.Execute(cfg, &scaffold.Boilerplate{BoilerplateSrcPath: headerFile}) 141 if err != nil { 142 return fmt.Errorf("boilerplate scaffold failed: (%v)", err) 143 } 144 s.BoilerplatePath = headerFile 145 } 146 147 if err := scaffoldHelmDepManager(s, cfg); err != nil { 148 return errors.Wrap(err, "migrate Helm dependency manager file scaffold failed") 149 } 150 151 err := s.Execute(cfg, 152 &helm.Main{}, 153 &helm.DockerfileHybrid{ 154 Watches: true, 155 HelmCharts: true, 156 }, 157 &helm.Entrypoint{}, 158 &helm.UserSetup{}, 159 ) 160 if err != nil { 161 return fmt.Errorf("migrate helm scaffold failed: (%v)", err) 162 } 163 return nil 164 } 165 166 func renameDockerfile() error { 167 dockerfilePath := filepath.Join(scaffold.BuildDir, scaffold.DockerfileFile) 168 newDockerfilePath := dockerfilePath + ".sdkold" 169 err := os.Rename(dockerfilePath, newDockerfilePath) 170 if err != nil { 171 return fmt.Errorf("failed to rename Dockerfile: (%v)", err) 172 } 173 log.Infof("Renamed Dockerfile to %s and replaced with newer version. Compare the new Dockerfile to your old one and manually migrate any customizations", newDockerfilePath) 174 return nil 175 } 176 177 func scaffoldHelmDepManager(s *scaffold.Scaffold, cfg *input.Config) error { 178 var files []input.File 179 switch m := projutil.DepManagerType(depManager); m { 180 case projutil.DepManagerDep: 181 files = append(files, &helm.GopkgToml{}) 182 case projutil.DepManagerGoMod: 183 if err := goModCheck(); err != nil { 184 return err 185 } 186 files = append(files, &helm.GoMod{}, &scaffold.Tools{}) 187 default: 188 return projutil.ErrInvalidDepManager(depManager) 189 } 190 return s.Execute(cfg, files...) 191 } 192 193 func scaffoldAnsibleDepManager(s *scaffold.Scaffold, cfg *input.Config) error { 194 var files []input.File 195 switch m := projutil.DepManagerType(depManager); m { 196 case projutil.DepManagerDep: 197 files = append(files, &ansible.GopkgToml{}) 198 case projutil.DepManagerGoMod: 199 if err := goModCheck(); err != nil { 200 return err 201 } 202 files = append(files, &ansible.GoMod{}, &scaffold.Tools{}) 203 default: 204 return projutil.ErrInvalidDepManager(depManager) 205 } 206 return s.Execute(cfg, files...) 207 } 208 209 func goModCheck() error { 210 goModOn, err := projutil.GoModOn() 211 if err == nil && !goModOn { 212 log.Fatal(`Dependency manager "modules" has been selected but go modules are not active. ` + 213 `Activate modules then run "operator-sdk migrate".`) 214 } 215 return err 216 }