<commit_before>package oauth2

import (
	"net/http"
	"net/http/httptest"
	"regexp"
	"testing"

	. "github.com/stretchr/testify/assert"
	"github.com/tarent/loginsrv/model"
)

var gitlabTestUserResponse = `{
	"id": 1,
	"username": "john_smith",
	"email": "john@example.com",
	"name": "John Smith",
	"state": "active",
	"avatar_url": "http://localhost:3000/uploads/user/avatar/1/index.jpg",
	"web_url": "http://localhost:3000/john_smith",
	"created_at": "2012-05-23T08:00:58Z",
	"bio": null,
	"location": null,
	"public_email": "john@example.com",
	"skype": "",
	"linkedin": "",
	"twitter": "",
	"website_url": "",
	"organization": "",
	"last_sign_in_at": "2012-06-01T11:41:01Z",
	"confirmed_at": "2012-05-23T09:05:22Z",
	"theme_id": 1,
	"last_activity_on": "2012-05-23",
	"color_scheme_id": 2,
	"projects_limit": 100,
	"current_sign_in_at": "2012-06-02T06:36:55Z",
	"identities": [
	  {"provider": "github", "extern_uid": "2435223452345"},
	  {"provider": "bitbucket", "extern_uid": "john_smith"},
	  {"provider": "google_oauth2", "extern_uid": "8776128412476123468721346"}
	],
	"can_create_group": true,
	"can_create_project": true,
	"two_factor_enabled": true,
	"external": false,
	"private_profile": false
  }`

var gitlabTestGroupsResponse = `[
	{
	  "id": 1,
	  "web_url": "https://gitlab.com/groups/example",
	  "name": "example",
	  "path": "example",
	  "description": "",
	  "visibility": "private",
	  "lfs_enabled": true,
	  "avatar_url": null,
	  "request_access_enabled": true,
	  "full_name": "example",
	  "full_path": "example",
	  "parent_id": null,
	  "ldap_cn": null,
	  "ldap_access": null
	},
	{
		"id": 2,
		"web_url": "https://gitlab.com/groups/example/subgroup",
		"name": "subgroup",
		"path": "subgroup",
		"description": "",
		"visibility": "private",
		"lfs_enabled": true,
		"avatar_url": null,
		"request_access_enabled": true,
		"full_name": "example / subgroup",
		"full_path": "example/subgroup",
		"parent_id": null,
		"ldap_cn": null,
		"ldap_access": null
	}
]`

func Test_Gitlab_getUserInfo(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestUserResponse))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestGroupsResponse))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	NoError(t, err)
	Equal(t, "john_smith", u.Sub)
	Equal(t, "john@example.com", u.Email)
	Equal(t, "John Smith", u.Name)
	Equal(t, []string{"example", "example/subgroup"}, u.Groups)
	Equal(t, `{"user":`+gitlabTestUserResponse+`,"groups":`+gitlabTestGroupsResponse+`}`, rawJSON)
}

func Test_Gitlab_getUserInfo_NoServer(t *testing.T) {
	gitlabAPI = "http://localhost"

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`connection refused$`), err.Error())
}

func Test_Gitlab_getUserInfo_UserContentTypeNegative(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			w.Write([]byte(gitlabTestUserResponse))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestGroupsResponse))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`^wrong content-type on gitlab get user info`), err.Error())
}

func Test_Gitlab_getUserInfo_GroupsContentTypeNegative(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestUserResponse))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			w.Write([]byte(gitlabTestGroupsResponse))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`^wrong content-type on gitlab get groups info`), err.Error())
}

func Test_Gitlab_getUserInfo_UserStatusCodeNegative(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(gitlabTestUserResponse))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestGroupsResponse))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`^got http status [0-9]{3} on gitlab get user info`), err.Error())
}

func Test_Gitlab_getUserInfo_GroupsStatusCodeNegative(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestUserResponse))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(gitlabTestGroupsResponse))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`^got http status [0-9]{3} on gitlab get groups info`), err.Error())
}

func Test_Gitlab_getUserInfo_UserJSONNegative(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte("[]"))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestGroupsResponse))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`^error parsing gitlab get user info`), err.Error())
}

func Test_Gitlab_getUserInfo_GroupsJSONNegative(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestUserResponse))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte("{}"))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`^error parsing gitlab get groups info`), err.Error())
}
<commit_msg>test: fix Test_Gitlab_getUserInfo_NoServer on Windows<commit_after>package oauth2

import (
	"net/http"
	"net/http/httptest"
	"regexp"
	"testing"

	. "github.com/stretchr/testify/assert"
	"github.com/tarent/loginsrv/model"
)

var gitlabTestUserResponse = `{
	"id": 1,
	"username": "john_smith",
	"email": "john@example.com",
	"name": "John Smith",
	"state": "active",
	"avatar_url": "http://localhost:3000/uploads/user/avatar/1/index.jpg",
	"web_url": "http://localhost:3000/john_smith",
	"created_at": "2012-05-23T08:00:58Z",
	"bio": null,
	"location": null,
	"public_email": "john@example.com",
	"skype": "",
	"linkedin": "",
	"twitter": "",
	"website_url": "",
	"organization": "",
	"last_sign_in_at": "2012-06-01T11:41:01Z",
	"confirmed_at": "2012-05-23T09:05:22Z",
	"theme_id": 1,
	"last_activity_on": "2012-05-23",
	"color_scheme_id": 2,
	"projects_limit": 100,
	"current_sign_in_at": "2012-06-02T06:36:55Z",
	"identities": [
	  {"provider": "github", "extern_uid": "2435223452345"},
	  {"provider": "bitbucket", "extern_uid": "john_smith"},
	  {"provider": "google_oauth2", "extern_uid": "8776128412476123468721346"}
	],
	"can_create_group": true,
	"can_create_project": true,
	"two_factor_enabled": true,
	"external": false,
	"private_profile": false
  }`

var gitlabTestGroupsResponse = `[
	{
	  "id": 1,
	  "web_url": "https://gitlab.com/groups/example",
	  "name": "example",
	  "path": "example",
	  "description": "",
	  "visibility": "private",
	  "lfs_enabled": true,
	  "avatar_url": null,
	  "request_access_enabled": true,
	  "full_name": "example",
	  "full_path": "example",
	  "parent_id": null,
	  "ldap_cn": null,
	  "ldap_access": null
	},
	{
		"id": 2,
		"web_url": "https://gitlab.com/groups/example/subgroup",
		"name": "subgroup",
		"path": "subgroup",
		"description": "",
		"visibility": "private",
		"lfs_enabled": true,
		"avatar_url": null,
		"request_access_enabled": true,
		"full_name": "example / subgroup",
		"full_path": "example/subgroup",
		"parent_id": null,
		"ldap_cn": null,
		"ldap_access": null
	}
]`

func Test_Gitlab_getUserInfo(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestUserResponse))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestGroupsResponse))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	NoError(t, err)
	Equal(t, "john_smith", u.Sub)
	Equal(t, "john@example.com", u.Email)
	Equal(t, "John Smith", u.Name)
	Equal(t, []string{"example", "example/subgroup"}, u.Groups)
	Equal(t, `{"user":`+gitlabTestUserResponse+`,"groups":`+gitlabTestGroupsResponse+`}`, rawJSON)
}

func Test_Gitlab_getUserInfo_NoServer(t *testing.T) {
	gitlabAPI = "http://localhost:1234"

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`(connection refused$)|(actively refused it.$)`), err.Error())
}

func Test_Gitlab_getUserInfo_UserContentTypeNegative(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			w.Write([]byte(gitlabTestUserResponse))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestGroupsResponse))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`^wrong content-type on gitlab get user info`), err.Error())
}

func Test_Gitlab_getUserInfo_GroupsContentTypeNegative(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestUserResponse))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "text/plain; charset=utf-8")
			w.Write([]byte(gitlabTestGroupsResponse))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`^wrong content-type on gitlab get groups info`), err.Error())
}

func Test_Gitlab_getUserInfo_UserStatusCodeNegative(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(gitlabTestUserResponse))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestGroupsResponse))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`^got http status [0-9]{3} on gitlab get user info`), err.Error())
}

func Test_Gitlab_getUserInfo_GroupsStatusCodeNegative(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestUserResponse))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(gitlabTestGroupsResponse))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`^got http status [0-9]{3} on gitlab get groups info`), err.Error())
}

func Test_Gitlab_getUserInfo_UserJSONNegative(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte("[]"))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestGroupsResponse))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`^error parsing gitlab get user info`), err.Error())
}

func Test_Gitlab_getUserInfo_GroupsJSONNegative(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/user" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte(gitlabTestUserResponse))
		} else if r.URL.Path == "/groups" {
			Equal(t, "secret", r.FormValue("access_token"))
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			w.Write([]byte("{}"))
		}
	}))
	defer server.Close()

	gitlabAPI = server.URL

	u, rawJSON, err := providerGitlab.GetUserInfo(TokenInfo{AccessToken: "secret"})
	Equal(t, model.UserInfo{}, u)
	Empty(t, rawJSON)
	Error(t, err)
	Regexp(t, regexp.MustCompile(`^error parsing gitlab get groups info`), err.Error())
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative Authors

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 route

