Enable lint check for comments (#2023)

Commit 1: Enable lint check for comments

Part of #217. Follow up from #1982 and #2018.

A subsequent commit will fix the ci failure.

Commit 2: Address all comment-related linter errors.

This change addresses all comment-related linter errors by doing the
following:
- Add comments to exported symbols
- Make some exported symbols private
- Recommend via TODOs that some exported symbols should should move or
  be removed

This PR does not:
- Modify, move, or remove any code
- Modify existing comments

Signed-off-by: Andrew Seigner <siggy@buoyant.io>
This commit is contained in:
Andrew Seigner 2019-01-02 14:03:59 -08:00 committed by GitHub
parent ef02cd6828
commit 1c302182ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 214 additions and 35 deletions

View File

@ -12,8 +12,8 @@ cd "$rootdir"
# install golint from vendor
go install ./vendor/golang.org/x/lint/golint
# use `go list` to exclude packages in vendor, ignore uncommented warnings
out=$(go list ./... | xargs golint | grep -v 'should have comment') || true
# use `go list` to exclude packages in vendor
out=$(go list ./... | xargs golint) || true
if [ -n "$out" ]; then
echo "$out"

View File

@ -5,6 +5,8 @@ import (
"google.golang.org/grpc"
)
// NewClient creates a new gRPC client to the Destination service.
// TODO: consider moving this into destination-client, or removing altogether.
func NewClient(addr string) (pb.DestinationClient, *grpc.ClientConn, error) {
conn, err := grpc.Dial(addr, grpc.WithInsecure())
if err != nil {

View File

@ -190,6 +190,8 @@ func newClient(apiURL *url.URL, httpClientToUse *http.Client, controlPlaneNamesp
}, nil
}
// NewInternalClient creates a new Public API client intended to run inside a
// Kubernetes cluster.
func NewInternalClient(controlPlaneNamespace string, kubeAPIHost string) (pb.ApiClient, error) {
apiURL, err := url.Parse(fmt.Sprintf("http://%s/", kubeAPIHost))
if err != nil {
@ -199,6 +201,8 @@ func NewInternalClient(controlPlaneNamespace string, kubeAPIHost string) (pb.Api
return newClient(apiURL, http.DefaultClient, controlPlaneNamespace)
}
// NewExternalClient creates a new Public API client intended to run from
// outside a Kubernetes cluster.
func NewExternalClient(controlPlaneNamespace string, kubeAPI *k8s.KubernetesAPI) (pb.ApiClient, error) {
apiURL, err := kubeAPI.URLFor(controlPlaneNamespace, "/services/linkerd-controller-api:http/proxy/")
if err != nil {

View File

@ -39,10 +39,10 @@ type podReport struct {
const (
podQuery = "max(process_start_time_seconds{%s}) by (pod, namespace)"
K8sClientSubsystemName = "kubernetes"
K8sClientCheckDescription = "control plane can talk to Kubernetes"
PromClientSubsystemName = "prometheus"
PromClientCheckDescription = "control plane can talk to Prometheus"
k8sClientSubsystemName = "kubernetes"
k8sClientCheckDescription = "control plane can talk to Kubernetes"
promClientSubsystemName = "prometheus"
promClientCheckDescription = "control plane can talk to Prometheus"
)
func newGrpcServer(
@ -190,8 +190,8 @@ func (s *grpcServer) ListPods(ctx context.Context, req *pb.ListPodsRequest) (*pb
func (s *grpcServer) SelfCheck(ctx context.Context, in *healthcheckPb.SelfCheckRequest) (*healthcheckPb.SelfCheckResponse, error) {
k8sClientCheck := &healthcheckPb.CheckResult{
SubsystemName: K8sClientSubsystemName,
CheckDescription: K8sClientCheckDescription,
SubsystemName: k8sClientSubsystemName,
CheckDescription: k8sClientCheckDescription,
Status: healthcheckPb.CheckStatus_OK,
}
_, err := s.k8sAPI.Pod().Lister().List(labels.Everything())
@ -201,8 +201,8 @@ func (s *grpcServer) SelfCheck(ctx context.Context, in *healthcheckPb.SelfCheckR
}
promClientCheck := &healthcheckPb.CheckResult{
SubsystemName: PromClientSubsystemName,
CheckDescription: PromClientCheckDescription,
SubsystemName: promClientSubsystemName,
CheckDescription: promClientCheckDescription,
Status: healthcheckPb.CheckStatus_OK,
}
_, err = s.queryProm(ctx, fmt.Sprintf(podQuery, ""))

View File

@ -167,7 +167,7 @@ spec:
}
fakeGrpcServer := newGrpcServer(
&MockProm{Res: exp.promRes},
&mockProm{Res: exp.promRes},
tap.NewTapClient(nil),
k8sAPI,
"linkerd",
@ -248,7 +248,7 @@ metadata:
}
fakeGrpcServer := newGrpcServer(
&MockProm{},
&mockProm{},
tap.NewTapClient(nil),
k8sAPI,
"linkerd",

View File

@ -239,6 +239,7 @@ func fullURLPathFor(method string) string {
return apiRoot + apiPrefix + method
}
// NewServer creates a Public API HTTP server.
func NewServer(
addr string,
prometheusClient promApi.Client,

View File

@ -771,7 +771,7 @@ status:
for _, exp := range expectations {
fakeGrpcServer := newGrpcServer(
&MockProm{Res: exp.mockPromResponse},
&mockProm{Res: exp.mockPromResponse},
tap.NewTapClient(nil),
k8sAPI,
"linkerd",
@ -795,7 +795,7 @@ status:
t.Fatalf("NewFakeAPI returned an error: %s", err)
}
fakeGrpcServer := newGrpcServer(
&MockProm{Res: model.Vector{}},
&mockProm{Res: model.Vector{}},
tap.NewTapClient(nil),
k8sAPI,
"linkerd",

View File

@ -18,6 +18,7 @@ import (
"google.golang.org/grpc"
)
// MockAPIClient satisfies the Public API's gRPC interface.
type MockAPIClient struct {
ErrorToReturn error
VersionInfoToReturn *pb.VersionInfo
@ -30,45 +31,53 @@ type MockAPIClient struct {
APITapByResourceClientToReturn pb.Api_TapByResourceClient
}
// StatSummary provides a mock of a Public API method.
func (c *MockAPIClient) StatSummary(ctx context.Context, in *pb.StatSummaryRequest, opts ...grpc.CallOption) (*pb.StatSummaryResponse, error) {
return c.StatSummaryResponseToReturn, c.ErrorToReturn
}
// TopRoutes provides a mock of a Public API method.
func (c *MockAPIClient) TopRoutes(ctx context.Context, in *pb.TopRoutesRequest, opts ...grpc.CallOption) (*pb.TopRoutesResponse, error) {
return c.TopRoutesResponseToReturn, c.ErrorToReturn
}
// Version provides a mock of a Public API method.
func (c *MockAPIClient) Version(ctx context.Context, in *pb.Empty, opts ...grpc.CallOption) (*pb.VersionInfo, error) {
return c.VersionInfoToReturn, c.ErrorToReturn
}
// ListPods provides a mock of a Public API method.
func (c *MockAPIClient) ListPods(ctx context.Context, in *pb.ListPodsRequest, opts ...grpc.CallOption) (*pb.ListPodsResponse, error) {
return c.ListPodsResponseToReturn, c.ErrorToReturn
}
// ListServices provides a mock of a Public API method.
func (c *MockAPIClient) ListServices(ctx context.Context, in *pb.ListServicesRequest, opts ...grpc.CallOption) (*pb.ListServicesResponse, error) {
return c.ListServicesResponseToReturn, c.ErrorToReturn
}
// Tap provides a mock of a Public API method.
func (c *MockAPIClient) Tap(ctx context.Context, in *pb.TapRequest, opts ...grpc.CallOption) (pb.Api_TapClient, error) {
return c.APITapClientToReturn, c.ErrorToReturn
}
// TapByResource provides a mock of a Public API method.
func (c *MockAPIClient) TapByResource(ctx context.Context, in *pb.TapByResourceRequest, opts ...grpc.CallOption) (pb.Api_TapByResourceClient, error) {
return c.APITapByResourceClientToReturn, c.ErrorToReturn
}
// SelfCheck provides a mock of a Public API method.
func (c *MockAPIClient) SelfCheck(ctx context.Context, in *healthcheckPb.SelfCheckRequest, _ ...grpc.CallOption) (*healthcheckPb.SelfCheckResponse, error) {
return c.SelfCheckResponseToReturn, c.ErrorToReturn
}
type MockAPITapClient struct {
type mockAPITapClient struct {
TapEventsToReturn []pb.TapEvent
ErrorsToReturn []error
grpc.ClientStream
}
func (a *MockAPITapClient) Recv() (*pb.TapEvent, error) {
func (a *mockAPITapClient) Recv() (*pb.TapEvent, error) {
var eventPopped pb.TapEvent
var errorPopped error
if len(a.TapEventsToReturn) == 0 && len(a.ErrorsToReturn) == 0 {
@ -84,12 +93,14 @@ func (a *MockAPITapClient) Recv() (*pb.TapEvent, error) {
return &eventPopped, errorPopped
}
// MockAPITapByResourceClient satisfies the TapByResourceClient gRPC interface.
type MockAPITapByResourceClient struct {
TapEventsToReturn []pb.TapEvent
ErrorsToReturn []error
grpc.ClientStream
}
// Recv satisfies the TapByResourceClient.Recv() gRPC method.
func (a *MockAPITapByResourceClient) Recv() (*pb.TapEvent, error) {
var eventPopped pb.TapEvent
var errorPopped error
@ -110,37 +121,41 @@ func (a *MockAPITapByResourceClient) Recv() (*pb.TapEvent, error) {
// Prometheus client
//
type MockProm struct {
type mockProm struct {
Res model.Value
QueriesExecuted []string // expose the queries our Mock Prometheus receives, to test query generation
rwLock sync.Mutex
}
// PodCounts is a test helper struct that is used for representing data in a
// StatTable.PodGroup.Row.
type PodCounts struct {
MeshedPods uint64
RunningPods uint64
FailedPods uint64
}
func (m *MockProm) Query(ctx context.Context, query string, ts time.Time) (model.Value, error) {
func (m *mockProm) Query(ctx context.Context, query string, ts time.Time) (model.Value, error) {
m.rwLock.Lock()
defer m.rwLock.Unlock()
m.QueriesExecuted = append(m.QueriesExecuted, query)
return m.Res, nil
}
func (m *MockProm) QueryRange(ctx context.Context, query string, r v1.Range) (model.Value, error) {
func (m *mockProm) QueryRange(ctx context.Context, query string, r v1.Range) (model.Value, error) {
m.rwLock.Lock()
defer m.rwLock.Unlock()
m.QueriesExecuted = append(m.QueriesExecuted, query)
return m.Res, nil
}
func (m *MockProm) LabelValues(ctx context.Context, label string) (model.LabelValues, error) {
func (m *mockProm) LabelValues(ctx context.Context, label string) (model.LabelValues, error) {
return nil, nil
}
func (m *MockProm) Series(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) ([]model.LabelSet, error) {
func (m *mockProm) Series(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) ([]model.LabelSet, error) {
return nil, nil
}
// GenStatSummaryResponse generates a mock Public API StatSummaryResponse
// object.
func GenStatSummaryResponse(resName, resType string, resNs []string, counts *PodCounts, basicStats bool) pb.StatSummaryResponse {
rows := []*pb.StatTable_PodGroup_Row{}
for _, ns := range resNs {
@ -192,6 +207,7 @@ func GenStatSummaryResponse(resName, resType string, resNs []string, counts *Pod
return resp
}
// GenTopRoutesResponse generates a mock Public API TopRoutesResponse object.
func GenTopRoutesResponse(routes []string, counts []uint64) pb.TopRoutesResponse {
rows := []*pb.RouteTable_Row{}
for i, route := range routes {
@ -228,13 +244,13 @@ type expectedStatRPC struct {
expectedPrometheusQueries []string // queries we expect public-api to issue to prometheus
}
func newMockGrpcServer(exp expectedStatRPC) (*MockProm, *grpcServer, error) {
func newMockGrpcServer(exp expectedStatRPC) (*mockProm, *grpcServer, error) {
k8sAPI, err := k8s.NewFakeAPI("", exp.k8sConfigs...)
if err != nil {
return nil, nil, err
}
mockProm := &MockProm{Res: exp.mockPromResponse}
mockProm := &mockProm{Res: exp.mockPromResponse}
fakeGrpcServer := newGrpcServer(
mockProm,
tap.NewTapClient(nil),
@ -248,7 +264,7 @@ func newMockGrpcServer(exp expectedStatRPC) (*MockProm, *grpcServer, error) {
return mockProm, fakeGrpcServer, nil
}
func (exp expectedStatRPC) verifyPromQueries(mockProm *MockProm) error {
func (exp expectedStatRPC) verifyPromQueries(mockProm *mockProm) error {
// if exp.expectedPrometheusQueries is an empty slice we still wanna check no queries were executed.
if exp.expectedPrometheusQueries != nil {
sort.Strings(exp.expectedPrometheusQueries)

View File

@ -49,7 +49,7 @@ var (
)
// StatsBaseRequestParams contains parameters that are used to build requests
// for metrics data. This includes requests to StatSummary and TopRoutes
// for metrics data. This includes requests to StatSummary and TopRoutes.
type StatsBaseRequestParams struct {
TimeWindow string
Namespace string
@ -58,6 +58,8 @@ type StatsBaseRequestParams struct {
AllNamespaces bool
}
// StatsSummaryRequestParams contains parameters that are used to build
// StatSummary requests.
type StatsSummaryRequestParams struct {
StatsBaseRequestParams
ToNamespace string
@ -69,12 +71,16 @@ type StatsSummaryRequestParams struct {
SkipStats bool
}
// TopRoutesRequestParams contains parameters that are used to build TopRoutes
// requests.
type TopRoutesRequestParams struct {
StatsBaseRequestParams
To string
ToAll bool
}
// TapRequestParams contains parameters that are used to build a
// TapByResourceRequest.
type TapRequestParams struct {
Resource string
Namespace string
@ -119,6 +125,8 @@ func GRPCError(err error) error {
return err
}
// BuildStatSummaryRequest builds a Public API StatSummaryRequest from a
// StatsSummaryRequestParams.
func BuildStatSummaryRequest(p StatsSummaryRequestParams) (*pb.StatSummaryRequest, error) {
window := defaultMetricTimeWindow
if p.TimeWindow != "" {
@ -206,6 +214,8 @@ func BuildStatSummaryRequest(p StatsSummaryRequestParams) (*pb.StatSummaryReques
return statRequest, nil
}
// BuildTopRoutesRequest builds a Public API TopRoutesRequest from a
// TopRoutesRequestParams.
func BuildTopRoutesRequest(p TopRoutesRequestParams) (*pb.TopRoutesRequest, error) {
window := defaultMetricTimeWindow
if p.TimeWindow != "" {
@ -372,6 +382,8 @@ func buildResource(namespace string, resType string, name string) (pb.Resource,
}, nil
}
// BuildTapByResourceRequest builds a Public API TapByResourceRequest from a
// TapRequestParams.
func BuildTapByResourceRequest(params TapRequestParams) (*pb.TapByResourceRequest, error) {
target, err := BuildResource(params.Namespace, params.Resource)
if err != nil {
@ -535,6 +547,8 @@ func routeLabels(event *pb.TapEvent) string {
return out
}
// RenderTapEvent renders a Public API TapEvent to a string.
// TODO: consider moving this into cli/cmd/tap.go.
func RenderTapEvent(event *pb.TapEvent, resource string) string {
dst := dst(event)
src := src(event)
@ -634,6 +648,8 @@ func RenderTapEvent(event *pb.TapEvent, resource string) string {
}
}
// GetRequestRate calculates request rate from Public API BasicStats.
// TODO: consider moving this into `/cli/cmd`.
func GetRequestRate(stats *pb.BasicStats, timeWindow string) float64 {
success := stats.SuccessCount
failure := stats.FailureCount
@ -645,6 +661,8 @@ func GetRequestRate(stats *pb.BasicStats, timeWindow string) float64 {
return float64(success+failure) / windowLength.Seconds()
}
// GetSuccessRate calculates success rate from Public API BasicStats.
// TODO: consider moving this into `/cli/cmd`.
func GetSuccessRate(stats *pb.BasicStats) float64 {
success := stats.SuccessCount
failure := stats.FailureCount
@ -655,6 +673,9 @@ func GetSuccessRate(stats *pb.BasicStats) float64 {
return float64(success) / float64(success+failure)
}
// GetPercentTLS calculates the percent of traffic that is TLS, from Public API
// BasicStats.
// TODO: consider moving this into `/cli/cmd/stat.go`.
func GetPercentTLS(stats *pb.BasicStats) float64 {
reqTotal := stats.SuccessCount + stats.FailureCount
if reqTotal == 0 {

View File

@ -48,6 +48,7 @@ type CA struct {
nextSerialNumber uint64
}
// CertificateAndPrivateKey encapsulates a certificate / private key pair.
type CertificateAndPrivateKey struct {
// The ASN.1 DER-encoded (binary, not PEM) certificate.
Certificate []byte

View File

@ -18,6 +18,8 @@ import (
"k8s.io/client-go/util/workqueue"
)
// CertificateController listens for added and updated meshed pods, and then
// provides certificates in the form of secrets.
type CertificateController struct {
namespace string
k8sAPI *k8s.API
@ -32,6 +34,8 @@ type CertificateController struct {
queue workqueue.RateLimitingInterface
}
// NewCertificateController initializes a CertificateController and its
// internal Certificate Authority.
func NewCertificateController(controllerNamespace string, k8sAPI *k8s.API, proxyAutoInject bool) (*CertificateController, error) {
ca, err := NewCA()
if err != nil {
@ -67,6 +71,7 @@ func NewCertificateController(controllerNamespace string, k8sAPI *k8s.API, proxy
return c, nil
}
// Run kicks off CertificateController queue processing.
func (c *CertificateController) Run(stopCh <-chan struct{}) {
defer runtime.HandleCrash()
defer c.queue.ShutDown()

View File

@ -1,3 +1,4 @@
package serviceprofile
// GroupName identifies the API Group Name for a ServiceProfile.
const GroupName = "linkerd.io"

View File

@ -26,8 +26,15 @@ func Resource(resource string) schema.GroupResource {
}
var (
// SchemeBuilder collects functions that add things to a scheme. It's to allow
// code to compile without explicitly referencing generated types. You should
// declare one in each package that will have generated deep copy or conversion
// functions.
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
// AddToScheme applies all the stored functions to the scheme. A non-nil error
// indicates that one function failed and the attempt was abandoned.
AddToScheme = SchemeBuilder.AddToScheme
)
// Adds the list of known types to Scheme.

View File

@ -25,16 +25,19 @@ type ServiceProfile struct {
Spec ServiceProfileSpec `json:"spec"`
}
// ServiceProfileSpec specifies a ServiceProfile resource.
type ServiceProfileSpec struct {
Routes []*RouteSpec `json:"routes"`
}
// RouteSpec specifies a Route resource.
type RouteSpec struct {
Name string `json:"name"`
Condition *RequestMatch `json:"condition"`
ResponseClasses []*ResponseClass `json:"responseClasses,omitempty"`
}
// RequestMatch describes the conditions under which to match a Route.
type RequestMatch struct {
All []*RequestMatch `json:"all,omitempty"`
Not *RequestMatch `json:"not,omitempty"`
@ -43,11 +46,14 @@ type RequestMatch struct {
Method string `json:"method,omitempty"`
}
// ResponseClass describes how to classify a response (e.g. success or
// failures).
type ResponseClass struct {
Condition *ResponseMatch `json:"condition"`
IsFailure bool `json:"isFailure,omitempty"`
}
// ResponseMatch describes the conditions under which to classify a response.
type ResponseMatch struct {
All []*ResponseMatch `json:"all,omitempty"`
Not *ResponseMatch `json:"not,omitempty"`
@ -55,6 +61,7 @@ type ResponseMatch struct {
Status *Range `json:"status,omitempty"`
}
// Range describes a range of integers (e.g. status codes).
type Range struct {
Min uint32 `json:"min,omitempty"`
Max uint32 `json:"max,omitempty"`
@ -62,7 +69,7 @@ type Range struct {
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// ServiceProfileList is a list of ServiceProfile resources
// ServiceProfileList is a list of ServiceProfile resources.
type ServiceProfileList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata"`

View File

@ -26,8 +26,11 @@ import (
"k8s.io/client-go/tools/cache"
)
// APIResource is an enum for Kubernetes API resource types, for use when
// initializing a K8s API, to describe which resource types to interact with.
type APIResource int
// These constants enumerate Kubernetes resource types.
const (
CM APIResource = iota
Deploy
@ -140,6 +143,7 @@ func (api *API) Sync() {
log.Infof("caches synced")
}
// Deploy provides access to a shared informer and lister for Deployments.
func (api *API) Deploy() appinformers.DeploymentInformer {
if api.deploy == nil {
panic("Deploy informer not configured")
@ -147,6 +151,7 @@ func (api *API) Deploy() appinformers.DeploymentInformer {
return api.deploy
}
// RS provides access to a shared informer and lister for ReplicaSets.
func (api *API) RS() appinformers.ReplicaSetInformer {
if api.rs == nil {
panic("RS informer not configured")
@ -154,6 +159,7 @@ func (api *API) RS() appinformers.ReplicaSetInformer {
return api.rs
}
// Pod provides access to a shared informer and lister for Pods.
func (api *API) Pod() coreinformers.PodInformer {
if api.pod == nil {
panic("Pod informer not configured")
@ -161,6 +167,8 @@ func (api *API) Pod() coreinformers.PodInformer {
return api.pod
}
// RC provides access to a shared informer and lister for
// ReplicationControllers.
func (api *API) RC() coreinformers.ReplicationControllerInformer {
if api.rc == nil {
panic("RC informer not configured")
@ -168,6 +176,7 @@ func (api *API) RC() coreinformers.ReplicationControllerInformer {
return api.rc
}
// Svc provides access to a shared informer and lister for Services.
func (api *API) Svc() coreinformers.ServiceInformer {
if api.svc == nil {
panic("Svc informer not configured")
@ -175,6 +184,7 @@ func (api *API) Svc() coreinformers.ServiceInformer {
return api.svc
}
// Endpoint provides access to a shared informer and lister for Endpoints.
func (api *API) Endpoint() coreinformers.EndpointsInformer {
if api.endpoint == nil {
panic("Endpoint informer not configured")
@ -182,6 +192,7 @@ func (api *API) Endpoint() coreinformers.EndpointsInformer {
return api.endpoint
}
// CM provides access to a shared informer and lister for ConfigMaps.
func (api *API) CM() coreinformers.ConfigMapInformer {
if api.cm == nil {
panic("CM informer not configured")
@ -189,6 +200,7 @@ func (api *API) CM() coreinformers.ConfigMapInformer {
return api.cm
}
// SP provides access to a shared informer and lister for ServiceProfiles.
func (api *API) SP() spinformers.ServiceProfileInformer {
if api.sp == nil {
panic("SP informer not configured")
@ -196,6 +208,7 @@ func (api *API) SP() spinformers.ServiceProfileInformer {
return api.sp
}
// MWC provides access to a shared informer and lister for MutatingWebhookConfigurations.
func (api *API) MWC() arinformers.MutatingWebhookConfigurationInformer {
if api.mwc == nil {
panic("MWC informer not configured")
@ -439,6 +452,8 @@ func (api *API) getServices(namespace, name string) ([]runtime.Object, error) {
return objects, nil
}
// GetServices returns a list of Service resources, based on input namespace and
// name.
func (api *API) GetServices(namespace, name string) ([]*apiv1.Service, error) {
var err error
var services []*apiv1.Service

View File

@ -4,10 +4,12 @@ import (
spclient "github.com/linkerd/linkerd2/controller/gen/client/clientset/versioned"
"github.com/linkerd/linkerd2/pkg/k8s"
"k8s.io/client-go/kubernetes"
// Load all the auth plugins for the cloud providers.
_ "k8s.io/client-go/plugin/pkg/client/auth"
)
// NewClientSet returns a Kubernetes client for the given configuration.
func NewClientSet(kubeConfig string) (*kubernetes.Clientset, error) {
config, err := k8s.GetConfig(kubeConfig, "")
if err != nil {
@ -17,6 +19,8 @@ func NewClientSet(kubeConfig string) (*kubernetes.Clientset, error) {
return kubernetes.NewForConfig(config)
}
// NewSpClientSet returns a Kubernetes ServiceProfile client for the given
// configuration.
func NewSpClientSet(kubeConfig string) (*spclient.Clientset, error) {
config, err := k8s.GetConfig(kubeConfig, "")
if err != nil {

View File

@ -18,6 +18,7 @@ func toRuntimeObject(config string) (runtime.Object, error) {
return obj, err
}
// NewFakeAPI provides a mock Kubernetes API for testing.
func NewFakeAPI(namespace string, configs ...string) (*API, error) {
objs := []runtime.Object{}
spObjs := []runtime.Object{}

View File

@ -11,6 +11,7 @@ import (
corev1 "k8s.io/api/core/v1"
)
// These constants provide default, fake strings for testing proxy-injector.
const (
DefaultControllerNamespace = "linkerd"
DefaultNamespace = "default"

View File

@ -1,5 +1,7 @@
package tmpl
// MutatingWebhookConfigurationSpec provides a template for a
// MutatingWebhookConfiguration.
var MutatingWebhookConfigurationSpec = `
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration

View File

@ -5,6 +5,7 @@ import (
"google.golang.org/grpc"
)
// NewClient creates a client for the control-plane's Tap service.
func NewClient(addr string) (pb.TapClient, *grpc.ClientConn, error) {
conn, err := grpc.Dial(addr, grpc.WithInsecure())
if err != nil {

View File

@ -9,21 +9,25 @@ import (
"github.com/linkerd/linkerd2/controller/gen/public"
)
// PublicAddressToString formats a Public API TCPAddress as a string.
func PublicAddressToString(addr *public.TcpAddress) string {
octects := decodeIPToOctets(addr.GetIp().GetIpv4())
return fmt.Sprintf("%d.%d.%d.%d:%d", octects[0], octects[1], octects[2], octects[3], addr.GetPort())
}
// PublicIPToString formats a Public API IPAddress as a string.
func PublicIPToString(ip *public.IPAddress) string {
octets := decodeIPToOctets(ip.GetIpv4())
return fmt.Sprintf("%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3])
}
// ProxyAddressToString formats a Proxy API TCPAddress as a string.
func ProxyAddressToString(addr *pb.TcpAddress) string {
octects := decodeIPToOctets(addr.GetIp().GetIpv4())
return fmt.Sprintf("%d.%d.%d.%d:%d", octects[0], octects[1], octects[2], octects[3], addr.GetPort())
}
// ProxyAddressesToString formats a list of Proxy API TCPAddresses as a string.
func ProxyAddressesToString(addrs []pb.TcpAddress) string {
addrStrs := make([]string, len(addrs))
for i := range addrs {
@ -32,11 +36,13 @@ func ProxyAddressesToString(addrs []pb.TcpAddress) string {
return "[" + strings.Join(addrStrs, ",") + "]"
}
// ProxyIPToString formats a Proxy API IPAddress as a string.
func ProxyIPToString(ip *pb.IPAddress) string {
octets := decodeIPToOctets(ip.GetIpv4())
return fmt.Sprintf("%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3])
}
// ProxyIPV4 encodes 4 octets as a Proxy API IPAddress.
func ProxyIPV4(a1, a2, a3, a4 uint8) *pb.IPAddress {
ip := (uint32(a1) << 24) | (uint32(a2) << 16) | (uint32(a3) << 8) | uint32(a4)
return &pb.IPAddress{
@ -46,6 +52,7 @@ func ProxyIPV4(a1, a2, a3, a4 uint8) *pb.IPAddress {
}
}
// ParseProxyIPV4 parses an IP Address string into a Proxy API IPAddress.
func ParseProxyIPV4(ip string) (*pb.IPAddress, error) {
segments := strings.Split(ip, ".")
if len(segments) != 4 {
@ -62,6 +69,7 @@ func ParseProxyIPV4(ip string) (*pb.IPAddress, error) {
return ProxyIPV4(octets[0], octets[1], octets[2], octets[3]), nil
}
// PublicIPV4 encodes 4 octets as a Public API IPAddress.
func PublicIPV4(a1, a2, a3, a4 uint8) *public.IPAddress {
ip := (uint32(a1) << 24) | (uint32(a2) << 16) | (uint32(a3) << 8) | uint32(a4)
return &public.IPAddress{
@ -71,6 +79,7 @@ func PublicIPV4(a1, a2, a3, a4 uint8) *public.IPAddress {
}
}
// ParsePublicIPV4 parses an IP Address string into a Public API IPAddress.
func ParsePublicIPV4(ip string) (*public.IPAddress, error) {
segments := strings.Split(ip, ".")
if len(segments) != 4 {

View File

@ -12,6 +12,7 @@ type handler struct {
promHandler http.Handler
}
// StartServer starts an admin server listening on a given address.
func StartServer(addr string) {
log.Infof("starting admin server on %s", addr)

View File

@ -12,6 +12,8 @@ import (
"os"
)
// FileSystem provides access to a collection of named files via
// http.FileSystem, given a directory.
func FileSystem(dir string) http.FileSystem {
return fileSystem{http.Dir(dir)}
}

View File

@ -21,6 +21,7 @@ import (
"k8s.io/client-go/kubernetes"
)
// Checks is an enum for the types of health checks.
type Checks int
const (
@ -56,11 +57,19 @@ const (
// and ShouldCheckDataPlaneVersion options are false.
LinkerdVersionChecks
KubernetesAPICategory = "kubernetes-api"
// KubernetesAPICategory is the string representation of KubernetesAPIChecks.
KubernetesAPICategory = "kubernetes-api"
// LinkerdPreInstallCategory is the string representation of
// LinkerdPreInstallChecks.
LinkerdPreInstallCategory = "kubernetes-setup"
LinkerdDataPlaneCategory = "linkerd-data-plane"
LinkerdAPICategory = "linkerd-api"
LinkerdVersionCategory = "linkerd-version"
// LinkerdDataPlaneCategory is the string representation of
// LinkerdDataPlaneChecks.
LinkerdDataPlaneCategory = "linkerd-data-plane"
// LinkerdAPICategory is the string representation of LinkerdAPIChecks.
LinkerdAPICategory = "linkerd-api"
// LinkerdVersionCategory is the string representation of
// LinkerdVersionChecks.
LinkerdVersionCategory = "linkerd-version"
)
var (
@ -100,6 +109,7 @@ type checker struct {
checkRPC func() (*healthcheckPb.SelfCheckResponse, error)
}
// CheckResult encapsulates a check's identifying information and output
type CheckResult struct {
Category string
Description string
@ -110,6 +120,7 @@ type CheckResult struct {
type checkObserver func(*CheckResult)
// Options specifies configuration for a HealthChecker.
type Options struct {
ControlPlaneNamespace string
DataPlaneNamespace string
@ -124,6 +135,8 @@ type Options struct {
SingleNamespace bool
}
// HealthChecker encapsulates all health check checkers, and clients required to
// perform those checks.
type HealthChecker struct {
checkers []*checker
*Options
@ -139,6 +152,7 @@ type HealthChecker struct {
latestVersion string
}
// NewHealthChecker returns an initialized HealthChecker
func NewHealthChecker(checks []Checks, options *Options) *HealthChecker {
hc := &HealthChecker{
checkers: make([]*checker, 0),

View File

@ -19,10 +19,13 @@ import (
var minAPIVersion = [3]int{1, 8, 0}
// KubernetesAPI provides a client for accessing a Kubernetes cluster.
type KubernetesAPI struct {
*rest.Config
}
// NewClient returns an http.Client configured with a Transport to connect to
// the Kubernetes cluster.
func (kubeAPI *KubernetesAPI) NewClient() (*http.Client, error) {
secureTransport, err := rest.TransportFor(kubeAPI.Config)
if err != nil {
@ -34,6 +37,7 @@ func (kubeAPI *KubernetesAPI) NewClient() (*http.Client, error) {
}, nil
}
// GetVersionInfo returns version.Info for the Kubernetes cluster.
func (kubeAPI *KubernetesAPI) GetVersionInfo(client *http.Client) (*version.Info, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
@ -58,6 +62,8 @@ func (kubeAPI *KubernetesAPI) GetVersionInfo(client *http.Client) (*version.Info
return &versionInfo, err
}
// CheckVersion validates whether the configured Kubernetes cluster's version is
// running a minimum Kubernetes API version.
func (kubeAPI *KubernetesAPI) CheckVersion(versionInfo *version.Info) error {
apiVersion, err := getK8sVersion(versionInfo.String())
if err != nil {
@ -73,6 +79,7 @@ func (kubeAPI *KubernetesAPI) CheckVersion(versionInfo *version.Info) error {
return nil
}
// NamespaceExists validates whether a given namespace exists.
func (kubeAPI *KubernetesAPI) NamespaceExists(client *http.Client, namespace string) (bool, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

View File

@ -8,6 +8,7 @@ import (
"k8s.io/client-go/tools/clientcmd"
)
// These constants are string representations of Kubernetes resource types.
const (
All = "all"
Authority = "authority"
@ -159,6 +160,10 @@ func ShortNameFromCanonicalResourceName(canonicalName string) string {
}
}
// KindToL5DLabel converts a Kubernetes `kind` to a Linkerd label.
// For example:
// `pod` -> `pod`
// `job` -> `k8s_job`
func KindToL5DLabel(k8sKind string) string {
if k8sKind == Job {
return l5dJob

View File

@ -120,7 +120,12 @@ const (
// that contains the actual trust anchor bundle.
TLSTrustAnchorFileName = "trust-anchors.pem"
TLSCertFileName = "certificate.crt"
// TLSCertFileName is the name (key) within proxy-injector ConfigMap that
// contains the TLS certificate.
TLSCertFileName = "certificate.crt"
// TLSPrivateKeyFileName is the name (key) within proxy-injector ConfigMap
// that contains the TLS private key.
TLSPrivateKeyFileName = "private-key.p8"
/*
@ -185,6 +190,7 @@ func GetPodLabels(ownerKind, ownerName string, pod *coreV1.Pod) map[string]strin
return labels
}
// IsMeshed returns whether a given Pod is in a given controller's service mesh.
func IsMeshed(pod *coreV1.Pod, controllerNS string) bool {
return pod.Labels[ControllerNSLabel] == controllerNS
}
@ -207,6 +213,7 @@ type TLSIdentity struct {
ControllerNamespace string
}
// ToDNSName formats a TLSIdentity as a DNS name.
func (i TLSIdentity) ToDNSName() string {
if i.Kind == Service {
return fmt.Sprintf("%s.%s.svc", i.Name, i.Namespace)
@ -215,10 +222,13 @@ func (i TLSIdentity) ToDNSName() string {
i.Kind, i.Namespace, i.ControllerNamespace)
}
// ToSecretName formats a TLSIdentity as a secret name.
func (i TLSIdentity) ToSecretName() string {
return fmt.Sprintf("%s-%s-tls-linkerd-io", i.Name, i.Kind)
}
// ToControllerIdentity returns the TLSIdentity of the Linkerd Controller, given
// an arbitrary TLSIdentity.
func (i TLSIdentity) ToControllerIdentity() TLSIdentity {
return TLSIdentity{
Name: "controller",

View File

@ -13,6 +13,7 @@ import (
_ "k8s.io/client-go/plugin/pkg/client/auth"
)
// KubernetesProxy provides a proxied connection into a Kubernetes cluster.
type KubernetesProxy struct {
listener net.Listener
server *proxy.Server

View File

@ -18,6 +18,7 @@ type profileTemplateConfig struct {
ClusterZone string
}
// ToRoute returns a Proxy API Route, given a ServiceProfile Route.
func ToRoute(route *sp.RouteSpec) (*pb.Route, error) {
cond, err := ToRequestMatch(route.Condition)
if err != nil {
@ -38,6 +39,8 @@ func ToRoute(route *sp.RouteSpec) (*pb.Route, error) {
}, nil
}
// ToResponseClass returns a Proxy API ResponseClass, given a ServiceProfile
// ResponseClass.
func ToResponseClass(rc *sp.ResponseClass) (*pb.ResponseClass, error) {
cond, err := ToResponseMatch(rc.Condition)
if err != nil {
@ -49,6 +52,8 @@ func ToResponseClass(rc *sp.ResponseClass) (*pb.ResponseClass, error) {
}, nil
}
// ToResponseMatch returns a Proxy API ResponseMatch, given a ServiceProfile
// ResponseMatch.
func ToResponseMatch(rspMatch *sp.ResponseMatch) (*pb.ResponseMatch, error) {
if rspMatch == nil {
return nil, errors.New("missing response match")
@ -134,6 +139,8 @@ func ToResponseMatch(rspMatch *sp.ResponseMatch) (*pb.ResponseMatch, error) {
}, nil
}
// ToRequestMatch returns a Proxy API RequestMatch, given a ServiceProfile
// RequestMatch.
func ToRequestMatch(reqMatch *sp.RequestMatch) (*pb.RequestMatch, error) {
if reqMatch == nil {
return nil, errors.New("missing request match")
@ -226,6 +233,8 @@ func ToRequestMatch(reqMatch *sp.RequestMatch) (*pb.RequestMatch, error) {
}, nil
}
// ValidateRequestMatch validates whether a ServiceProfile RequestMatch has at
// least one field set.
func ValidateRequestMatch(reqMatch *sp.RequestMatch) error {
matchKindSet := false
if reqMatch.All != nil {
@ -267,6 +276,8 @@ func ValidateRequestMatch(reqMatch *sp.RequestMatch) error {
return nil
}
// ValidateResponseMatch validates whether a ServiceProfile ResponseMatch has at
// least one field set, and sanity checks the Status Range.
func ValidateResponseMatch(rspMatch *sp.ResponseMatch) error {
invalidRangeErr := errors.New("Range maximum cannot be smaller than minimum")
matchKindSet := false
@ -318,6 +329,8 @@ func buildConfig(namespace, service, controlPlaneNamespace string) *profileTempl
}
}
// RenderProfileTemplate renders a ServiceProfile template to a buffer, given a
// namespace, service, and control plane namespace.
func RenderProfileTemplate(namespace, service, controlPlaneNamespace string, w io.Writer) error {
config := buildConfig(namespace, service, controlPlaneNamespace)
template, err := template.New("profile").Parse(Template)

View File

@ -9,6 +9,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// GenServiceProfile generates a mock ServiceProfile.
func GenServiceProfile(service, namespace, controlPlaneNamespace string) v1alpha1.ServiceProfile {
return v1alpha1.ServiceProfile{
TypeMeta: metav1.TypeMeta{
@ -44,6 +45,7 @@ func GenServiceProfile(service, namespace, controlPlaneNamespace string) v1alpha
}
}
// ServiceProfileYamlEquals validates whether two ServiceProfiles are equal.
func ServiceProfileYamlEquals(actual, expected v1alpha1.ServiceProfile) error {
if !reflect.DeepEqual(actual, expected) {
acutalYaml, err := yaml.Marshal(actual)

View File

@ -6,6 +6,7 @@ import (
"fmt"
)
// Supported TLS key types.
const (
KeyTypeRSA = "rsa"
KeyTypeECDSA = "ecdsa"

View File

@ -37,6 +37,8 @@ func init() {
}
}
// CheckClientVersion validates whether the Linkerd Public API client's version
// matches an expected version.
func CheckClientVersion(expectedVersion string) error {
if Version != expectedVersion {
return versionMismatchError(expectedVersion, Version)
@ -45,6 +47,8 @@ func CheckClientVersion(expectedVersion string) error {
return nil
}
// CheckServerVersion validates whether the Linkerd Public API server's version
// matches an expected version.
func CheckServerVersion(apiClient pb.ApiClient, expectedVersion string) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
@ -61,6 +65,8 @@ func CheckServerVersion(apiClient pb.ApiClient, expectedVersion string) error {
return nil
}
// GetLatestVersion performs an online request to check for the latest Linkerd
// version.
func GetLatestVersion(uuid string, source string) (string, error) {
url := fmt.Sprintf(versionCheckURL, Version, uuid, source)
req, err := http.NewRequest("GET", url, nil)

View File

@ -29,6 +29,8 @@ func newRootOptions() *rootOptions {
}
}
// NewRootCmd returns a configured cobra.Command for the `proxy-init` command.
// TODO: consider moving this to `/proxy-init/main.go`
func NewRootCmd() *cobra.Command {
options := newRootOptions()

View File

@ -10,16 +10,26 @@ import (
)
const (
RedirectAllMode = "redirect-all"
RedirectListedMode = "redirect-listed"
// RedirectAllMode indicates redirecting all ports.
RedirectAllMode = "redirect-all"
// RedirectListedMode indicates redirecting a given list of ports.
RedirectListedMode = "redirect-listed"
// IptablesPreroutingChainName specifies an iptables `PREROUTING` chain,
// responsible for packets that just arrived at the network interface.
IptablesPreroutingChainName = "PREROUTING"
IptablesOutputChainName = "OUTPUT"
// IptablesOutputChainName specifies an iptables `OUTPUT` chain.
IptablesOutputChainName = "OUTPUT"
)
var (
// ExecutionTraceID provides a unique identifier for this script's execution.
ExecutionTraceID = strconv.Itoa(int(time.Now().Unix()))
)
// FirewallConfiguration specifies how to configure a pod's iptables.
type FirewallConfiguration struct {
Mode string
PortsToRedirectInbound []int

View File

@ -20,6 +20,7 @@ const (
)
type (
// Server encapsulates the Linkerd control plane's web dashboard server.
Server struct {
templateDir string
staticDir string
@ -52,6 +53,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
s.router.ServeHTTP(w, req)
}
// NewServer returns an initialized `http.Server`, configured to listen on an
// address, render templates, and serve static assets, for a given Linkerd
// control plane.
func NewServer(addr, templateDir, staticDir, uuid, controllerNamespace string, singleNamespace bool, webpackDevServer string, reload bool, apiClient pb.ApiClient) *http.Server {
server := &Server{
templateDir: templateDir,
@ -118,6 +122,8 @@ func NewServer(addr, templateDir, staticDir, uuid, controllerNamespace string, s
return httpServer
}
// RenderTemplate writes a rendered template into a buffer, given an HTTP
// request and template information.
func (s *Server) RenderTemplate(w http.ResponseWriter, templateFile, templateName string, args interface{}) error {
log.Debugf("emitting template %s", templateFile)
template, err := s.loadTemplate(templateFile)

View File

@ -1,5 +1,6 @@
package srv
// FakeServer provides a mock of a Server in `/web/srv`.
func FakeServer() Server {
return Server{
templateDir: "../templates",