From 846a90683409bfa3a4cf3f9dcc97ff9ccf2b687e Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Thu, 12 Jan 2017 09:42:43 +0400 Subject: [PATCH] initial support yaml transform extensions --- agent/agent.go | 4 +++ drone/agent/agent.go | 6 ++++ drone/agent/exec.go | 2 ++ yaml/transform/rpc.go | 43 +++++++++++++++++++++++++ yaml/transform/rpc_test.go | 64 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 yaml/transform/rpc.go create mode 100644 yaml/transform/rpc_test.go diff --git a/agent/agent.go b/agent/agent.go index 4f1e5fc97..c39aa2573 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -28,6 +28,7 @@ type Agent struct { Timeout time.Duration Platform string Namespace string + Extension string Disable []string Escalate []string Netrc []string @@ -169,6 +170,9 @@ func (a *Agent) prep(w *model.Work) (*yaml.Config, error) { } transform.Pod(conf, a.Platform) + if err := transform.RemoteTransform(conf, a.Extension); err != nil { + return nil, err + } return conf, nil } diff --git a/drone/agent/agent.go b/drone/agent/agent.go index 30f8acaef..a41c87ff7 100644 --- a/drone/agent/agent.go +++ b/drone/agent/agent.go @@ -133,6 +133,11 @@ var AgentCmd = cli.Command{ Name: "pull", Usage: "always pull latest plugin images", }, + cli.StringFlag{ + EnvVar: "DRONE_YAML_EXTENSION", + Name: "extension", + Usage: "custom plugin extension endpoint", + }, }, } @@ -192,6 +197,7 @@ func start(c *cli.Context) { privileged: c.StringSlice("privileged"), pull: c.BoolT("pull"), logs: int64(c.Int("max-log-size")) * 1000000, + extension: c.String("extension"), }, } diff --git a/drone/agent/exec.go b/drone/agent/exec.go index 7ad0b458c..895e6522c 100644 --- a/drone/agent/exec.go +++ b/drone/agent/exec.go @@ -19,6 +19,7 @@ type config struct { pull bool logs int64 timeout time.Duration + extension string } type pipeline struct { @@ -47,6 +48,7 @@ func (r *pipeline) run(w *model.Work) { Platform: r.config.platform, Namespace: r.config.namespace, Escalate: r.config.privileged, + Extension: r.config.extension, Pull: r.config.pull, } diff --git a/yaml/transform/rpc.go b/yaml/transform/rpc.go new file mode 100644 index 000000000..852cac138 --- /dev/null +++ b/yaml/transform/rpc.go @@ -0,0 +1,43 @@ +package transform + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + "github.com/drone/drone/yaml" +) + +// RemoteTransform makes remote transform requests. +func RemoteTransform(c *yaml.Config, url string) error { + if url == "" { + return nil + } + + var buf bytes.Buffer + + // encode yaml in json format + if err := json.NewEncoder(&buf).Encode(c); err != nil { + return err + } + resp, err := http.Post(url, "application/json", &buf) + if err != nil { + return err + } + defer resp.Body.Close() + + // decode the updated yaml from the body + if resp.StatusCode == 200 { + err = json.NewDecoder(resp.Body).Decode(c) + return err + } + + // handle error response + out, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + return fmt.Errorf(string(out)) +} diff --git a/yaml/transform/rpc_test.go b/yaml/transform/rpc_test.go new file mode 100644 index 000000000..12e0ce8ad --- /dev/null +++ b/yaml/transform/rpc_test.go @@ -0,0 +1,64 @@ +package transform + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/drone/drone/yaml" + "github.com/franela/goblin" +) + +func handleNetrcRemoval(w http.ResponseWriter, r *http.Request) { + c := new(yaml.Config) + err := json.NewDecoder(r.Body).Decode(c) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + for _, container := range c.Pipeline { + if strings.HasPrefix(container.Image, "plugins/git") { + continue + } + container.Environment["DRONE_NETRC_USERNAME"] = "" + container.Environment["DRONE_NETRC_PASSWORD"] = "" + container.Environment["DRONE_NETRC_MACHINE"] = "" + } + json.NewEncoder(w).Encode(c) +} + +func Test_rpc_transform(t *testing.T) { + g := goblin.Goblin(t) + g.Describe("rpc transform", func() { + + g.It("should mutate the yaml", func() { + c := newConfig(&yaml.Container{ + Image: "golang", + Environment: map[string]string{ + "DRONE_NETRC_USERNAME": "foo", + "DRONE_NETRC_PASSWORD": "bar", + "DRONE_BRANCH": "master", + }, + Commands: []string{ + "go build", + "go test", + }, + }) + + server := httptest.NewServer(http.HandlerFunc(handleNetrcRemoval)) + defer server.Close() + + err := RemoteTransform(c, server.URL) + g.Assert(err == nil).IsTrue() + g.Assert(c.Pipeline[0].Image).Equal("golang") + g.Assert(c.Pipeline[0].Environment["DRONE_BRANCH"]).Equal("master") + g.Assert(c.Pipeline[0].Environment["DRONE_NETRC_USERNAME"]).Equal("") + g.Assert(c.Pipeline[0].Environment["DRONE_NETRC_PASSWORD"]).Equal("") + g.Assert(c.Pipeline[0].Commands[0]).Equal("go build") + g.Assert(c.Pipeline[0].Commands[1]).Equal("go test") + }) + }) +}