import (
	"context"

	kubeclient "knative.dev/pkg/client/injection/kube/client"
	serviceinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/service"
	servingclient "knative.dev/serving/pkg/client/injection/client"
	certificateinformer "knative.dev/serving/pkg/client/injection/informers/networking/v1alpha1/certificate"
	ingressinformer "knative.dev/serving/pkg/client/injection/informers/networking/v1alpha1/ingress"
	configurationinformer "knative.dev/serving/pkg/client/injection/informers/serving/v1/configuration"
	revisioninformer "knative.dev/serving/pkg/client/injection/informers/serving/v1/revision"
	routeinformer "knative.dev/serving/pkg/client/injection/informers/serving/v1/route"
	routereconciler "knative.dev/serving/pkg/client/injection/reconciler/serving/v1/route"

	"k8s.io/client-go/tools/cache"
	"knative.dev/pkg/configmap"
	"knative.dev/pkg/controller"
	"knative.dev/pkg/logging"
	"knative.dev/pkg/system"
	"knative.dev/pkg/tracker"
	v1 "knative.dev/serving/pkg/apis/serving/v1"
	"knative.dev/serving/pkg/network"
	servingreconciler "knative.dev/serving/pkg/reconciler"
	"knative.dev/serving/pkg/reconciler/route/config"
)

const controllerAgentName = "route-controller"

// NewController initializes the controller and is called by the generated code
// Registers eventhandlers to enqueue events
func NewController(
	ctx context.Context,
	cmw configmap.Watcher,
) *controller.Impl {
	return newControllerWithClock(ctx, cmw, system.RealClock{})
}

type reconcilerOption func(*Reconciler)

func newControllerWithClock(
	ctx context.Context,
	cmw configmap.Watcher,
	clock system.Clock,
	opts ...reconcilerOption,
) *controller.Impl {
	ctx = servingreconciler.AnnotateLoggerWithName(ctx, controllerAgentName)
	logger := logging.FromContext(ctx)
	serviceInformer := serviceinformer.Get(ctx)
	routeInformer := routeinformer.Get(ctx)
	configInformer := configurationinformer.Get(ctx)
	revisionInformer := revisioninformer.Get(ctx)
	ingressInformer := ingressinformer.Get(ctx)
	certificateInformer := certificateinformer.Get(ctx)

	// No need to lock domainConfigMutex yet since the informers that can modify
	// domainConfig haven't started yet.
	c := &Reconciler{
		kubeclient:          kubeclient.Get(ctx),
		client:              servingclient.Get(ctx),
		configurationLister: configInformer.Lister(),
		revisionLister:      revisionInformer.Lister(),
		serviceLister:       serviceInformer.Lister(),
		ingressLister:       ingressInformer.Lister(),
		certificateLister:   certificateInformer.Lister(),
		clock:               clock,
	}
	impl := routereconciler.NewImpl(ctx, c, func(impl *controller.Impl) controller.Options {
		configsToResync := []interface{}{
			&network.Config{},
			&config.Domain{},
		}
		resync := configmap.TypeFilter(configsToResync...)(func(string, interface{}) {
			impl.GlobalResync(routeInformer.Informer())
		})
		configStore := config.NewStore(logging.WithLogger(ctx, logger.Named("config-store")), resync)
		configStore.WatchConfigs(cmw)
		return controller.Options{ConfigStore: configStore}
	})

	logger.Info("Setting up event handlers")
	routeInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue))

	serviceInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
		FilterFunc: controller.FilterGroupKind(v1.Kind("Route")),
		Handler:    controller.HandleAll(impl.EnqueueControllerOf),
	})

	ingressInformer.Informer().AddEventHandler(controller.HandleAll(impl.EnqueueControllerOf))

	c.tracker = tracker.New(impl.EnqueueKey, controller.GetTrackerLease(ctx))

	configInformer.Informer().AddEventHandler(controller.HandleAll(
		// Call the tracker's OnChanged method, but we've seen the objects
		// coming through this path missing TypeMeta, so ensure it is properly
		// populated.
		controller.EnsureTypeMeta(
			c.tracker.OnChanged,
			v1.SchemeGroupVersion.WithKind("Configuration"),
		),
	))

	revisionInformer.Informer().AddEventHandler(controller.HandleAll(
		// Call the tracker's OnChanged method, but we've seen the objects
		// coming through this path missing TypeMeta, so ensure it is properly
		// populated.
		controller.EnsureTypeMeta(
			c.tracker.OnChanged,
			v1.SchemeGroupVersion.WithKind("Revision"),
		),
	))

	certificateInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
		FilterFunc: controller.FilterGroupKind(v1.Kind("Route")),
		Handler:    controller.HandleAll(impl.EnqueueControllerOf),
	})

	for _, opt := range opts {
		opt(c)
	}
	return impl
}
<commit_msg>Remove outdated comment from route controller. (#7688)<commit_after>/*
Copyright 2019 The Knative Authors

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 route

import (
	"context"

	kubeclient "knative.dev/pkg/client/injection/kube/client"
	serviceinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/service"
	servingclient "knative.dev/serving/pkg/client/injection/client"
	certificateinformer "knative.dev/serving/pkg/client/injection/informers/networking/v1alpha1/certificate"
	ingressinformer "knative.dev/serving/pkg/client/injection/informers/networking/v1alpha1/ingress"
	configurationinformer "knative.dev/serving/pkg/client/injection/informers/serving/v1/configuration"
	revisioninformer "knative.dev/serving/pkg/client/injection/informers/serving/v1/revision"
	routeinformer "knative.dev/serving/pkg/client/injection/informers/serving/v1/route"
	routereconciler "knative.dev/serving/pkg/client/injection/reconciler/serving/v1/route"

	"k8s.io/client-go/tools/cache"
	"knative.dev/pkg/configmap"
	"knative.dev/pkg/controller"
	"knative.dev/pkg/logging"
	"knative.dev/pkg/system"
	"knative.dev/pkg/tracker"
	v1 "knative.dev/serving/pkg/apis/serving/v1"
	"knative.dev/serving/pkg/network"
	servingreconciler "knative.dev/serving/pkg/reconciler"
	"knative.dev/serving/pkg/reconciler/route/config"
)

const controllerAgentName = "route-controller"

// NewController initializes the controller and is called by the generated code
// Registers eventhandlers to enqueue events
func NewController(
	ctx context.Context,
	cmw configmap.Watcher,
) *controller.Impl {
	return newControllerWithClock(ctx, cmw, system.RealClock{})
}

type reconcilerOption func(*Reconciler)

func newControllerWithClock(
	ctx context.Context,
	cmw configmap.Watcher,
	clock system.Clock,
	opts ...reconcilerOption,
) *controller.Impl {
	ctx = servingreconciler.AnnotateLoggerWithName(ctx, controllerAgentName)
	logger := logging.FromContext(ctx)
	serviceInformer := serviceinformer.Get(ctx)
	routeInformer := routeinformer.Get(ctx)
	configInformer := configurationinformer.Get(ctx)
	revisionInformer := revisioninformer.Get(ctx)
	ingressInformer := ingressinformer.Get(ctx)
	certificateInformer := certificateinformer.Get(ctx)

	c := &Reconciler{
		kubeclient:          kubeclient.Get(ctx),
		client:              servingclient.Get(ctx),
		configurationLister: configInformer.Lister(),
		revisionLister:      revisionInformer.Lister(),
		serviceLister:       serviceInformer.Lister(),
		ingressLister:       ingressInformer.Lister(),
		certificateLister:   certificateInformer.Lister(),
		clock:               clock,
	}
	impl := routereconciler.NewImpl(ctx, c, func(impl *controller.Impl) controller.Options {
		configsToResync := []interface{}{
			&network.Config{},
			&config.Domain{},
		}
		resync := configmap.TypeFilter(configsToResync...)(func(string, interface{}) {
			impl.GlobalResync(routeInformer.Informer())
		})
		configStore := config.NewStore(logging.WithLogger(ctx, logger.Named("config-store")), resync)
		configStore.WatchConfigs(cmw)
		return controller.Options{ConfigStore: configStore}
	})

	logger.Info("Setting up event handlers")
	routeInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue))

	serviceInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
		FilterFunc: controller.FilterGroupKind(v1.Kind("Route")),
		Handler:    controller.HandleAll(impl.EnqueueControllerOf),
	})

	ingressInformer.Informer().AddEventHandler(controller.HandleAll(impl.EnqueueControllerOf))

	c.tracker = tracker.New(impl.EnqueueKey, controller.GetTrackerLease(ctx))

	configInformer.Informer().AddEventHandler(controller.HandleAll(
		// Call the tracker's OnChanged method, but we've seen the objects
		// coming through this path missing TypeMeta, so ensure it is properly
		// populated.
		controller.EnsureTypeMeta(
			c.tracker.OnChanged,
			v1.SchemeGroupVersion.WithKind("Configuration"),
		),
	))

	revisionInformer.Informer().AddEventHandler(controller.HandleAll(
		// Call the tracker's OnChanged method, but we've seen the objects
		// coming through this path missing TypeMeta, so ensure it is properly
		// populated.
		controller.EnsureTypeMeta(
			c.tracker.OnChanged,
			v1.SchemeGroupVersion.WithKind("Revision"),
		),
	))

	certificateInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
		FilterFunc: controller.FilterGroupKind(v1.Kind("Route")),
		Handler:    controller.HandleAll(impl.EnqueueControllerOf),
	})

	for _, opt := range opts {
		opt(c)
	}
	return impl
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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 ebtables

