package main import ( "os" "os/exec" "strconv" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) type pluginConfig struct { check_syntax bool check bool diff bool verbosity int64 limit *string tags *string privateKey *string vaultToken *string galaxyFile *string playbook *string } func runCommand(sugar *zap.SugaredLogger, args ...string) { sugar.Infof("➡️ %s", args) cmd := exec.Command(args[0], args[1:]...) cmd.Env = os.Environ() cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { os.Exit(1) } } func getPluginConfig(sugar *zap.SugaredLogger) pluginConfig { config := pluginConfig{} check_syntax, present := os.LookupEnv("PLUGIN_CHECK_SYNTAX") if !present { config.check_syntax = false } else { converted, err := strconv.ParseBool(check_syntax) if err != nil { sugar.Fatal(err) } config.check_syntax = converted } check, present := os.LookupEnv("PLUGIN_CHECK") if !present { config.check = false } else { converted, err := strconv.ParseBool(check) if err != nil { sugar.Fatal(err) } config.check = converted } diff, present := os.LookupEnv("PLUGIN_DIFF") if !present { config.diff = false } else { converted, err := strconv.ParseBool(diff) if err != nil { sugar.Fatal(err) } config.diff = converted } verbosity, present := os.LookupEnv("PLUGIN_VERBOSITY") if !present { config.verbosity = 0 } else { converted, err := strconv.ParseInt(verbosity, 10, 0) if err != nil { sugar.Fatal(err) } config.verbosity = converted } limit, present := os.LookupEnv("PLUGIN_LIMIT") if !present { config.limit = nil } else { config.limit = &limit } tags, present := os.LookupEnv("PLUGIN_TAGS") if !present { config.tags = nil } else { config.tags = &tags } privateKey, present := os.LookupEnv("PLUGIN_PRIVATE_KEY") if !present { sugar.Warn("⚠️ 'private_key' setting not defined !") config.privateKey = nil } else { config.privateKey = &privateKey } vaultToken, present := os.LookupEnv("PLUGIN_VAULT_TOKEN") if !present { config.vaultToken = nil } else { config.vaultToken = &vaultToken } galaxyFile, present := os.LookupEnv("PLUGIN_GALAXY_FILE") if !present { config.galaxyFile = nil } else { config.galaxyFile = &galaxyFile } playbook, present := os.LookupEnv("PLUGIN_PLAYBOOK") if !present { sugar.Fatal("⚠️ 'playbook' setting not defined, ABORT!") } else { config.playbook = &playbook } return config } func main() { // encoderConfig := zapcore.EncoderConfig{ // MessageKey: "message", // LevelKey: "level", // EncodeLevel: zapcore.CapitalColorLevelEncoder, // EncodeDuration: zapcore.StringDurationEncoder, // EncodeCaller: zapcore.ShortCallerEncoder, // } // encoder := zapcore.NewConsoleEncoder(encoderConfig) // core := zapcore.NewCore(encoder, os.Stdout, zapcore.InfoLevel) config := zap.NewProductionConfig() config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder config.EncoderConfig.TimeKey = "" config.Encoding = "console" config.DisableCaller = true config.DisableStacktrace = true logger, _ := config.Build() defer logger.Sync() sugar := logger.Sugar() sugar.Info("Woodpecker Ansible Runner") pluginConfig := getPluginConfig(sugar) if pluginConfig.privateKey != nil { runCommand(sugar, "mkdir", "/root/.ssh") err := os.WriteFile("/root/.ssh/id_ed25519", []byte(*pluginConfig.privateKey), 0400) if err != nil { sugar.Fatal(err) } } args := []string{*pluginConfig.playbook} if pluginConfig.vaultToken != nil { sugar.Info("💼 Adding vault token to 'credentials/ci_vault_token'") runCommand(sugar, "mkdir", "credentials") err := os.WriteFile("credentials/ci_vault_token", []byte(*pluginConfig.vaultToken), 0644) if err != nil { sugar.Fatal(err) } args = append(args, "--vault-password-file=credentials/ci_vault_token") sugar.Info("⚙️ Clean ansible.cfg") runCommand(sugar, "sed", "-i", "/vault_password_file.*/d", "./ansible.cfg") } if _, err := os.Stat("ansible-ci.cfg"); err == nil { sugar.Info("⚙️ ansible-ci.cfg is present, using it.") os.Remove("ansible.cfg") os.Rename("ansible-ci.cfg", "ansible.cfg") } if pluginConfig.galaxyFile != nil { sugar.Infof("🚀 Installing Galaxy dependencies (%s)", *pluginConfig.galaxyFile) runCommand(sugar, "ansible-galaxy", "install", "-r", *pluginConfig.galaxyFile, "--force") } if pluginConfig.check_syntax { args = append(args, "--syntax-check") } if pluginConfig.check { args = append(args, "--check") } if pluginConfig.diff { args = append(args, "--diff") } if pluginConfig.verbosity != 0 { verb := "-" for i := 0; i < int(pluginConfig.verbosity); i++ { verb += "v" } args = append(args, verb) } if pluginConfig.limit != nil { args = append(args, "--limit", *pluginConfig.limit) } if pluginConfig.tags != nil { args = append(args, "--tags", *pluginConfig.tags) } // runCommand(sugar, "export", "ANSIBLE_HOST_KEY_CHECKING=False") command := append([]string{"ansible-playbook"}, args...) runCommand(sugar, command...) }