gitlab.com/jfprevost/gitlab-runner-notlscheck@v11.11.4+incompatible/commands/register.go (about) 1 package commands 2 3 import ( 4 "bufio" 5 "os" 6 "os/signal" 7 "strings" 8 9 "github.com/sirupsen/logrus" 10 "github.com/urfave/cli" 11 12 "gitlab.com/gitlab-org/gitlab-runner/common" 13 "gitlab.com/gitlab-org/gitlab-runner/helpers/ssh" 14 "gitlab.com/gitlab-org/gitlab-runner/network" 15 ) 16 17 type RegisterCommand struct { 18 context *cli.Context 19 network common.Network 20 reader *bufio.Reader 21 registered bool 22 23 configOptions 24 TagList string `long:"tag-list" env:"RUNNER_TAG_LIST" description:"Tag list"` 25 NonInteractive bool `short:"n" long:"non-interactive" env:"REGISTER_NON_INTERACTIVE" description:"Run registration unattended"` 26 LeaveRunner bool `long:"leave-runner" env:"REGISTER_LEAVE_RUNNER" description:"Don't remove runner if registration fails"` 27 RegistrationToken string `short:"r" long:"registration-token" env:"REGISTRATION_TOKEN" description:"Runner's registration token"` 28 RunUntagged bool `long:"run-untagged" env:"REGISTER_RUN_UNTAGGED" description:"Register to run untagged builds; defaults to 'true' when 'tag-list' is empty"` 29 Locked bool `long:"locked" env:"REGISTER_LOCKED" description:"Lock Runner for current project, defaults to 'true'"` 30 MaximumTimeout int `long:"maximum-timeout" env:"REGISTER_MAXIMUM_TIMEOUT" description:"What is the maximum timeout (in seconds) that will be set for job when using this Runner"` 31 Paused bool `long:"paused" env:"REGISTER_PAUSED" description:"Set Runner to be paused, defaults to 'false'"` 32 33 common.RunnerConfig 34 } 35 36 func (s *RegisterCommand) askOnce(prompt string, result *string, allowEmpty bool) bool { 37 println(prompt) 38 if *result != "" { 39 print("["+*result, "]: ") 40 } 41 42 if s.reader == nil { 43 s.reader = bufio.NewReader(os.Stdin) 44 } 45 46 data, _, err := s.reader.ReadLine() 47 if err != nil { 48 panic(err) 49 } 50 newResult := string(data) 51 newResult = strings.TrimSpace(newResult) 52 53 if newResult != "" { 54 *result = newResult 55 return true 56 } 57 58 if allowEmpty || *result != "" { 59 return true 60 } 61 return false 62 } 63 64 func (s *RegisterCommand) ask(key, prompt string, allowEmptyOptional ...bool) string { 65 allowEmpty := len(allowEmptyOptional) > 0 && allowEmptyOptional[0] 66 67 result := s.context.String(key) 68 result = strings.TrimSpace(result) 69 70 if s.NonInteractive || prompt == "" { 71 if result == "" && !allowEmpty { 72 logrus.Panicln("The", key, "needs to be entered") 73 } 74 return result 75 } 76 77 for { 78 if s.askOnce(prompt, &result, allowEmpty) { 79 break 80 } 81 } 82 83 return result 84 } 85 86 func (s *RegisterCommand) askExecutor() { 87 for { 88 names := common.GetExecutors() 89 executors := strings.Join(names, ", ") 90 s.Executor = s.ask("executor", "Please enter the executor: "+executors+":", true) 91 if common.GetExecutor(s.Executor) != nil { 92 return 93 } 94 95 message := "Invalid executor specified" 96 if s.NonInteractive { 97 logrus.Panicln(message) 98 } else { 99 logrus.Errorln(message) 100 } 101 } 102 } 103 104 func (s *RegisterCommand) askDocker() { 105 if s.Docker == nil { 106 s.Docker = &common.DockerConfig{} 107 } 108 s.Docker.Image = s.ask("docker-image", "Please enter the default Docker image (e.g. ruby:2.1):") 109 110 for _, volume := range s.Docker.Volumes { 111 parts := strings.Split(volume, ":") 112 if parts[len(parts)-1] == "/cache" { 113 return 114 } 115 } 116 s.Docker.Volumes = append(s.Docker.Volumes, "/cache") 117 } 118 119 func (s *RegisterCommand) askParallels() { 120 s.Parallels.BaseName = s.ask("parallels-base-name", "Please enter the Parallels VM (e.g. my-vm):") 121 } 122 123 func (s *RegisterCommand) askVirtualBox() { 124 s.VirtualBox.BaseName = s.ask("virtualbox-base-name", "Please enter the VirtualBox VM (e.g. my-vm):") 125 } 126 127 func (s *RegisterCommand) askSSHServer() { 128 s.SSH.Host = s.ask("ssh-host", "Please enter the SSH server address (e.g. my.server.com):") 129 s.SSH.Port = s.ask("ssh-port", "Please enter the SSH server port (e.g. 22):", true) 130 } 131 132 func (s *RegisterCommand) askSSHLogin() { 133 s.SSH.User = s.ask("ssh-user", "Please enter the SSH user (e.g. root):") 134 s.SSH.Password = s.ask("ssh-password", "Please enter the SSH password (e.g. docker.io):", true) 135 s.SSH.IdentityFile = s.ask("ssh-identity-file", "Please enter path to SSH identity file (e.g. /home/user/.ssh/id_rsa):", true) 136 } 137 138 func (s *RegisterCommand) addRunner(runner *common.RunnerConfig) { 139 s.config.Runners = append(s.config.Runners, runner) 140 } 141 142 func (s *RegisterCommand) askRunner() { 143 s.URL = s.ask("url", "Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):") 144 145 if s.Token != "" { 146 logrus.Infoln("Token specified trying to verify runner...") 147 logrus.Warningln("If you want to register use the '-r' instead of '-t'.") 148 if !s.network.VerifyRunner(s.RunnerCredentials) { 149 logrus.Panicln("Failed to verify this runner. Perhaps you are having network problems") 150 } 151 } else { 152 // we store registration token as token, since we pass that to RunnerCredentials 153 s.Token = s.ask("registration-token", "Please enter the gitlab-ci token for this runner:") 154 s.Name = s.ask("name", "Please enter the gitlab-ci description for this runner:") 155 s.TagList = s.ask("tag-list", "Please enter the gitlab-ci tags for this runner (comma separated):", true) 156 157 if s.TagList == "" { 158 s.RunUntagged = true 159 } 160 161 parameters := common.RegisterRunnerParameters{ 162 Description: s.Name, 163 Tags: s.TagList, 164 Locked: s.Locked, 165 RunUntagged: s.RunUntagged, 166 MaximumTimeout: s.MaximumTimeout, 167 Active: !s.Paused, 168 } 169 170 result := s.network.RegisterRunner(s.RunnerCredentials, parameters) 171 if result == nil { 172 logrus.Panicln("Failed to register this runner. Perhaps you are having network problems") 173 } 174 175 s.Token = result.Token 176 s.registered = true 177 } 178 } 179 180 func (s *RegisterCommand) askExecutorOptions() { 181 kubernetes := s.Kubernetes 182 machine := s.Machine 183 docker := s.Docker 184 ssh := s.SSH 185 parallels := s.Parallels 186 virtualbox := s.VirtualBox 187 188 s.Kubernetes = nil 189 s.Machine = nil 190 s.Docker = nil 191 s.SSH = nil 192 s.Parallels = nil 193 s.VirtualBox = nil 194 195 switch s.Executor { 196 case "kubernetes": 197 s.Kubernetes = kubernetes 198 case "docker+machine": 199 s.Machine = machine 200 s.Docker = docker 201 s.askDocker() 202 case "docker-ssh+machine": 203 s.Machine = machine 204 s.Docker = docker 205 s.SSH = ssh 206 s.askDocker() 207 s.askSSHLogin() 208 case "docker": 209 s.Docker = docker 210 s.askDocker() 211 case "docker-ssh": 212 s.Docker = docker 213 s.SSH = ssh 214 s.askDocker() 215 s.askSSHLogin() 216 case "ssh": 217 s.SSH = ssh 218 s.askSSHServer() 219 s.askSSHLogin() 220 case "parallels": 221 s.SSH = ssh 222 s.Parallels = parallels 223 s.askParallels() 224 s.askSSHServer() 225 case "virtualbox": 226 s.SSH = ssh 227 s.VirtualBox = virtualbox 228 s.askVirtualBox() 229 s.askSSHLogin() 230 } 231 } 232 233 // DEPRECATED 234 // TODO: Remove in 12.0 235 // 236 // Writes cache configuration section using new syntax, even if 237 // old CLI options/env variables were used. 238 func (s *RegisterCommand) prepareCache() { 239 cache := s.RunnerConfig.Cache 240 if cache == nil { 241 return 242 } 243 244 // Called to log deprecated usage, if old cli options/env variables are used 245 cache.Path = cache.GetPath() 246 cache.Shared = cache.GetShared() 247 248 // Called to assign values and log deprecated usage, if old env variables are used 249 setStringIfUnset(&cache.S3.ServerAddress, cache.GetServerAddress()) 250 setStringIfUnset(&cache.S3.AccessKey, cache.GetAccessKey()) 251 setStringIfUnset(&cache.S3.SecretKey, cache.GetSecretKey()) 252 setStringIfUnset(&cache.S3.BucketName, cache.GetBucketName()) 253 setStringIfUnset(&cache.S3.BucketLocation, cache.GetBucketLocation()) 254 setBoolIfUnset(&cache.S3.Insecure, cache.GetInsecure()) 255 } 256 257 // TODO: Remove in 12.0 258 func setStringIfUnset(setting *string, newSetting string) { 259 if *setting != "" { 260 return 261 } 262 263 *setting = newSetting 264 } 265 266 // TODO: Remove in 12.0 267 func setBoolIfUnset(setting *bool, newSetting bool) { 268 if *setting { 269 return 270 } 271 272 *setting = newSetting 273 } 274 275 func (s *RegisterCommand) Execute(context *cli.Context) { 276 userModeWarning(true) 277 278 s.context = context 279 err := s.loadConfig() 280 if err != nil { 281 logrus.Panicln(err) 282 } 283 s.askRunner() 284 285 if !s.LeaveRunner { 286 defer func() { 287 // De-register runner on panic 288 if r := recover(); r != nil { 289 if s.registered { 290 s.network.UnregisterRunner(s.RunnerCredentials) 291 } 292 293 // pass panic to next defer 294 panic(r) 295 } 296 }() 297 298 signals := make(chan os.Signal, 1) 299 signal.Notify(signals, os.Interrupt) 300 301 go func() { 302 signal := <-signals 303 s.network.UnregisterRunner(s.RunnerCredentials) 304 logrus.Fatalf("RECEIVED SIGNAL: %v", signal) 305 }() 306 } 307 308 if s.config.Concurrent < s.Limit { 309 logrus.Warningf("Specified limit (%d) larger then current concurrent limit (%d). Concurrent limit will not be enlarged.", s.Limit, s.config.Concurrent) 310 } 311 312 s.askExecutor() 313 s.askExecutorOptions() 314 s.addRunner(&s.RunnerConfig) 315 s.prepareCache() 316 s.saveConfig() 317 318 logrus.Printf("Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!") 319 } 320 321 func getHostname() string { 322 hostname, _ := os.Hostname() 323 return hostname 324 } 325 326 func newRegisterCommand() *RegisterCommand { 327 return &RegisterCommand{ 328 RunnerConfig: common.RunnerConfig{ 329 Name: getHostname(), 330 RunnerSettings: common.RunnerSettings{ 331 Kubernetes: &common.KubernetesConfig{}, 332 Cache: &common.CacheConfig{}, 333 Machine: &common.DockerMachine{}, 334 Docker: &common.DockerConfig{}, 335 SSH: &ssh.Config{}, 336 Parallels: &common.ParallelsConfig{}, 337 VirtualBox: &common.VirtualBoxConfig{}, 338 }, 339 }, 340 Locked: true, 341 Paused: false, 342 network: network.NewGitLabClient(), 343 } 344 } 345 346 func init() { 347 common.RegisterCommand2("register", "register a new runner", newRegisterCommand()) 348 }