import (
	"strings"
	"testing"

	"k8s.io/kubernetes/pkg/util/exec"
)

func testEnsureChain(t *testing.T) {
	fcmd := exec.FakeCmd{
		CombinedOutputScript: []exec.FakeCombinedOutputAction{
			// Does not Exists
			func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
			// Success
			func() ([]byte, error) { return []byte{}, nil },
			// Exists
			func() ([]byte, error) { return nil, nil },
			// Does not Exists
			func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
			// Fail to create chain
			func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 2} },
		},
	}
	fexec := exec.FakeExec{
		CommandScript: []exec.FakeCommandAction{
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
		},
	}

	runner := New(&fexec)
	exists, err := runner.EnsureChain(TableFilter, "TEST-CHAIN")
	if exists {
		t.Errorf("expected exists = false")
	}
	if err != nil {
		t.Errorf("expected err = nil")
	}

	exists, err = runner.EnsureChain(TableFilter, "TEST-CHAIN")
	if !exists {
		t.Errorf("expected exists = true")
	}
	if err != nil {
		t.Errorf("expected err = nil")
	}

	exists, err = runner.EnsureChain(TableFilter, "TEST-CHAIN")
	if exists {
		t.Errorf("expected exists = false")
	}
	errStr := "Failed to ensure TEST-CHAIN chain: exit 2, output:"
	if err == nil || !strings.Contains(err.Error(), errStr) {
		t.Errorf("expected error: %q", errStr)
	}
}

func testEnsureRule(t *testing.T) {
	fcmd := exec.FakeCmd{
		CombinedOutputScript: []exec.FakeCombinedOutputAction{
			// Exists
			func() ([]byte, error) {
				return []byte(`Bridge table: filter

Bridge chain: OUTPUT, entries: 4, policy: ACCEPT
-j TEST
`), nil
			},
			// Does not Exists.
			func() ([]byte, error) {
				return []byte(`Bridge table: filter

Bridge chain: TEST, entries: 0, policy: ACCEPT`), nil
			},
			// Fail to create
			func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 2} },
		},
	}
	fexec := exec.FakeExec{
		CommandScript: []exec.FakeCommandAction{
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
		},
	}

	runner := New(&fexec)

	exists, err := runner.EnsureRule(Append, TableFilter, ChainOutput, "-j", "TEST")
	if !exists {
		t.Errorf("expected exists = true")
	}
	if err != nil {
		t.Errorf("expected err = nil")
	}

	exists, err = runner.EnsureRule(Append, TableFilter, ChainOutput, "-j", "NEXT-TEST")
	if exists {
		t.Errorf("expected exists = false")
	}
	errStr := "Failed to ensure rule: exist 2, output: "
	if err == nil || err.Error() != errStr {
		t.Errorf("expected error: %q", errStr)
	}
}
<commit_msg>Fix ebtables_test.go to actually get run, and to pass<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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 ebtables

import (
	"strings"
	"testing"

	"k8s.io/kubernetes/pkg/util/exec"
)

func TestEnsureChain(t *testing.T) {
	fcmd := exec.FakeCmd{
		CombinedOutputScript: []exec.FakeCombinedOutputAction{
			// Does not Exists
			func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
			// Success
			func() ([]byte, error) { return []byte{}, nil },
			// Exists
			func() ([]byte, error) { return nil, nil },
			// Does not Exists
			func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 1} },
			// Fail to create chain
			func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 2} },
		},
	}
	fexec := exec.FakeExec{
		CommandScript: []exec.FakeCommandAction{
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
		},
	}

	runner := New(&fexec)
	exists, err := runner.EnsureChain(TableFilter, "TEST-CHAIN")
	if exists {
		t.Errorf("expected exists = false")
	}
	if err != nil {
		t.Errorf("expected err = nil")
	}

	exists, err = runner.EnsureChain(TableFilter, "TEST-CHAIN")
	if !exists {
		t.Errorf("expected exists = true")
	}
	if err != nil {
		t.Errorf("expected err = nil")
	}

	exists, err = runner.EnsureChain(TableFilter, "TEST-CHAIN")
	if exists {
		t.Errorf("expected exists = false")
	}
	errStr := "Failed to ensure TEST-CHAIN chain: exit 2, output:"
	if err == nil || !strings.Contains(err.Error(), errStr) {
		t.Errorf("expected error: %q", errStr)
	}
}

func TestEnsureRule(t *testing.T) {
	fcmd := exec.FakeCmd{
		CombinedOutputScript: []exec.FakeCombinedOutputAction{
			// Exists
			func() ([]byte, error) {
				return []byte(`Bridge table: filter

Bridge chain: OUTPUT, entries: 4, policy: ACCEPT
-j TEST
`), nil
			},
			// Does not Exists.
			func() ([]byte, error) {
				return []byte(`Bridge table: filter

Bridge chain: TEST, entries: 0, policy: ACCEPT`), nil
			},
			// Fail to create
			func() ([]byte, error) { return nil, &exec.FakeExitError{Status: 2} },
		},
	}
	fexec := exec.FakeExec{
		CommandScript: []exec.FakeCommandAction{
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
			func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
		},
	}

	runner := New(&fexec)

	exists, err := runner.EnsureRule(Append, TableFilter, ChainOutput, "-j", "TEST")
	if !exists {
		t.Errorf("expected exists = true")
	}
	if err != nil {
		t.Errorf("expected err = nil")
	}

	exists, err = runner.EnsureRule(Append, TableFilter, ChainOutput, "-j", "NEXT-TEST")
	if exists {
		t.Errorf("expected exists = false")
	}
	errStr := "Failed to ensure rule: exit 2, output: "
	if err == nil || err.Error() != errStr {
		t.Errorf("expected error: %q", errStr)
	}
}
<|endoftext|>


<commit_before>package opentracing

import (
	"log"
	"os"

	basictracer "github.com/opentracing/basictracer-go"
	opentracing "github.com/opentracing/opentracing-go"
	"sourcegraph.com/sourcegraph/appdash"
)

var _ opentracing.Tracer = NewTracer(nil) // Compile time check.

// Options defines options for a Tracer.
type Options struct {
	// ShouldSample is a function that allows deterministic sampling of a trace
	// using the randomly generated Trace ID. The decision is made when a new Trace
	// is created and is propagated to all of the trace's spans. For example,
	//
	//   func(traceID int64) { return traceID % 128 == 0 }
	//
	// samples 1 in every 128 traces, approximately.
	ShouldSample func(traceID int64) bool

	// Verbose determines whether errors are logged to stdout only once or all
	// the time. By default, Verbose is false so only the first error is logged
	// and the rest are silenced.
	Verbose bool

	// Logger is used to log critical errors that can't be collected by the
	// Appdash Collector.
	Logger *log.Logger
}

func newLogger() *log.Logger {
	return log.New(os.Stderr, "opentracing: ", log.LstdFlags)
}

// DefaultOptions creates an Option with a sampling function that always return
// true and a logger that logs errors to stderr.
func DefaultOptions() Options {
	return Options{
		ShouldSample: func(_ int64) bool { return true },
		Logger:       newLogger(),
	}
}

// NewTracer creates a new opentracing.Tracer implementation that reports
// spans to an Appdash collector.
//
// The Tracer created by NewTracer reports all spans by default. If you want to
// sample 1 in every N spans, see NewTracerWithOptions. Spans are written to
// the underlying collector when Finish() is called on the span. It is
// possible to buffer and write span on a time interval using appdash.ChunkedCollector.
//
// For example:
//
//   collector := appdash.NewLocalCollector(myAppdashStore)
//   chunkedCollector := appdash.NewChunkedCollector(collector)
//
//   tracer := NewTracer(chunkedCollector)
//
// If writing traces to a remote Appdash collector, an appdash.RemoteCollector would
// be needed, for example:
//
//   collector := appdash.NewRemoteCollector("localhost:8700")
//   tracer := NewTracer(collector)
//
// will record all spans to a collector server on localhost:8700.
func NewTracer(c appdash.Collector) opentracing.Tracer {
	return NewTracerWithOptions(c, DefaultOptions())
}

// NewTracerWithOptions creates a new opentracing.Tracer that records spans to
// the given appdash.Collector.
func NewTracerWithOptions(c appdash.Collector, options Options) opentracing.Tracer {
	opts := basictracer.DefaultOptions()
	opts.ShouldSample = options.ShouldSample
	opts.Recorder = NewRecorder(c, options)
	return basictracer.NewWithOptions(opts)
}
<commit_msg>updates to match correct types<commit_after>package opentracing

import (
	"log"
	"os"

	basictracer "github.com/opentracing/basictracer-go"
	opentracing "github.com/opentracing/opentracing-go"
	"sourcegraph.com/sourcegraph/appdash"
)

var _ opentracing.Tracer = NewTracer(nil) // Compile time check.

