diff --git a/pkg/executor/push.go b/pkg/executor/push.go index 59d275d69..6508c7bd0 100644 --- a/pkg/executor/push.go +++ b/pkg/executor/push.go @@ -21,6 +21,8 @@ import ( "fmt" "io/ioutil" "net/http" + "os" + "strings" "time" "github.com/GoogleContainerTools/kaniko/pkg/cache" @@ -43,8 +45,16 @@ type withUserAgent struct { t http.RoundTripper } +const ( + UPSTREAM_CLIENT_UA_KEY = "UPSTREAM_CLIENT_TYPE" +) + func (w *withUserAgent) RoundTrip(r *http.Request) (*http.Response, error) { - r.Header.Set("User-Agent", fmt.Sprintf("kaniko/%s", version.Version())) + ua := []string{fmt.Sprintf("kaniko/%s", version.Version())} + if upstream := os.Getenv(UPSTREAM_CLIENT_UA_KEY); upstream != "" { + ua = append(ua, upstream) + } + r.Header.Set("User-Agent", strings.Join(ua, ",")) return w.t.RoundTrip(r) } diff --git a/pkg/executor/push_test.go b/pkg/executor/push_test.go new file mode 100644 index 000000000..2f9729960 --- /dev/null +++ b/pkg/executor/push_test.go @@ -0,0 +1,71 @@ +/* +Copyright 2018 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package executor + +import ( + "bytes" + "io/ioutil" + "net/http" + "os" + "testing" + + "github.com/GoogleContainerTools/kaniko/testutil" +) + +func TestHeaderAdded(t *testing.T) { + tests := []struct { + name string + upstream string + expected string + }{{ + name: "upstream env variable set", + upstream: "skaffold-v0.25.45", + expected: "kaniko/unset,skaffold-v0.25.45", + }, { + name: "upstream env variable not set", + expected: "kaniko/unset", + }, + } + for _, test := range tests { + + t.Run(test.name, func(t *testing.T) { + rt := &withUserAgent{t: &mockRoundTripper{}} + if test.upstream != "" { + os.Setenv("UPSTREAM_CLIENT_TYPE", test.upstream) + defer func() { os.Unsetenv("UPSTREAM_CLIENT_TYPE") }() + } + req, err := http.NewRequest("GET", "dummy", nil) + if err != nil { + t.Fatalf("culd not create a req due to %s", err) + } + resp, err := rt.RoundTrip(req) + testutil.CheckError(t, false, err) + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + testutil.CheckErrorAndDeepEqual(t, false, err, test.expected, string(body)) + }) + } + +} + +type mockRoundTripper struct { +} + +func (m *mockRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { + ua := r.UserAgent() + return &http.Response{Body: ioutil.NopCloser(bytes.NewBufferString(ua))}, nil +}