Skip to content

Commit

Permalink
Removed Version API from the public-api (#6000)
Browse files Browse the repository at this point in the history
* Removed `Version` API from the public-api

This is a sibling PR to #5993, and it's the second step towards removing the `linkerd-controller` pod.

This one deals with a replacement for the `Version` API, fetching instead the `linkerd-config` CM and retrieving the `LinkerdVersion` value.

## Changes to the public-api

- Removal of the `publicPb.ApiClient` entry from the `Client` interface
- Removal of the `publicPb.ApiServer` entry from the `Server` interface
- Removal of the `Version` and related methods from `client.go`, `grpc_server.go` and `http_server.go`

## Changes to `linkerd version`

- Removal of all references to the public API.
- Call `healthcheck.GetServerVersion` to retrieve the version

## Changes to `linkerd check`

- Removal of the "can query the control API" check from the "linkerd-api" section
- Addition of a new "can retrieve the control plane version" check under the "control-plane-version" section

## Changes to `linkerd-web`

- The version is now retrieved from the `linkerd-config` CM instead of a public-API call.
- Removal of all references to the public API.
- Removal of the `data-go-version` global attribute on the dashboard, which wasn't being used.

## Other changes

- Added `ValuesFromConfigMap` function in `values.go` to convert the `linkerd-config` CM into a `*Values` struct instance
- Removal of the `public` protobuf
- Refactor 'linkerd repair' to use the refactored 'healthcheck.GetServerVersion()' function
  • Loading branch information
alpeb committed Apr 16, 2021
1 parent b22b584 commit c24585e
Show file tree
Hide file tree
Showing 40 changed files with 533 additions and 1,491 deletions.
6 changes: 2 additions & 4 deletions bin/protoc-go.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@ bindir=$( cd "${0%/*}" && pwd )

go install -mod=readonly github.com/golang/protobuf/protoc-gen-go

rm -rf controller/gen/common controller/gen/public controller/gen/config viz/metrics-api/gen viz/tap/gen
mkdir -p controller/gen/common/net controller/gen/public viz/metrics-api/gen/viz viz/tap/gen/tap
rm -rf controller/gen/common controller/gen/config viz/metrics-api/gen viz/tap/gen
mkdir -p controller/gen/common/net viz/metrics-api/gen/viz viz/tap/gen/tap

"$bindir"/protoc -I proto --go_out=plugins=grpc,paths=source_relative:controller/gen proto/common/net.proto
"$bindir"/protoc -I proto --go_out=plugins=grpc,paths=source_relative:controller/gen proto/public.proto
"$bindir"/protoc -I proto --go_out=plugins=grpc,paths=source_relative:controller/gen proto/config/config.proto
"$bindir"/protoc -I proto -I viz/metrics-api/proto --go_out=plugins=grpc,paths=source_relative:viz/metrics-api/gen viz/metrics-api/proto/viz.proto
"$bindir"/protoc -I proto -I viz/tap/proto -I viz/metrics-api/proto --go_out=plugins=grpc,paths=source_relative:viz/tap/gen viz/tap/proto/viz_tap.proto

mv controller/gen/common/net.pb.go controller/gen/common/net/
mv controller/gen/public.pb.go controller/gen/public/
mv viz/metrics-api/gen/viz.pb.go viz/metrics-api/gen/viz/viz.pb.go
mv viz/tap/gen/viz_tap.pb.go viz/tap/gen/tap/viz_tap.pb.go
7 changes: 1 addition & 6 deletions cli/cmd/repair.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"time"

"github.com/golang/protobuf/ptypes"
"github.com/linkerd/linkerd2/controller/api/public"
pb "github.com/linkerd/linkerd2/controller/gen/config"
"github.com/linkerd/linkerd2/pkg/charts/linkerd2"
"github.com/linkerd/linkerd2/pkg/healthcheck"
Expand Down Expand Up @@ -77,11 +76,7 @@ func repair(ctx context.Context, forced bool) error {
// Check if the CLI version matches with that of the server
clientVersion := version.Version
var serverVersion string
publicClient, err := public.NewExternalClient(ctx, controlPlaneNamespace, k8sAPI)
if err != nil {
return err
}
serverVersion, err = healthcheck.GetServerVersion(ctx, publicClient)
serverVersion, err = healthcheck.GetServerVersion(ctx, controlPlaneNamespace, k8sAPI)
if err != nil {
return err
}
Expand Down
21 changes: 6 additions & 15 deletions cli/cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ import (
"os"
"time"

publicPb "github.com/linkerd/linkerd2/controller/gen/public"
"github.com/linkerd/linkerd2/pkg/healthcheck"
"github.com/linkerd/linkerd2/pkg/k8s"
api "github.com/linkerd/linkerd2/pkg/public"
"github.com/linkerd/linkerd2/pkg/version"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -51,7 +49,7 @@ func newCmdVersion() *cobra.Command {
}
}

configureAndRunVersion(cmd.Context(), k8sAPI, options, os.Stdout, api.RawPublicAPIClient)
configureAndRunVersion(k8sAPI, options, os.Stdout)
return nil
},
}
Expand All @@ -65,11 +63,9 @@ func newCmdVersion() *cobra.Command {
}