// Options defines options for a Tracer.
type Options struct {
	// ShouldSample is a function that allows deterministic sampling of a trace
	// using the randomly generated Trace ID. The decision is made when a new Trace
	// is created and is propagated to all of the trace's spans. For example,
	//
	//   func(traceID int64) { return traceID % 128 == 0 }
	//
	// samples 1 in every 128 traces, approximately.
	ShouldSample func(traceID uint64) bool

	// Verbose determines whether errors are logged to stdout only once or all
	// the time. By default, Verbose is false so only the first error is logged
	// and the rest are silenced.
	Verbose bool

	// Logger is used to log critical errors that can't be collected by the
	// Appdash Collector.
	Logger *log.Logger
}

func newLogger() *log.Logger {
	return log.New(os.Stderr, "opentracing: ", log.LstdFlags)
}

// DefaultOptions creates an Option with a sampling function that always return
// true and a logger that logs errors to stderr.
func DefaultOptions() Options {
	return Options{
		ShouldSample: func(_ uint64) bool { return true },
		Logger:       newLogger(),
	}
}

// NewTracer creates a new opentracing.Tracer implementation that reports
// spans to an Appdash collector.
//
// The Tracer created by NewTracer reports all spans by default. If you want to
// sample 1 in every N spans, see NewTracerWithOptions. Spans are written to
// the underlying collector when Finish() is called on the span. It is
// possible to buffer and write span on a time interval using appdash.ChunkedCollector.
//
// For example:
//
//   collector := appdash.NewLocalCollector(myAppdashStore)
//   chunkedCollector := appdash.NewChunkedCollector(collector)
//
//   tracer := NewTracer(chunkedCollector)
//
// If writing traces to a remote Appdash collector, an appdash.RemoteCollector would
// be needed, for example:
//
//   collector := appdash.NewRemoteCollector("localhost:8700")
//   tracer := NewTracer(collector)
//
// will record all spans to a collector server on localhost:8700.
func NewTracer(c appdash.Collector) opentracing.Tracer {
	return NewTracerWithOptions(c, DefaultOptions())
}

// NewTracerWithOptions creates a new opentracing.Tracer that records spans to
// the given appdash.Collector.
func NewTracerWithOptions(c appdash.Collector, options Options) opentracing.Tracer {
	opts := basictracer.DefaultOptions()
	opts.ShouldSample = options.ShouldSample
	opts.Recorder = NewRecorder(c, options)
	return basictracer.NewWithOptions(opts)
}
<|endoftext|>


<commit_before>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

// This represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "kafkactl",
	Short: "A simple REST client for the scheduler remote API",
	Long: `Kafkactl is a command line tool written in GO for controlling kafka scheduler
that runs on top of Apache Mesos.`,
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.kafkactl.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".kafkactl") // name of config file (without extension)
	viper.AddConfigPath("$HOME")     // adding home directory as first search path
	viper.AutomaticEnv()             // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<commit_msg>root-cmd: Api persistent flags added<commit_after>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string
var apiURL string

// This represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "kafkactl",
	Short: "A simple REST client for the scheduler remote API",
	Long: `Kafkactl is a command line tool written in GO for controlling kafka scheduler
that runs on top of Apache Mesos.`,
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.kafkactl.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

	RootCmd.PersistentFlags().StringVar(&apiURL, "api", os.Getenv("KAFKA_API"), "Kafka scheduler api url")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".kafkactl") // name of config file (without extension)
	viper.AddConfigPath("$HOME")     // adding home directory as first search path
	viper.AutomaticEnv()             // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package cmd

import (
	"fmt"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"time"

	"code.gitea.io/gitea/models"
	asymkey_model "code.gitea.io/gitea/models/asymkey"
	"code.gitea.io/gitea/models/perm"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/json"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/pprof"
	"code.gitea.io/gitea/modules/private"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/services/lfs"

	"github.com/golang-jwt/jwt/v4"
	"github.com/kballard/go-shellquote"
	"github.com/urfave/cli"
)

const (
	lfsAuthenticateVerb = "git-lfs-authenticate"
)

// CmdServ represents the available serv sub-command.
var CmdServ = cli.Command{
	Name:        "serv",
	Usage:       "This command should only be called by SSH shell",
	Description: `Serv provide access auth for repositories`,
	Action:      runServ,
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name: "enable-pprof",
		},
		cli.BoolFlag{
			Name: "debug",
		},
	},
}

func setup(logPath string, debug bool) {
	_ = log.DelLogger("console")
	if debug {
		_ = log.NewLogger(1000, "console", "console", `{"level":"trace","stacktracelevel":"NONE","stderr":true}`)
	} else {
		_ = log.NewLogger(1000, "console", "console", `{"level":"fatal","stacktracelevel":"NONE","stderr":true}`)
	}
	setting.LoadFromExisting()
	if debug {
		setting.RunMode = "dev"
	}
}

var (
	allowedCommands = map[string]perm.AccessMode{
		"git-upload-pack":    perm.AccessModeRead,
		"git-upload-archive": perm.AccessModeRead,
		"git-receive-pack":   perm.AccessModeWrite,
		lfsAuthenticateVerb:  perm.AccessModeNone,
	}
	alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
)

func fail(userMessage, logMessage string, args ...interface{}) error {
	// There appears to be a chance to cause a zombie process and failure to read the Exit status
	// if nothing is outputted on stdout.
	fmt.Fprintln(os.Stdout, "")
	fmt.Fprintln(os.Stderr, "Gitea:", userMessage)

	if len(logMessage) > 0 {
		if !setting.IsProd {
			fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
		}
	}
	ctx, cancel := installSignals()
	defer cancel()

	if len(logMessage) > 0 {
		_ = private.SSHLog(ctx, true, fmt.Sprintf(logMessage+": ", args...))
	}
	return cli.NewExitError("", 1)
}

func runServ(c *cli.Context) error {
	ctx, cancel := installSignals()
	defer cancel()

	// FIXME: This needs to internationalised
	setup("serv.log", c.Bool("debug"))

	if setting.SSH.Disabled {
		println("Gitea: SSH has been disabled")
		return nil
	}

	if len(c.Args()) < 1 {
		if err := cli.ShowSubcommandHelp(c); err != nil {
			fmt.Printf("error showing subcommand help: %v\n", err)
		}
		return nil
	}

	keys := strings.Split(c.Args()[0], "-")
	if len(keys) != 2 || keys[0] != "key" {
		return fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
	}
	keyID, err := strconv.ParseInt(keys[1], 10, 64)
	if err != nil {
		return fail("Key ID format error", "Invalid key argument: %s", c.Args()[1])
	}

	cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
	if len(cmd) == 0 {
		key, user, err := private.ServNoCommand(ctx, keyID)
		if err != nil {
			return fail("Internal error", "Failed to check provided key: %v", err)
		}
		switch key.Type {
		case asymkey_model.KeyTypeDeploy:
			println("Hi there! You've successfully authenticated with the deploy key named " + key.Name + ", but Gitea does not provide shell access.")
		case asymkey_model.KeyTypePrincipal:
			println("Hi there! You've successfully authenticated with the principal " + key.Content + ", but Gitea does not provide shell access.")
		default:
			println("Hi there, " + user.Name + "! You've successfully authenticated with the key named " + key.Name + ", but Gitea does not provide shell access.")
		}
		println("If this is unexpected, please log in with password and setup Gitea under another user.")
		return nil
	} else if c.Bool("debug") {
		log.Debug("SSH_ORIGINAL_COMMAND: %s", os.Getenv("SSH_ORIGINAL_COMMAND"))
	}

	words, err := shellquote.Split(cmd)
	if err != nil {
		return fail("Error parsing arguments", "Failed to parse arguments: %v", err)
	}

	if len(words) < 2 {
		if git.CheckGitVersionAtLeast("2.29") == nil {
			// for AGit Flow
			if cmd == "ssh_info" {
				fmt.Print(`{"type":"gitea","version":1}`)
				return nil
			}
		}
		return fail("Too few arguments", "Too few arguments in cmd: %s", cmd)
	}

	verb := words[0]
	repoPath := words[1]
	if repoPath[0] == '/' {
		repoPath = repoPath[1:]
	}

	var lfsVerb string
	if verb == lfsAuthenticateVerb {
		if !setting.LFS.StartServer {
			return fail("Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
		}

		if len(words) > 2 {
			lfsVerb = words[2]
		}
	}

	// LowerCase and trim the repoPath as that's how they are stored.
	repoPath = strings.ToLower(strings.TrimSpace(repoPath))

	rr := strings.SplitN(repoPath, "/", 2)
	if len(rr) != 2 {
		return fail("Invalid repository path", "Invalid repository path: %v", repoPath)
	}

	username := strings.ToLower(rr[0])
	reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))

	if alphaDashDotPattern.MatchString(reponame) {
		return fail("Invalid repo name", "Invalid repo name: %s", reponame)
	}

	if c.Bool("enable-pprof") {
		if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
			return fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
		}

		stopCPUProfiler, err := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
		if err != nil {
			return fail("Internal Server Error", "Unable to start CPU profile: %v", err)
		}
		defer func() {
			stopCPUProfiler()
			err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
			if err != nil {
				_ = fail("Internal Server Error", "Unable to dump Mem Profile: %v", err)
			}
		}()
	}

	requestedMode, has := allowedCommands[verb]
	if !has {
		return fail("Unknown git command", "Unknown git command %s", verb)
	}

	if verb == lfsAuthenticateVerb {
		if lfsVerb == "upload" {
			requestedMode = perm.AccessModeWrite
		} else if lfsVerb == "download" {
			requestedMode = perm.AccessModeRead
		} else {
			return fail("Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
		}
	}

	results, err := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
	if err != nil {
		if private.IsErrServCommand(err) {
			errServCommand := err.(private.ErrServCommand)
			if errServCommand.StatusCode != http.StatusInternalServerError {
				return fail("Unauthorized", "%s", errServCommand.Error())
			}
			return fail("Internal Server Error", "%s", errServCommand.Error())
		}
		return fail("Internal Server Error", "%s", err.Error())
	}
	os.Setenv(models.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki))
	os.Setenv(models.EnvRepoName, results.RepoName)
	os.Setenv(models.EnvRepoUsername, results.OwnerName)
	os.Setenv(models.EnvPusherName, results.UserName)
	os.Setenv(models.EnvPusherEmail, results.UserEmail)
	os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
	os.Setenv(models.EnvRepoID, strconv.FormatInt(results.RepoID, 10))
	os.Setenv(models.EnvPRID, fmt.Sprintf("%d", 0))
	os.Setenv(models.EnvDeployKeyID, fmt.Sprintf("%d", results.DeployKeyID))
	os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID))
	os.Setenv(models.EnvAppURL, setting.AppURL)

	// LFS token authentication
	if verb == lfsAuthenticateVerb {
		url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName))

		now := time.Now()
		claims := lfs.Claims{
			RegisteredClaims: jwt.RegisteredClaims{
				ExpiresAt: jwt.NewNumericDate(now.Add(setting.LFS.HTTPAuthExpiry)),
				NotBefore: jwt.NewNumericDate(now),
			},
			RepoID: results.RepoID,
			Op:     lfsVerb,
			UserID: results.UserID,
		}
		token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

		// Sign and get the complete encoded token as a string using the secret
		tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
		if err != nil {
			return fail("Internal error", "Failed to sign JWT token: %v", err)
		}

		tokenAuthentication := &models.LFSTokenResponse{
			Header: make(map[string]string),
			Href:   url,
		}
		tokenAuthentication.Header["Authorization"] = fmt.Sprintf("Bearer %s", tokenString)

		enc := json.NewEncoder(os.Stdout)
		err = enc.Encode(tokenAuthentication)
		if err != nil {
			return fail("Internal error", "Failed to encode LFS json response: %v", err)
		}
		return nil
	}

	// Special handle for Windows.
	if setting.IsWindows {
		verb = strings.Replace(verb, "-", " ", 1)
	}

	var gitcmd *exec.Cmd
	verbs := strings.Split(verb, " ")
	if len(verbs) == 2 {
		gitcmd = exec.CommandContext(ctx, verbs[0], verbs[1], repoPath)
	} else {
		gitcmd = exec.CommandContext(ctx, verb, repoPath)
	}

	gitcmd.Dir = setting.RepoRootPath
	gitcmd.Stdout = os.Stdout
	gitcmd.Stdin = os.Stdin
	gitcmd.Stderr = os.Stderr
	if err = gitcmd.Run(); err != nil {
		return fail("Internal error", "Failed to execute git command: %v", err)
	}

	// Update user key activity.
	if results.KeyID > 0 {
		if err = private.UpdatePublicKeyInRepo(ctx, results.KeyID, results.RepoID); err != nil {
			return fail("Internal error", "UpdatePublicKeyInRepo: %v", err)
		}
	}

	return nil
}
<commit_msg>Warn on SSH connection for incorrect configuration (#19317)<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package cmd

import (
	"fmt"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"time"

	"code.gitea.io/gitea/models"
	asymkey_model "code.gitea.io/gitea/models/asymkey"
	"code.gitea.io/gitea/models/perm"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/json"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/pprof"
	"code.gitea.io/gitea/modules/private"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/services/lfs"

	"github.com/golang-jwt/jwt/v4"
	"github.com/kballard/go-shellquote"
	"github.com/urfave/cli"
)

const (
	lfsAuthenticateVerb = "git-lfs-authenticate"
)

// CmdServ represents the available serv sub-command.
var CmdServ = cli.Command{
	Name:        "serv",
	Usage:       "This command should only be called by SSH shell",
	Description: `Serv provide access auth for repositories`,
	Action:      runServ,
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name: "enable-pprof",
		},
		cli.BoolFlag{
			Name: "debug",
		},
	},
}

func setup(logPath string, debug bool) {
	_ = log.DelLogger("console")
	if debug {
		_ = log.NewLogger(1000, "console", "console", `{"level":"trace","stacktracelevel":"NONE","stderr":true}`)
	} else {
		_ = log.NewLogger(1000, "console", "console", `{"level":"fatal","stacktracelevel":"NONE","stderr":true}`)
	}
	setting.LoadFromExisting()
	if debug {
		setting.RunMode = "dev"
	}
}

var (
	allowedCommands = map[string]perm.AccessMode{
		"git-upload-pack":    perm.AccessModeRead,
		"git-upload-archive": perm.AccessModeRead,
		"git-receive-pack":   perm.AccessModeWrite,
		lfsAuthenticateVerb:  perm.AccessModeNone,
	}
	alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
)

func fail(userMessage, logMessage string, args ...interface{}) error {
	// There appears to be a chance to cause a zombie process and failure to read the Exit status
	// if nothing is outputted on stdout.
	fmt.Fprintln(os.Stdout, "")
	fmt.Fprintln(os.Stderr, "Gitea:", userMessage)

	if len(logMessage) > 0 {
		if !setting.IsProd {
			fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
		}
	}
	ctx, cancel := installSignals()
	defer cancel()

	if len(logMessage) > 0 {
		_ = private.SSHLog(ctx, true, fmt.Sprintf(logMessage+": ", args...))
	}
	return cli.NewExitError("", 1)
}