func configureAndRunVersion(
ctx context.Context,
k8sAPI *k8s.KubernetesAPI,
options *versionOptions,
stdout io.Writer,
mkPublicClient func(ctx context.Context, k8sAPI *k8s.KubernetesAPI, controlPlaneNamespace, apiAddr string) (publicPb.ApiClient, error),
) {
clientVersion := version.Version
if options.shortVersion {
Expand All @@ -79,16 +75,11 @@ func configureAndRunVersion(
}

if !options.onlyClientVersion {
serverVersion := defaultVersionString
publicClient, clientErr := mkPublicClient(ctx, k8sAPI, controlPlaneNamespace, apiAddr)
if clientErr == nil {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
var err error
serverVersion, err = healthcheck.GetServerVersion(ctx, publicClient)
if err != nil {
serverVersion = defaultVersionString
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
serverVersion, err := healthcheck.GetServerVersion(ctx, controlPlaneNamespace, k8sAPI)
if err != nil {
serverVersion = defaultVersionString
}

if options.shortVersion {
Expand Down
77 changes: 0 additions & 77 deletions cli/cmd/version_test.go

This file was deleted.

64 changes: 1 addition & 63 deletions controller/api/public/client.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
package public

import (
"bufio"
"bytes"
"context"
"fmt"
"net/http"
"net/url"

"github.com/golang/protobuf/proto"
publicPb "github.com/linkerd/linkerd2/controller/gen/public"
"github.com/linkerd/linkerd2/pkg/k8s"
"github.com/linkerd/linkerd2/pkg/protohttp"
log "github.com/sirupsen/logrus"
"go.opencensus.io/plugin/ochttp"
"google.golang.org/grpc"
)

const (
apiRoot = "/" // Must be absolute (with a leading slash).
apiVersion = "v1"
apiPrefix = "api/" + apiVersion + "/" // Must be relative (without a leading slash).
apiPort = 8085
apiDeployment = "linkerd-controller"
)

// Client wraps one gRPC client interface for publicPb.Api:
// Client wraps one gRPC client interface for destination
type Client interface {
publicPb.ApiClient
}

type grpcOverHTTPClient struct {
Expand All @@ -36,60 +28,6 @@ type grpcOverHTTPClient struct {
controlPlaneNamespace string
}

func (c *grpcOverHTTPClient) Version(ctx context.Context, req *publicPb.Empty, _ ...grpc.CallOption) (*publicPb.VersionInfo, error) {
var msg publicPb.VersionInfo
err := c.apiRequest(ctx, "Version", req, &msg)
return &msg, err
}

func (c *grpcOverHTTPClient) apiRequest(ctx context.Context, endpoint string, req proto.Message, protoResponse proto.Message) error {
url := c.endpointNameToPublicAPIURL(endpoint)

log.Debugf("Making gRPC-over-HTTP call to [%s] [%+v]", url.String(), req)
httpRsp, err := c.post(ctx, url, req)
if err != nil {
return err
}
defer httpRsp.Body.Close()
log.Debugf("gRPC-over-HTTP call returned status [%s] and content length [%d]", httpRsp.Status, httpRsp.ContentLength)

if err := protohttp.CheckIfResponseHasError(httpRsp); err != nil {
return err
}

reader := bufio.NewReader(httpRsp.Body)
return protohttp.FromByteStreamToProtocolBuffers(reader, protoResponse)
}

func (c *grpcOverHTTPClient) post(ctx context.Context, url *url.URL, req proto.Message) (*http.Response, error) {
reqBytes, err := proto.Marshal(req)
if err != nil {
return nil, err
}

httpReq, err := http.NewRequest(
http.MethodPost,
url.String(),
bytes.NewReader(reqBytes),
)
if err != nil {
return nil, err
}

rsp, err := c.httpClient.Do(httpReq.WithContext(ctx))
if err != nil {
log.Debugf("Error invoking [%s]: %v", url.String(), err)
} else {
log.Debugf("Response from [%s] had headers: %v", url.String(), rsp.Header)
}

return rsp, err
}

func (c *grpcOverHTTPClient) endpointNameToPublicAPIURL(endpoint string) *url.URL {
return c.serverURL.ResolveReference(&url.URL{Path: endpoint})
}

func newClient(apiURL *url.URL, httpClientToUse *http.Client, controlPlaneNamespace string) (Client, error) {
if !apiURL.IsAbs() {
return nil, fmt.Errorf("server URL must be absolute, was [%s]", apiURL.String())
Expand Down
86 changes: 0 additions & 86 deletions controller/api/public/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,85 +3,15 @@ package public
import (
"bufio"
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"testing"

"github.com/golang/protobuf/proto"
publicPb "github.com/linkerd/linkerd2/controller/gen/public"
"github.com/linkerd/linkerd2/pkg/protohttp"
pb "github.com/linkerd/linkerd2/viz/metrics-api/gen/viz"
)

type mockTransport struct {
responseToReturn *http.Response
requestSent *http.Request
errorToReturn error
}

func (m *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
m.requestSent = req
return m.responseToReturn, m.errorToReturn
}

func TestNewInternalClient(t *testing.T) {
t.Run("Makes a well-formed request over the Kubernetes public API", func(t *testing.T) {
mockTransport := &mockTransport{}
mockTransport.responseToReturn = &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bufferedReader(t, &pb.Empty{})),
}
mockHTTPClient := &http.Client{
Transport: mockTransport,
}

apiURL := &url.URL{
Scheme: "http",
Host: "some-hostname",
Path: "/",
}
client, err := newClient(apiURL, mockHTTPClient, "linkerd")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}

_, err = client.Version(context.Background(), &publicPb.Empty{})
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}

expectedURLRequested := "http://some-hostname/api/v1/Version"
actualURLRequested := mockTransport.requestSent.URL.String()
if actualURLRequested != expectedURLRequested {
t.Fatalf("Expected request to URL [%v], but got [%v]", expectedURLRequested, actualURLRequested)
}
})
}

func TestFromByteStreamToProtocolBuffers(t *testing.T) {
t.Run("Correctly marshalls an valid object", func(t *testing.T) {
versionInfo := publicPb.VersionInfo{
GoVersion: "1.9.1",
BuildDate: "2017.11.17",
ReleaseVersion: "1.2.3",
}

var protobufMessageToBeFilledWithData publicPb.VersionInfo
reader := bufferedReader(t, &versionInfo)

err := protohttp.FromByteStreamToProtocolBuffers(reader, &protobufMessageToBeFilledWithData)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}

if !proto.Equal(&protobufMessageToBeFilledWithData, &versionInfo) {
t.Fatalf("mismatch, %s != %s", protobufMessageToBeFilledWithData.String(), versionInfo.String())
}
})

t.Run("Correctly marshalls a large byte array", func(t *testing.T) {
rows := make([]*pb.StatTable_PodGroup_Row, 0)

Expand Down Expand Up @@ -137,22 +67,6 @@ func TestFromByteStreamToProtocolBuffers(t *testing.T) {
t.Fatalf("Expected object to contain message [%s], but got [%s]", expectedErrorMessage, actualErrorMessage)
}
})

t.Run("Returns error if byte stream contains wrong object", func(t *testing.T) {
versionInfo := &publicPb.VersionInfo{
GoVersion: "1.9.1",
BuildDate: "2017.11.17",
ReleaseVersion: "1.2.3",
}

reader := bufferedReader(t, versionInfo)

protobufMessageToBeFilledWithData := &pb.StatSummaryResponse{}
err := protohttp.FromByteStreamToProtocolBuffers(reader, protobufMessageToBeFilledWithData)
if err == nil {
t.Fatal("Expecting error, got nothing")
}
})
}

func bufferedReader(t *testing.T, msg proto.Message) *bufio.Reader {
Expand Down
Loading

0 comments on commit c24585e

Please sign in to comment.