func runServ(c *cli.Context) error {
	ctx, cancel := installSignals()
	defer cancel()

	// FIXME: This needs to internationalised
	setup("serv.log", c.Bool("debug"))

	if setting.SSH.Disabled {
		println("Gitea: SSH has been disabled")
		return nil
	}

	if len(c.Args()) < 1 {
		if err := cli.ShowSubcommandHelp(c); err != nil {
			fmt.Printf("error showing subcommand help: %v\n", err)
		}
		return nil
	}

	keys := strings.Split(c.Args()[0], "-")
	if len(keys) != 2 || keys[0] != "key" {
		return fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
	}
	keyID, err := strconv.ParseInt(keys[1], 10, 64)
	if err != nil {
		return fail("Key ID format error", "Invalid key argument: %s", c.Args()[1])
	}

	cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
	if len(cmd) == 0 {
		key, user, err := private.ServNoCommand(ctx, keyID)
		if err != nil {
			return fail("Internal error", "Failed to check provided key: %v", err)
		}
		switch key.Type {
		case asymkey_model.KeyTypeDeploy:
			println("Hi there! You've successfully authenticated with the deploy key named " + key.Name + ", but Gitea does not provide shell access.")
		case asymkey_model.KeyTypePrincipal:
			println("Hi there! You've successfully authenticated with the principal " + key.Content + ", but Gitea does not provide shell access.")
		default:
			println("Hi there, " + user.Name + "! You've successfully authenticated with the key named " + key.Name + ", but Gitea does not provide shell access.")
		}
		println("If this is unexpected, please log in with password and setup Gitea under another user.")
		return nil
	} else if c.Bool("debug") {
		log.Debug("SSH_ORIGINAL_COMMAND: %s", os.Getenv("SSH_ORIGINAL_COMMAND"))
	}

	words, err := shellquote.Split(cmd)
	if err != nil {
		return fail("Error parsing arguments", "Failed to parse arguments: %v", err)
	}

	if len(words) < 2 {
		if git.CheckGitVersionAtLeast("2.29") == nil {
			// for AGit Flow
			if cmd == "ssh_info" {
				fmt.Print(`{"type":"gitea","version":1}`)
				return nil
			}
		}
		return fail("Too few arguments", "Too few arguments in cmd: %s", cmd)
	}

	verb := words[0]
	repoPath := words[1]
	if repoPath[0] == '/' {
		repoPath = repoPath[1:]
	}

	var lfsVerb string
	if verb == lfsAuthenticateVerb {
		if !setting.LFS.StartServer {
			return fail("Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
		}

		if len(words) > 2 {
			lfsVerb = words[2]
		}
	}

	// LowerCase and trim the repoPath as that's how they are stored.
	repoPath = strings.ToLower(strings.TrimSpace(repoPath))

	rr := strings.SplitN(repoPath, "/", 2)
	if len(rr) != 2 {
		return fail("Invalid repository path", "Invalid repository path: %v", repoPath)
	}

	username := strings.ToLower(rr[0])
	reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))

	if alphaDashDotPattern.MatchString(reponame) {
		return fail("Invalid repo name", "Invalid repo name: %s", reponame)
	}

	if c.Bool("enable-pprof") {
		if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
			return fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
		}

		stopCPUProfiler, err := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
		if err != nil {
			return fail("Internal Server Error", "Unable to start CPU profile: %v", err)
		}
		defer func() {
			stopCPUProfiler()
			err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
			if err != nil {
				_ = fail("Internal Server Error", "Unable to dump Mem Profile: %v", err)
			}
		}()
	}

	requestedMode, has := allowedCommands[verb]
	if !has {
		return fail("Unknown git command", "Unknown git command %s", verb)
	}

	if verb == lfsAuthenticateVerb {
		if lfsVerb == "upload" {
			requestedMode = perm.AccessModeWrite
		} else if lfsVerb == "download" {
			requestedMode = perm.AccessModeRead
		} else {
			return fail("Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
		}
	}

	results, err := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
	if err != nil {
		if private.IsErrServCommand(err) {
			errServCommand := err.(private.ErrServCommand)
			if errServCommand.StatusCode != http.StatusInternalServerError {
				return fail("Unauthorized", "%s", errServCommand.Error())
			}
			return fail("Internal Server Error", "%s", errServCommand.Error())
		}
		return fail("Internal Server Error", "%s", err.Error())
	}
	os.Setenv(models.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki))
	os.Setenv(models.EnvRepoName, results.RepoName)
	os.Setenv(models.EnvRepoUsername, results.OwnerName)
	os.Setenv(models.EnvPusherName, results.UserName)
	os.Setenv(models.EnvPusherEmail, results.UserEmail)
	os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
	os.Setenv(models.EnvRepoID, strconv.FormatInt(results.RepoID, 10))
	os.Setenv(models.EnvPRID, fmt.Sprintf("%d", 0))
	os.Setenv(models.EnvDeployKeyID, fmt.Sprintf("%d", results.DeployKeyID))
	os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID))
	os.Setenv(models.EnvAppURL, setting.AppURL)

	// LFS token authentication
	if verb == lfsAuthenticateVerb {
		url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName))

		now := time.Now()
		claims := lfs.Claims{
			RegisteredClaims: jwt.RegisteredClaims{
				ExpiresAt: jwt.NewNumericDate(now.Add(setting.LFS.HTTPAuthExpiry)),
				NotBefore: jwt.NewNumericDate(now),
			},
			RepoID: results.RepoID,
			Op:     lfsVerb,
			UserID: results.UserID,
		}
		token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

		// Sign and get the complete encoded token as a string using the secret
		tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
		if err != nil {
			return fail("Internal error", "Failed to sign JWT token: %v", err)
		}

		tokenAuthentication := &models.LFSTokenResponse{
			Header: make(map[string]string),
			Href:   url,
		}
		tokenAuthentication.Header["Authorization"] = fmt.Sprintf("Bearer %s", tokenString)

		enc := json.NewEncoder(os.Stdout)
		err = enc.Encode(tokenAuthentication)
		if err != nil {
			return fail("Internal error", "Failed to encode LFS json response: %v", err)
		}
		return nil
	}

	// Special handle for Windows.
	if setting.IsWindows {
		verb = strings.Replace(verb, "-", " ", 1)
	}

	var gitcmd *exec.Cmd
	verbs := strings.Split(verb, " ")
	if len(verbs) == 2 {
		gitcmd = exec.CommandContext(ctx, verbs[0], verbs[1], repoPath)
	} else {
		gitcmd = exec.CommandContext(ctx, verb, repoPath)
	}

	// Check if setting.RepoRootPath exists. It could be the case that it doesn't exist, this can happen when
	// `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection.
	if _, err := os.Stat(setting.RepoRootPath); err != nil {
		if os.IsNotExist(err) {
			return fail("Incorrect configuration.",
				"Directory `[repository]` `ROOT` was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository]` `ROOT` an absolute value.")
		}
	}

	gitcmd.Dir = setting.RepoRootPath
	gitcmd.Stdout = os.Stdout
	gitcmd.Stdin = os.Stdin
	gitcmd.Stderr = os.Stderr
	if err = gitcmd.Run(); err != nil {
		return fail("Internal error", "Failed to execute git command: %v", err)
	}

	// Update user key activity.
	if results.KeyID > 0 {
		if err = private.UpdatePublicKeyInRepo(ctx, results.KeyID, results.RepoID); err != nil {
			return fail("Internal error", "UpdatePublicKeyInRepo: %v", err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before><commit_msg>Flesh out the help documentation for show<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"syscall"
)

// `direnv exec DIR <COMMAND> ...`
var CmdExec = &Cmd{
	Name: "exec",
	Desc: "Executes a command after loading the first .envrc found in DIR",
	Args: []string{"DIR", "COMMAND", "[...ARGS]"},
	Action: actionWithConfig(func(env Env, args []string, config *Config) (err error) {
		var (
			backupDiff *EnvDiff
			newEnv     Env
			rcPath     string
			command    string
		)

		if len(args) < 2 {
			return fmt.Errorf("missing DIR and COMMAND arguments")
		}

		rcPath = filepath.Clean(args[1])
		fi, err := os.Stat(rcPath)
		if err != nil {
			return
		}

		if fi.IsDir() {
			if len(args) < 3 {
				return fmt.Errorf("missing COMMAND argument")
			}
			command = args[2]
			args = args[2:]
		} else {
			command = rcPath
			rcPath = filepath.Dir(rcPath)
			args = args[1:]
		}

		rc := FindRC(rcPath, config)

		// Restore pristine environment if needed
		if backupDiff, err = config.EnvDiff(); err == nil {
			env = backupDiff.Reverse().Patch(env)
		}
		env.CleanContext()

		// Load the rc
		if rc != nil {
			if newEnv, err = rc.Load(config, env); err != nil {
				return
			}
		} else {
			newEnv = env
		}

		command, err = lookPath(command, newEnv["PATH"])
		if err != nil {
			return
		}

		err = syscall.Exec(command, args, newEnv.ToGoEnv())
		return
	}),
}
<commit_msg>direnv exec: improve the error message<commit_after>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"syscall"
)

// `direnv exec DIR <COMMAND> ...`
var CmdExec = &Cmd{
	Name: "exec",
	Desc: "Executes a command after loading the first .envrc found in DIR",
	Args: []string{"DIR", "COMMAND", "[...ARGS]"},
	Action: actionWithConfig(func(env Env, args []string, config *Config) (err error) {
		var (
			backupDiff *EnvDiff
			newEnv     Env
			rcPath     string
			command    string
		)

		if len(args) < 2 {
			return fmt.Errorf("missing DIR and COMMAND arguments")
		}

		rcPath = filepath.Clean(args[1])
		fi, err := os.Stat(rcPath)
		if err != nil {
			return
		}

		if fi.IsDir() {
			if len(args) < 3 {
				return fmt.Errorf("missing COMMAND argument")
			}
			command = args[2]
			args = args[2:]
		} else {
			command = rcPath
			rcPath = filepath.Dir(rcPath)
			args = args[1:]
		}

		rc := FindRC(rcPath, config)

		// Restore pristine environment if needed
		if backupDiff, err = config.EnvDiff(); err == nil {
			env = backupDiff.Reverse().Patch(env)
		}
		env.CleanContext()

		// Load the rc
		if rc != nil {
			if newEnv, err = rc.Load(config, env); err != nil {
				return
			}
		} else {
			newEnv = env
		}

		var commandPath string
		commandPath, err = lookPath(command, newEnv["PATH"])
		if err != nil {
			err = fmt.Errorf("command '%s' not found on PATH '%s'", command, newEnv["PATH"])
			return
		}

		err = syscall.Exec(commandPath, args, newEnv.ToGoEnv())
		return
	}),
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"html"
	"io/ioutil"
	"net/http"
	"os"
	"os/user"
	"regexp"

	"github.com/imwally/pinboard"
)

var (
	options   = flag.NewFlagSet("", flag.ExitOnError)
	privFlag  = options.Bool("private", false, "private bookmark")
	readFlag  = options.Bool("readlater", false, "read later bookmark")
	longFlag  = options.Bool("l", false, "display long format")
	extFlag   = options.String("text", "", "longer description of bookmark")
	tagFlag   = options.String("tag", "", "tags for bookmark")
	titleFlag = options.String("title", "", "title of the bookmark")

	token string
)

var usage = `Usage: pin
  pin rm  URL
  pin add URL [OPTION]
  pin ls [OPTION]

Options:
  -title      title of bookmark being added
  -tag        space delimited tags
  -private    mark bookmark as private
  -readlater  mark bookmark as read later
  -text       longer description of bookmark
  -l          long format for ls
`

// Number of bookmarks to display.
const COUNT int = 50

// Piped is a helper function to check for piped input. It will return
// input, true if data was piped.
func Piped() (string, bool) {
	fi, err := os.Stdin.Stat()
	if err != nil {
		fmt.Fprintf(os.Stderr, "pin: %s", err)
		return "", false
	}

	isPipe := (fi.Mode() & os.ModeNamedPipe) == os.ModeNamedPipe
	if isPipe {
		read := bufio.NewReader(os.Stdin)
		line, _, err := read.ReadLine()
		if err != nil {
			fmt.Println(err)
		}
		return string(line), true
	}

	return "", false
}

// PageTitle returns the title from an HTML page.
func PageTitle(url string) (title string, err error) {
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	re := regexp.MustCompile("<title>(.*?)</title>")

	return html.UnescapeString(string(re.FindSubmatch(body)[1])), nil
}

// Add checks flag values and encodes the GET URL for adding a bookmark.
func Add(p pinboard.Post) {

	var args []string

	// Check if URL is piped in or first argument. Optional tags
	// should follow the URL.
	if url, ok := Piped(); ok {
		p.URL = url
		args = flag.Args()[1:]
	} else {
		p.URL = flag.Args()[1]
		args = flag.Args()[2:]
	}

	// Parse flags after the URL.
	options.Parse(args)

	if *titleFlag != "" {
		p.Description = *titleFlag
	} else {
		// Use page title if title flag is not supplied.
		title, err := PageTitle(p.URL)
		if err != nil {
			fmt.Fprintf(os.Stderr, "pin: couldn't get title: %s\n", err)
			return
		} else {
			p.Description = title
		}
	}

	if *privFlag {
		p.Shared = "no"
	}

	if *readFlag {
		p.Toread = "yes"
	}

	p.Extended = *extFlag
	p.Tags = *tagFlag

	p.Encode()
	err := p.Add()
	if err != nil {
		fmt.Println(err)
	}
}

// Delete will delete the URL specified.
func Delete(p pinboard.Post) {

	// Check if URL is piped in or first argument.
	if url, ok := Piped(); ok {
		p.URL = url
	} else {
		p.URL = flag.Args()[1]
	}

	p.Encode()
	err := p.Delete()
	if err != nil {
		fmt.Println(err)
	}
}

// Show will list the most recent bookmarks. The -tag and -readlater
// flags can be used to filter results.
func Show(p pinboard.Post) {

	args := flag.Args()[1:]
	options.Parse(args)

	if *tagFlag != "" {
		p.Tag = *tagFlag
	}
	if *readFlag {
		p.Toread = "yes"
	}

	p.Count = COUNT
	p.Encode()

	recent := p.ShowRecent()

	if *longFlag {
		for _, v := range recent.Posts {
			var shared, unread string
			if v.Shared == "no" {
				shared = "[*]"
			}
			if v.Toread == "yes" {
				unread = "[#]"
			}
			fmt.Println(unread + shared + v.Description)
			fmt.Println(v.Href)
			if v.Extended != "" {
				fmt.Println(v.Extended)
			}
			fmt.Println(v.Tags, "\n")
		}
	} else {
		for _, v := range recent.Posts {
			fmt.Println(v.Href)
		}
	}
}

// runCmd takes a command string, initialises a new pinboard post and
// runs the command.
func runCmd(cmd string) {
	var p pinboard.Post
	p.Token = token

	if cmd == "help" {
		fmt.Printf("%s", usage)
	}

	if cmd == "ls" {
		Show(p)
	}

	if cmd == "add" {
		Add(p)
	}

	if cmd == "rm" {
		Delete(p)
	}
}

// start takes a slice of commands, parses flag arguments and runs the
// command if it's found.
func start(cmds []string) {
	flag.Parse()
	if flag.NArg() < 1 {
		fmt.Fprintf(os.Stderr, "pin: no command is given.\n")
		return
	}

	cmdName := flag.Arg(0)

	var found bool
	for _, cmd := range cmds {
		if cmdName == cmd {
			runCmd(cmd)
			return
		}
	}

	if !found {
		fmt.Fprintf(os.Stderr, "pin: command %s not found.\n", cmdName)
		return
	}
}

// TokenIsSet will check to make sure an authentication token is set before
// making any API calls.
func TokenIsSet() bool {
	if token == "" {
		return false
	}
	return true
}

func init() {
	u, err := user.Current()
	if err != nil {
		fmt.Println(err)
	}

	content, err := ioutil.ReadFile(u.HomeDir + "/.pinboard")
	if err != nil {
		fmt.Println("No authorization token found. Please add your authorization token to ~/.pinboard")
	}

	token = string(content)
}

func main() {
	if !TokenIsSet() {
		return
	}

	cmds := []string{"help", "add", "rm", "ls"}

	start(cmds)
}
<commit_msg>Changes recommended by golint.<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"html"
	"io/ioutil"
	"net/http"
	"os"
	"os/user"
	"regexp"

	"github.com/imwally/pinboard"
)

var (
	options   = flag.NewFlagSet("", flag.ExitOnError)
	privFlag  = options.Bool("private", false, "private bookmark")
	readFlag  = options.Bool("readlater", false, "read later bookmark")
	longFlag  = options.Bool("l", false, "display long format")
	extFlag   = options.String("text", "", "longer description of bookmark")
	tagFlag   = options.String("tag", "", "tags for bookmark")
	titleFlag = options.String("title", "", "title of the bookmark")

	token string
)

var usage = `Usage: pin
  pin rm  URL
  pin add URL [OPTION]
  pin ls [OPTION]

Options:
  -title      title of bookmark being added
  -tag        space delimited tags
  -private    mark bookmark as private
  -readlater  mark bookmark as read later
  -text       longer description of bookmark
  -l          long format for ls
`

// COUNT is the number of bookmarks to display.
const COUNT int = 50

// Piped is a helper function to check for piped input. It will return
// input, true if data was piped.
func Piped() (string, bool) {
	fi, err := os.Stdin.Stat()
	if err != nil {
		fmt.Fprintf(os.Stderr, "pin: %s", err)
		return "", false
	}

	isPipe := (fi.Mode() & os.ModeNamedPipe) == os.ModeNamedPipe
	if isPipe {
		read := bufio.NewReader(os.Stdin)
		line, _, err := read.ReadLine()
		if err != nil {
			fmt.Println(err)
		}
		return string(line), true
	}

	return "", false
}

// PageTitle returns the title from an HTML page.
func PageTitle(url string) (title string, err error) {
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	re := regexp.MustCompile("<title>(.*?)</title>")

	return html.UnescapeString(string(re.FindSubmatch(body)[1])), nil
}

// Add checks flag values and encodes the GET URL for adding a bookmark.
func Add(p pinboard.Post) {

	var args []string

	// Check if URL is piped in or first argument. Optional tags
	// should follow the URL.
	if url, ok := Piped(); ok {
		p.URL = url
		args = flag.Args()[1:]
	} else {
		p.URL = flag.Args()[1]
		args = flag.Args()[2:]
	}

	// Parse flags after the URL.
	options.Parse(args)

	if *titleFlag != "" {
		p.Description = *titleFlag
	} else {
		// Use page title if title flag is not supplied.
		title, err := PageTitle(p.URL)
		if err != nil {
			fmt.Fprintf(os.Stderr, "pin: couldn't get title: %s\n", err)
			return
		}

		p.Description = title
	}

	if *privFlag {
		p.Shared = "no"
	}

	if *readFlag {
		p.Toread = "yes"
	}

	p.Extended = *extFlag
	p.Tags = *tagFlag

	p.Encode()
	err := p.Add()
	if err != nil {
		fmt.Println(err)
	}
}

// Delete will delete the URL specified.
func Delete(p pinboard.Post) {

	// Check if URL is piped in or first argument.
	if url, ok := Piped(); ok {
		p.URL = url
	} else {
		p.URL = flag.Args()[1]
	}

	p.Encode()
	err := p.Delete()
	if err != nil {
		fmt.Println(err)
	}
}

// Show will list the most recent bookmarks. The -tag and -readlater
// flags can be used to filter results.
func Show(p pinboard.Post) {

	args := flag.Args()[1:]
	options.Parse(args)

	if *tagFlag != "" {
		p.Tag = *tagFlag
	}
	if *readFlag {
		p.Toread = "yes"
	}

	p.Count = COUNT
	p.Encode()

	recent := p.ShowRecent()

	if *longFlag {
		for _, v := range recent.Posts {
			var shared, unread string
			if v.Shared == "no" {
				shared = "[*]"
			}
			if v.Toread == "yes" {
				unread = "[#]"
			}
			fmt.Println(unread + shared + v.Description)
			fmt.Println(v.Href)
			if v.Extended != "" {
				fmt.Println(v.Extended)
			}
			fmt.Println(v.Tags, "\n")
		}
	} else {
		for _, v := range recent.Posts {
			fmt.Println(v.Href)
		}
	}
}

// runCmd takes a command string, initialises a new pinboard post and
// runs the command.
func runCmd(cmd string) {
	var p pinboard.Post
	p.Token = token

	if cmd == "help" {
		fmt.Printf("%s", usage)
	}

	if cmd == "ls" {
		Show(p)
	}

	if cmd == "add" {
		Add(p)
	}

	if cmd == "rm" {
		Delete(p)
	}
}

// start takes a slice of commands, parses flag arguments and runs the
// command if it's found.
func start(cmds []string) {
	flag.Parse()
	if flag.NArg() < 1 {
		fmt.Fprintf(os.Stderr, "pin: no command is given.\n")
		return
	}

	cmdName := flag.Arg(0)

	var found bool
	for _, cmd := range cmds {
		if cmdName == cmd {
			runCmd(cmd)
			return
		}
	}

	if !found {
		fmt.Fprintf(os.Stderr, "pin: command %s not found.\n", cmdName)
		return
	}
}

// TokenIsSet will check to make sure an authentication token is set before
// making any API calls.
func TokenIsSet() bool {
	if token == "" {
		return false
	}
	return true
}

func init() {
	u, err := user.Current()
	if err != nil {
		fmt.Println(err)
	}

	content, err := ioutil.ReadFile(u.HomeDir + "/.pinboard")
	if err != nil {
		fmt.Println("No authorization token found. Please add your authorization token to ~/.pinboard")
	}

	token = string(content)
}

func main() {
	if !TokenIsSet() {
		return
	}

	cmds := []string{"help", "add", "rm", "ls"}

	start(cmds)
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// 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 etcdserver

import (
	"time"

	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus"
	"github.com/coreos/etcd/pkg/runtime"
)

var (
	// TODO: with label in v3?
	proposeDurations = prometheus.NewSummary(prometheus.SummaryOpts{
		Namespace: "etcd",
		Subsystem: "server",
		Name:      "proposal_durations_milliseconds",
		Help:      "The latency distributions of committing proposal.",
	})
	proposePending = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: "etcd",
		Subsystem: "server",
		Name:      "pending_proposal_total",
		Help:      "The total number of pending proposals.",
	})
	// This is number of proposal failed in client's view.
	// The proposal might be later got committed in raft.
	proposeFailed = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: "etcd",
		Subsystem: "server",
		Name:      "proposal_failed_total",
		Help:      "The total number of failed proposals.",
	})

	fileDescriptorUsed = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: "etcd",
		Subsystem: "server",
		Name:      "file_descriptors_used_totol",
		Help:      "The total number of file descriptors used.",
	})
)

func init() {
	prometheus.MustRegister(proposeDurations)
	prometheus.MustRegister(proposePending)
	prometheus.MustRegister(proposeFailed)
	prometheus.MustRegister(fileDescriptorUsed)
}

func monitorFileDescriptor(done <-chan struct{}) {
	ticker := time.NewTicker(5 * time.Second)
	defer ticker.Stop()
	for {
		used, err := runtime.FDUsage()
		if err != nil {
			plog.Errorf("cannot monitor file descriptor usage (%v)", err)
			return
		}
		fileDescriptorUsed.Set(float64(used))
		limit, err := runtime.FDLimit()
		if err != nil {
			plog.Errorf("cannot monitor file descriptor usage (%v)", err)
			return
		}
		if used >= limit/5*4 {
			plog.Warningf("80%% of the file descriptor limit is used [used = %d, limit = %d]", used, limit)
		}
		select {
		case <-ticker.C:
		case <-done:
			return
		}
	}
}
<commit_msg>etcdserver: fix typo in metrics.go<commit_after>// Copyright 2015 CoreOS, Inc.
//
// 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 etcdserver

import (
	"time"

	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus"
	"github.com/coreos/etcd/pkg/runtime"
)

var (
	// TODO: with label in v3?
	proposeDurations = prometheus.NewSummary(prometheus.SummaryOpts{
		Namespace: "etcd",
		Subsystem: "server",
		Name:      "proposal_durations_milliseconds",
		Help:      "The latency distributions of committing proposal.",
	})
	proposePending = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: "etcd",
		Subsystem: "server",
		Name:      "pending_proposal_total",
		Help:      "The total number of pending proposals.",
	})
	// This is number of proposal failed in client's view.
	// The proposal might be later got committed in raft.
	proposeFailed = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: "etcd",
		Subsystem: "server",
		Name:      "proposal_failed_total",
		Help:      "The total number of failed proposals.",
	})

	fileDescriptorUsed = prometheus.NewGauge(prometheus.GaugeOpts{
		Namespace: "etcd",
		Subsystem: "server",
		Name:      "file_descriptors_used_total",
		Help:      "The total number of file descriptors used.",
	})
)

func init() {
	prometheus.MustRegister(proposeDurations)
	prometheus.MustRegister(proposePending)
	prometheus.MustRegister(proposeFailed)
	prometheus.MustRegister(fileDescriptorUsed)
}

func monitorFileDescriptor(done <-chan struct{}) {
	ticker := time.NewTicker(5 * time.Second)
	defer ticker.Stop()
	for {
		used, err := runtime.FDUsage()
		if err != nil {
			plog.Errorf("cannot monitor file descriptor usage (%v)", err)
			return
		}
		fileDescriptorUsed.Set(float64(used))
		limit, err := runtime.FDLimit()
		if err != nil {
			plog.Errorf("cannot monitor file descriptor usage (%v)", err)
			return
		}
		if used >= limit/5*4 {
			plog.Warningf("80%% of the file descriptor limit is used [used = %d, limit = %d]", used, limit)
		}
		select {
		case <-ticker.C:
		case <-done:
			return
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>apply goimports<commit_after><|endoftext|>


<commit_before>package messagerouter

import (
	"fmt"
	"github.com/nlopes/slack"
	"strings"
)

type ResponseWriter interface {
	Write(string) error
	WriteChannel(string, string) error
	WriteError(string) error
}

type SlackResponseWriter struct {
	rtm *slack.RTM
	msg *slack.Msg
}

func NewSlackResponseWriter(msg *slack.Msg, rtm *slack.RTM) *SlackResponseWriter {
	w := SlackResponseWriter{}
	w.msg = msg
	w.rtm = rtm

	return &w
}

//Msg sets the SlackResponseWriter Message
func (w *SlackResponseWriter) Msg(msg *slack.Msg) {
	w.msg = msg
}

//Msg sets the SlackResponseWriter RTM
func (w *SlackResponseWriter) Rtm(rtm *slack.RTM) {
	w.rtm = rtm
}

// WriteChannel sends message to particular channel
func (w *SlackResponseWriter) WriteChannel(channel string, text string) error {
	w.rtm.SendMessage(w.rtm.NewOutgoingMessage(text, w.msg.Channel))
	return nil
}

// Write writes to Slack
func (w *SlackResponseWriter) Write(text string) error {
	w.rtm.SendMessage(w.rtm.NewOutgoingMessage(text, w.msg.Channel))

	return nil
}

// WriteError writes an error to Slack
func (w *SlackResponseWriter) WriteError(errText string) error {
	lines := strings.Split(errText, "\n")
	for _, value := range lines {
		w.Write(":poop: " + value + " :poop:")
	}
	return nil
}

//CLIResponseWriter handles writing to the command line
type CLIResponseWriter struct {
}

// Write writes to CLI, prints channel it would go to if via Slack
func (w *CLIResponseWriter) WriteChannel(channel string, text string) error {
	fmt.Println(">> "+channel, text)

	return nil
}

// Write writes to CLI
func (w *CLIResponseWriter) Write(text string) error {
	fmt.Println(">> ", text)

	return nil
}

// WriteError writes error to CLI
func (w *CLIResponseWriter) WriteError(errText string) error {
	return w.Write(":poop: " + errText + " :poop:")
}
<commit_msg>Fix WriteChannel to actually send to the slack chan<commit_after>package messagerouter

import (
	"fmt"
	"github.com/nlopes/slack"
	"strings"
)

type ResponseWriter interface {
	Write(string) error
	WriteChannel(string, string) error
	WriteError(string) error
}

type SlackResponseWriter struct {
	rtm *slack.RTM
	msg *slack.Msg
}

func NewSlackResponseWriter(msg *slack.Msg, rtm *slack.RTM) *SlackResponseWriter {
	w := SlackResponseWriter{}
	w.msg = msg
	w.rtm = rtm

	return &w
}

//Msg sets the SlackResponseWriter Message
func (w *SlackResponseWriter) Msg(msg *slack.Msg) {
	w.msg = msg
}

//Msg sets the SlackResponseWriter RTM
func (w *SlackResponseWriter) Rtm(rtm *slack.RTM) {
	w.rtm = rtm
}

// WriteChannel sends message to particular channel
func (w *SlackResponseWriter) WriteChannel(channel string, text string) error {
	w.rtm.SendMessage(w.rtm.NewOutgoingMessage(text, channel))
	return nil
}

// Write writes to Slack
func (w *SlackResponseWriter) Write(text string) error {
	w.rtm.SendMessage(w.rtm.NewOutgoingMessage(text, w.msg.Channel))

	return nil
}

// WriteError writes an error to Slack
func (w *SlackResponseWriter) WriteError(errText string) error {
	lines := strings.Split(errText, "\n")
	for _, value := range lines {
		w.Write(":poop: " + value + " :poop:")
	}
	return nil
}

//CLIResponseWriter handles writing to the command line
type CLIResponseWriter struct {
}

// Write writes to CLI, prints channel it would go to if via Slack
func (w *CLIResponseWriter) WriteChannel(channel string, text string) error {
	fmt.Println(">> "+channel, text)

	return nil
}

// Write writes to CLI
func (w *CLIResponseWriter) Write(text string) error {
	fmt.Println(">> ", text)

	return nil
}

// WriteError writes error to CLI
func (w *CLIResponseWriter) WriteError(errText string) error {
	return w.Write(":poop: " + errText + " :poop:")
}
<|endoftext|>