mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
[Feature] New gRPC and HTTP listeners (#1036)
This commit is contained in:
parent
b153b7183a
commit
583532e665
18 changed files with 1067 additions and 10 deletions
|
@ -60,6 +60,7 @@
|
|||
- (Bugfix) Infinite loop fix in ArangoD AsyncClient
|
||||
- (Bugfix) Add Panic Handler
|
||||
- (Bugfix) Unify yaml packages
|
||||
- (Feature) Add new GRPC and HTTP API
|
||||
|
||||
## [1.2.13](https://github.com/arangodb/kube-arangodb/tree/1.2.13) (2022-06-07)
|
||||
- (Bugfix) Fix arangosync members state inspection
|
||||
|
|
33
Makefile
33
Makefile
|
@ -89,6 +89,14 @@ else
|
|||
COMPILE_DEBUG_FLAGS :=
|
||||
endif
|
||||
|
||||
PROTOC_VERSION := 21.1
|
||||
ifeq ($(shell uname),Darwin)
|
||||
PROTOC_ARCHIVE_SUFFIX := osx-universal_binary
|
||||
else
|
||||
PROTOC_ARCHIVE_SUFFIX := linux-x86_64
|
||||
endif
|
||||
PROTOC_URL := https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-${PROTOC_ARCHIVE_SUFFIX}.zip
|
||||
|
||||
ifeq ($(MANIFESTSUFFIX),-)
|
||||
# Release setting
|
||||
MANIFESTSUFFIX :=
|
||||
|
@ -157,7 +165,7 @@ endif
|
|||
|
||||
EXCLUDE_DIRS := vendor .gobuild deps tools pkg/generated/clientset pkg/generated/informers pkg/generated/listers
|
||||
EXCLUDE_FILES := *generated.deepcopy.go
|
||||
SOURCES_QUERY := find ./ -type f -name '*.go' $(foreach EXCLUDE_DIR,$(EXCLUDE_DIRS), ! -path "*/$(EXCLUDE_DIR)/*") $(foreach EXCLUDE_FILE,$(EXCLUDE_FILES), ! -path "*/$(EXCLUDE_FILE)")
|
||||
SOURCES_QUERY := find ./ -type f -name '*.go' ! -name '*.pb.go' $(foreach EXCLUDE_DIR,$(EXCLUDE_DIRS), ! -path "*/$(EXCLUDE_DIR)/*") $(foreach EXCLUDE_FILE,$(EXCLUDE_FILES), ! -path "*/$(EXCLUDE_FILE)")
|
||||
SOURCES := $(shell $(SOURCES_QUERY))
|
||||
DASHBOARDSOURCES := $(shell find $(DASHBOARDDIR)/src -name '*.js') $(DASHBOARDDIR)/package.json
|
||||
LINT_EXCLUDES:=
|
||||
|
@ -167,6 +175,8 @@ else
|
|||
LINT_EXCLUDES+=.*\.enterprise\.go$$
|
||||
endif
|
||||
|
||||
PROTOSOURCES := $(shell find ./ -type f -name '*.proto' $(foreach EXCLUDE_DIR,$(EXCLUDE_DIRS), ! -path "*/$(EXCLUDE_DIR)/*") | sort)
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
.PHONY: all
|
||||
all: check-vars verify-generated build
|
||||
|
@ -185,7 +195,7 @@ allall: all
|
|||
.PHONY: license-verify
|
||||
license-verify:
|
||||
@echo ">> Verify license of files"
|
||||
@$(GOPATH)/bin/addlicense -f "./tools/codegen/license-header.txt" -check $(SOURCES)
|
||||
@$(GOPATH)/bin/addlicense -f "./tools/codegen/license-header.txt" -check $(SOURCES) $(PROTOSOURCES)
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
|
@ -196,7 +206,7 @@ fmt:
|
|||
.PHONY: license
|
||||
license:
|
||||
@echo ">> Ensuring license of files"
|
||||
@$(GOPATH)/bin/addlicense -f "./tools/codegen/license-header.txt" $(SOURCES)
|
||||
@$(GOPATH)/bin/addlicense -f "./tools/codegen/license-header.txt" $(SOURCES) $(PROTOSOURCES)
|
||||
|
||||
.PHONY: fmt-verify
|
||||
fmt-verify: license-verify
|
||||
|
@ -464,6 +474,13 @@ tools: update-vendor
|
|||
@GOBIN=$(GOPATH)/bin go install github.com/jessevdk/go-assets-builder@b8483521738fd2198ecfc378067a4e8a6079f8e5
|
||||
@echo ">> Fetching gci"
|
||||
@GOBIN=$(GOPATH)/bin go install github.com/daixiang0/gci@v0.3.0
|
||||
@echo ">> Downloading protobuf compiler..."
|
||||
@curl -L ${PROTOC_URL} -o $(GOPATH)/protoc.zip
|
||||
@echo ">> Unzipping protobuf compiler..."
|
||||
@unzip -o $(GOPATH)/protoc.zip -d $(GOPATH)/
|
||||
@echo ">> Fetching protoc go plugins..."
|
||||
@GOBIN=$(GOPATH)/bin go install github.com/golang/protobuf/protoc-gen-go@v1.5.2
|
||||
@GOBIN=$(GOPATH)/bin go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
|
||||
|
||||
.PHONY: vendor
|
||||
vendor:
|
||||
|
@ -532,5 +549,13 @@ check-community:
|
|||
_check:
|
||||
@$(MAKE) fmt license-verify linter run-unit-tests bin
|
||||
|
||||
generate: generate-internal generate-proto fmt
|
||||
|
||||
generate-internal:
|
||||
ROOT=$(ROOT) go test --count=1 "$(REPOPATH)/internal/..."
|
||||
ROOT=$(ROOT) go test --count=1 "$(REPOPATH)/internal/..."
|
||||
|
||||
generate-proto:
|
||||
PATH=$(PATH):$(GOBUILDDIR)/bin $(GOBUILDDIR)/bin/protoc -I.:$(GOBUILDDIR)/include/ \
|
||||
--go_out=. --go_opt=paths=source_relative \
|
||||
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
|
||||
$(PROTOSOURCES)
|
|
@ -19,6 +19,14 @@ spec:
|
|||
port: 8528
|
||||
protocol: TCP
|
||||
targetPort: 8528
|
||||
- name: http-api
|
||||
port: 8628
|
||||
protocol: TCP
|
||||
targetPort: 8628
|
||||
- name: grpc-api
|
||||
port: 8728
|
||||
protocol: TCP
|
||||
targetPort: 8728
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ template "kube-arangodb.name" . }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
|
|
52
cmd/cmd.go
52
cmd/cmd.go
|
@ -45,6 +45,7 @@ import (
|
|||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/klog"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/api"
|
||||
deploymentApi "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||
"github.com/arangodb/kube-arangodb/pkg/crd"
|
||||
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
||||
|
@ -68,8 +69,12 @@ import (
|
|||
const (
|
||||
defaultServerHost = "0.0.0.0"
|
||||
defaultServerPort = 8528
|
||||
defaultAPIHTTPPort = 8628
|
||||
defaultAPIGRPCPort = 8728
|
||||
defaultLogLevel = "debug"
|
||||
defaultAdminSecretName = "arangodb-operator-dashboard"
|
||||
defaultAPIJWTSecretName = "arangodb-operator-api-jwt"
|
||||
defaultAPIJWTKeySecretName = "arangodb-operator-api-jwt-key"
|
||||
defaultAlpineImage = "alpine:3.7"
|
||||
defaultMetricsExporterImage = "arangodb/arangodb-exporter:0.1.6"
|
||||
defaultArangoImage = "arangodb/arangodb:latest"
|
||||
|
@ -98,6 +103,14 @@ var (
|
|||
adminSecretName string // Name of basic authentication secret containing the admin username+password of the dashboard
|
||||
allowAnonymous bool // If set, anonymous access to dashboard is allowed
|
||||
}
|
||||
apiOptions struct {
|
||||
enabled bool
|
||||
httpPort int
|
||||
grpcPort int
|
||||
jwtSecretName string
|
||||
jwtKeySecretName string
|
||||
tlsSecretName string
|
||||
}
|
||||
operatorOptions struct {
|
||||
enableDeployment bool // Run deployment operator
|
||||
enableDeploymentReplication bool // Run deployment-replication operator
|
||||
|
@ -158,6 +171,12 @@ func init() {
|
|||
f.StringVar(&serverOptions.adminSecretName, "server.admin-secret-name", defaultAdminSecretName, "Name of secret containing username + password for login to the dashboard")
|
||||
f.BoolVar(&serverOptions.allowAnonymous, "server.allow-anonymous-access", false, "Allow anonymous access to the dashboard")
|
||||
f.StringArrayVar(&logLevels, "log.level", []string{defaultLogLevel}, fmt.Sprintf("Set log levels in format <level> or <logger>=<level>. Possible loggers: %s", strings.Join(logging.Global().Names(), ", ")))
|
||||
f.BoolVar(&apiOptions.enabled, "api.enabled", true, "Enable operator HTTP and gRPC API")
|
||||
f.IntVar(&apiOptions.httpPort, "api.http-port", defaultAPIHTTPPort, "HTTP API port to listen on")
|
||||
f.IntVar(&apiOptions.grpcPort, "api.grpc-port", defaultAPIGRPCPort, "gRPC API port to listen on")
|
||||
f.StringVar(&apiOptions.tlsSecretName, "api.tls-secret-name", "", "Name of secret containing tls.crt & tls.key for HTTPS API (if empty, self-signed certificate is used)")
|
||||
f.StringVar(&apiOptions.jwtSecretName, "api.jwt-secret-name", defaultAPIJWTSecretName, "Name of secret which will contain JWT to authenticate API requests.")
|
||||
f.StringVar(&apiOptions.jwtKeySecretName, "api.jwt-key-secret-name", defaultAPIJWTKeySecretName, "Name of secret containing key used to sign JWT. If there is no such secret present, value will be saved here")
|
||||
f.BoolVar(&operatorOptions.enableDeployment, "operator.deployment", false, "Enable to run the ArangoDeployment operator")
|
||||
f.BoolVar(&operatorOptions.enableDeploymentReplication, "operator.deployment-replication", false, "Enable to run the ArangoDeploymentReplication operator")
|
||||
f.BoolVar(&operatorOptions.enableStorage, "operator.storage", false, "Enable to run the ArangoLocalStorage operator")
|
||||
|
@ -306,6 +325,37 @@ func executeMain(cmd *cobra.Command, args []string) {
|
|||
logger.Err(err).Fatal("Failed to create operator")
|
||||
}
|
||||
|
||||
if apiOptions.enabled {
|
||||
apiServerCfg := api.ServerConfig{
|
||||
Namespace: namespace,
|
||||
ServerName: name,
|
||||
ServerAltNames: []string{ip},
|
||||
HTTPAddress: net.JoinHostPort("0.0.0.0", strconv.Itoa(apiOptions.httpPort)),
|
||||
GRPCAddress: net.JoinHostPort("0.0.0.0", strconv.Itoa(apiOptions.grpcPort)),
|
||||
TLSSecretName: apiOptions.tlsSecretName,
|
||||
JWTSecretName: apiOptions.jwtSecretName,
|
||||
JWTKeySecretName: apiOptions.jwtKeySecretName,
|
||||
LivelinessProbe: &livenessProbe,
|
||||
ProbeDeployment: api.ReadinessProbeConfig{
|
||||
Enabled: cfg.EnableDeployment,
|
||||
Probe: &deploymentProbe,
|
||||
},
|
||||
ProbeDeploymentReplication: api.ReadinessProbeConfig{
|
||||
Enabled: cfg.EnableDeploymentReplication,
|
||||
Probe: &deploymentReplicationProbe,
|
||||
},
|
||||
ProbeStorage: api.ReadinessProbeConfig{
|
||||
Enabled: cfg.EnableStorage,
|
||||
Probe: &storageProbe,
|
||||
},
|
||||
}
|
||||
apiServer, err := api.NewServer(client.Kubernetes().CoreV1(), apiServerCfg)
|
||||
if err != nil {
|
||||
logger.Err(err).Fatal("Failed to create API server")
|
||||
}
|
||||
go utilsError.LogError(logger, "while running API server", apiServer.Run)
|
||||
}
|
||||
|
||||
listenAddr := net.JoinHostPort(serverOptions.host, strconv.Itoa(serverOptions.port))
|
||||
if svr, err := server.NewServer(client.Kubernetes().CoreV1(), server.Config{
|
||||
Namespace: namespace,
|
||||
|
@ -348,7 +398,7 @@ func executeMain(cmd *cobra.Command, args []string) {
|
|||
}); err != nil {
|
||||
logger.Err(err).Fatal("Failed to create HTTP server")
|
||||
} else {
|
||||
go utilsError.LogError(logger, "error while starting service", svr.Run)
|
||||
go utilsError.LogError(logger, "error while starting server", svr.Run)
|
||||
}
|
||||
|
||||
// startChaos(context.Background(), cfg.KubeCli, cfg.Namespace, chaosLevel)
|
||||
|
|
|
@ -13,3 +13,4 @@
|
|||
- [Additional configuration](./additional_configuration.md)
|
||||
- [Topology awareness](./topology_awareness.md)
|
||||
- [Configuring timezone](./configuring_tz.md)
|
||||
- [Operator API](./api.md)
|
||||
|
|
30
docs/design/api.md
Normal file
30
docs/design/api.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Operator API
|
||||
|
||||
A running operator exposes HTTP and gRPC API listeners to allow retrieving and setting some configuration values programmatically.
|
||||
Both listeners require a secured connection to be established. It is possible to provide TLS certificate via k8s secret
|
||||
using command line option `--api.tls-secret-name`. If secret name is not provided, operator will use self-signed certificate.
|
||||
|
||||
Some HTTP endpoints require the authorization to work with. All gRPC endpoints require the authorization.
|
||||
The authorization can be accomplished by providing JWT token in 'Authorization' header, e.g. `Authorization: Bearer <token>`
|
||||
The JWT token can be fetched from k8s secret (by default `arangodb-operator-api-jwt`). The token is generated automatically
|
||||
on operator startup using the signing key specified in `arangodb-operator-api-jwt-key` secret. If it is empty or not exists,
|
||||
the signing key will be auto-generated and saved into secret. You can specify other signing key using `--api.jwt-key-secret-name` CLI option.
|
||||
|
||||
## HTTP
|
||||
|
||||
The HTTP API is running at endpoint specified by operator command line options `--api.http-port` (8628 by default).
|
||||
|
||||
The HTTP API exposes endpoints used to get operator health and readiness status, operator version, and prometheus-compatible metrics.
|
||||
|
||||
For now only `/metrics` endpoint require authorization.
|
||||
|
||||
|
||||
## gRPC
|
||||
|
||||
The gRPC API is running at endpoint specified by operator command line options `--api.grpc-port` (8728 by default).
|
||||
|
||||
The gRPC API is exposed to allow programmatic access to some operator features and status.
|
||||
|
||||
gRPC protobuf definitions and go-client can be found at `github.com/kube-arangodb/pkg/api/server` package.
|
||||
|
||||
All gRPC requests require per-RPC metadata set to contain a valid Authorization header.
|
11
go.mod
11
go.mod
|
@ -45,7 +45,9 @@ require (
|
|||
github.com/spf13/cobra v1.2.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.7.0
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
|
||||
google.golang.org/grpc v1.47.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
k8s.io/api v0.21.10
|
||||
k8s.io/apiextensions-apiserver v0.18.3
|
||||
|
@ -54,6 +56,11 @@ require (
|
|||
k8s.io/klog v1.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/arangodb/rebalancer v0.1.1 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
|
@ -68,7 +75,7 @@ require (
|
|||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/go-cmp v0.5.5 // indirect
|
||||
github.com/google/go-cmp v0.5.6 // indirect
|
||||
github.com/google/gofuzz v1.1.0 // indirect
|
||||
github.com/google/uuid v1.1.2 // indirect
|
||||
github.com/googleapis/gnostic v0.4.1 // indirect
|
||||
|
@ -95,7 +102,7 @@ require (
|
|||
golang.org/x/text v0.3.6 // indirect
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
google.golang.org/protobuf v1.28.0
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/klog/v2 v2.9.0 // indirect
|
||||
|
|
18
go.sum
18
go.sum
|
@ -97,6 +97,10 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
|||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
|
@ -132,6 +136,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
|||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
|
||||
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
|
@ -226,8 +231,9 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
|
@ -488,6 +494,7 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
|
@ -612,6 +619,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -822,6 +831,8 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D
|
|||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad h1:kqrS+lhvaMHCxul6sKQvKJ8nAAhlVItmZV822hYFH/U=
|
||||
google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
@ -842,6 +853,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
|
|||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
|
||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -854,8 +867,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
|||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
130
pkg/api/api.go
Normal file
130
pkg/api/api.go
Normal file
|
@ -0,0 +1,130 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
typedCore "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
|
||||
pb "github.com/arangodb/kube-arangodb/pkg/api/server"
|
||||
"github.com/arangodb/kube-arangodb/pkg/logging"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/probe"
|
||||
)
|
||||
|
||||
var apiLogger = logging.Global().RegisterAndGetLogger("api-server", logging.Info)
|
||||
|
||||
type Server struct {
|
||||
httpServer *http.Server
|
||||
grpcServer *grpc.Server
|
||||
grpcAddress string
|
||||
|
||||
pb.UnimplementedOperatorServer
|
||||
}
|
||||
|
||||
type ReadinessProbeConfig struct {
|
||||
Enabled bool
|
||||
Probe *probe.ReadyProbe
|
||||
}
|
||||
|
||||
// ServerConfig settings for the Server
|
||||
type ServerConfig struct {
|
||||
Namespace string
|
||||
ServerName string
|
||||
ServerAltNames []string
|
||||
HTTPAddress string
|
||||
GRPCAddress string
|
||||
TLSSecretName string
|
||||
JWTSecretName string
|
||||
JWTKeySecretName string
|
||||
LivelinessProbe *probe.LivenessProbe
|
||||
ProbeDeployment ReadinessProbeConfig
|
||||
ProbeDeploymentReplication ReadinessProbeConfig
|
||||
ProbeStorage ReadinessProbeConfig
|
||||
}
|
||||
|
||||
// NewServer creates and configure a new Server
|
||||
func NewServer(cli typedCore.CoreV1Interface, cfg ServerConfig) (*Server, error) {
|
||||
jwtSigningKey, err := ensureJWT(cli, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsConfig, err := prepareTLSConfig(cli, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
auth := &authorization{jwtSigningKey: jwtSigningKey}
|
||||
|
||||
s := &Server{
|
||||
httpServer: &http.Server{
|
||||
Addr: cfg.HTTPAddress,
|
||||
ReadTimeout: time.Second * 30,
|
||||
ReadHeaderTimeout: time.Second * 15,
|
||||
WriteTimeout: time.Second * 30,
|
||||
TLSConfig: tlsConfig,
|
||||
},
|
||||
grpcServer: grpc.NewServer(
|
||||
grpc.UnaryInterceptor(auth.ensureGRPCAuth),
|
||||
grpc.Creds(credentials.NewTLS(tlsConfig)),
|
||||
),
|
||||
grpcAddress: cfg.GRPCAddress,
|
||||
}
|
||||
handler, err := buildHTTPHandler(cfg, auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.httpServer.Handler = handler
|
||||
|
||||
pb.RegisterOperatorServer(s.grpcServer, s)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Server) Run() error {
|
||||
g := errgroup.Group{}
|
||||
g.Go(func() error {
|
||||
apiLogger.Info("Serving HTTP API on %s", s.httpServer.Addr)
|
||||
if err := s.httpServer.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
g.Go(func() error {
|
||||
apiLogger.Info("Serving GRPC API on %s", s.grpcAddress)
|
||||
ln, err := net.Listen("tcp", s.grpcAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ln.Close()
|
||||
|
||||
if err := s.grpcServer.Serve(ln); err != nil && err != grpc.ErrServerStopped {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return g.Wait()
|
||||
}
|
82
pkg/api/auth.go
Normal file
82
pkg/api/auth.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
jg "github.com/golang-jwt/jwt"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type authorization struct {
|
||||
jwtSigningKey string
|
||||
}
|
||||
|
||||
func (a *authorization) isValid(token string) bool {
|
||||
t, err := jg.Parse(token, func(_ *jg.Token) (interface{}, error) {
|
||||
return []byte(a.jwtSigningKey), nil
|
||||
})
|
||||
if err != nil {
|
||||
apiLogger.Err(err).Info("invalid JWT: %s", token)
|
||||
return false
|
||||
}
|
||||
return t.Valid
|
||||
}
|
||||
|
||||
// ensureHTTPAuth ensure a valid token exists within HTTP request header
|
||||
func (a *authorization) ensureHTTPAuth(c *gin.Context) {
|
||||
h := c.Request.Header.Values("Authorization")
|
||||
bearerToken := extractBearerToken(h)
|
||||
if !a.isValid(bearerToken) {
|
||||
c.AbortWithStatus(http.StatusUnauthorized)
|
||||
}
|
||||
}
|
||||
|
||||
// ensureGRPCAuth ensures a valid token exists within a GRPC request's metadata
|
||||
func (a *authorization) ensureGRPCAuth(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if !ok {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "missing metadata")
|
||||
}
|
||||
|
||||
// The keys within metadata.MD are normalized to lowercase.
|
||||
// See: https://godoc.org/google.golang.org/grpc/metadata#New
|
||||
bearerToken := extractBearerToken(md["authorization"])
|
||||
if !a.isValid(bearerToken) {
|
||||
return nil, status.Errorf(codes.Unauthenticated, "invalid token")
|
||||
}
|
||||
// Continue execution of handler after ensuring a valid token.
|
||||
return handler(ctx, req)
|
||||
}
|
||||
|
||||
func extractBearerToken(authorization []string) string {
|
||||
if len(authorization) < 1 {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimPrefix(authorization[0], "Bearer ")
|
||||
}
|
39
pkg/api/grpc.go
Normal file
39
pkg/api/grpc.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
pb "github.com/arangodb/kube-arangodb/pkg/api/server"
|
||||
"github.com/arangodb/kube-arangodb/pkg/version"
|
||||
)
|
||||
|
||||
func (s *Server) GetVersion(ctx context.Context, _ *pb.Empty) (*pb.Version, error) {
|
||||
v := version.GetVersionV1()
|
||||
return &pb.Version{
|
||||
Version: string(v.Version),
|
||||
Build: v.Build,
|
||||
Edition: string(v.Edition),
|
||||
GoVersion: v.GoVersion,
|
||||
BuildDate: v.BuildDate,
|
||||
}, nil
|
||||
}
|
79
pkg/api/http.go
Normal file
79
pkg/api/http.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
prometheus "github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
operatorHTTP "github.com/arangodb/kube-arangodb/pkg/util/http"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/probe"
|
||||
"github.com/arangodb/kube-arangodb/pkg/version"
|
||||
)
|
||||
|
||||
func buildHTTPHandler(cfg ServerConfig, auth *authorization) (http.Handler, error) {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r := gin.New()
|
||||
r.Use(gin.Recovery())
|
||||
|
||||
versionV1Responder, err := operatorHTTP.NewSimpleJSONResponse(version.GetVersionV1())
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
r.GET("/_api/version", gin.WrapF(versionV1Responder.ServeHTTP))
|
||||
r.GET("/api/v1/version", gin.WrapF(versionV1Responder.ServeHTTP))
|
||||
r.GET("/health", gin.WrapF(cfg.LivelinessProbe.LivenessHandler))
|
||||
|
||||
var readyProbes []*probe.ReadyProbe
|
||||
if cfg.ProbeDeployment.Enabled {
|
||||
r.GET("/ready/deployment", gin.WrapF(cfg.ProbeDeployment.Probe.ReadyHandler))
|
||||
readyProbes = append(readyProbes, cfg.ProbeDeployment.Probe)
|
||||
}
|
||||
if cfg.ProbeDeploymentReplication.Enabled {
|
||||
r.GET("/ready/deployment-replication", gin.WrapF(cfg.ProbeDeploymentReplication.Probe.ReadyHandler))
|
||||
readyProbes = append(readyProbes, cfg.ProbeDeploymentReplication.Probe)
|
||||
}
|
||||
if cfg.ProbeStorage.Enabled {
|
||||
r.GET("/ready/storage", gin.WrapF(cfg.ProbeStorage.Probe.ReadyHandler))
|
||||
readyProbes = append(readyProbes, cfg.ProbeStorage.Probe)
|
||||
}
|
||||
r.GET("/ready", gin.WrapF(handleGetReady(readyProbes...)))
|
||||
|
||||
r.GET("/metrics", auth.ensureHTTPAuth, gin.WrapH(prometheus.Handler()))
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func handleGetReady(probes ...*probe.ReadyProbe) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
for _, probe := range probes {
|
||||
if !probe.IsReady() {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
}
|
95
pkg/api/jwt.go
Normal file
95
pkg/api/jwt.go
Normal file
|
@ -0,0 +1,95 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
jg "github.com/golang-jwt/jwt"
|
||||
typedCore "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||
secret "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/secret/v1"
|
||||
)
|
||||
|
||||
// ensureJWT ensure that JWT signing key exists or creates a new one.
|
||||
// It also saves new token into secret if it is not present.
|
||||
// Returns JWT signing key.
|
||||
func ensureJWT(cli typedCore.CoreV1Interface, cfg ServerConfig) (string, error) {
|
||||
secrets := cli.Secrets(cfg.Namespace)
|
||||
|
||||
signingKey, err := k8sutil.GetTokenSecret(context.Background(), secrets, cfg.JWTKeySecretName)
|
||||
if err != nil && k8sutil.IsNotFound(err) || signingKey == "" {
|
||||
signingKey, err = createSigningKey(secrets, cfg.JWTKeySecretName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else if err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
|
||||
_, err = k8sutil.GetTokenSecret(context.Background(), secrets, cfg.JWTSecretName)
|
||||
if err != nil && k8sutil.IsNotFound(err) {
|
||||
err = generateAndSaveJWT(secrets, cfg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else if err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
return signingKey, nil
|
||||
}
|
||||
|
||||
// generateAndSaveJWT tries to generate new JWT using signing key retrieved from secret.
|
||||
// If it is not present, it creates a new key.
|
||||
// The resulting JWT is stored in secrets.
|
||||
func generateAndSaveJWT(secrets secret.Interface, cfg ServerConfig) error {
|
||||
claims := jg.MapClaims{
|
||||
"iss": fmt.Sprintf("kube-arangodb/%s", cfg.ServerName),
|
||||
"iat": time.Now().Unix(),
|
||||
}
|
||||
err := k8sutil.CreateJWTFromSecret(context.Background(), secrets, secrets, cfg.JWTSecretName, cfg.JWTKeySecretName, claims, nil)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func createSigningKey(secrets secret.ModInterface, keySecretName string) (string, error) {
|
||||
signingKey := make([]byte, 32)
|
||||
_, err := rand.Read(signingKey)
|
||||
if err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
|
||||
err = globals.GetGlobalTimeouts().Kubernetes().RunWithTimeout(context.Background(), func(ctxChild context.Context) error {
|
||||
return k8sutil.CreateTokenSecret(ctxChild, secrets, keySecretName, string(signingKey), nil)
|
||||
})
|
||||
if err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
return string(signingKey), nil
|
||||
}
|
261
pkg/api/server/operator.pb.go
Normal file
261
pkg/api/server/operator.pb.go
Normal file
|
@ -0,0 +1,261 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.21.1
|
||||
// source: pkg/api/server/operator.proto
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Empty struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *Empty) Reset() {
|
||||
*x = Empty{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_pkg_api_server_operator_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Empty) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Empty) ProtoMessage() {}
|
||||
|
||||
func (x *Empty) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_pkg_api_server_operator_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Empty.ProtoReflect.Descriptor instead.
|
||||
func (*Empty) Descriptor() ([]byte, []int) {
|
||||
return file_pkg_api_server_operator_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type Version struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
|
||||
Build string `protobuf:"bytes,2,opt,name=build,proto3" json:"build,omitempty"`
|
||||
Edition string `protobuf:"bytes,3,opt,name=edition,proto3" json:"edition,omitempty"`
|
||||
GoVersion string `protobuf:"bytes,4,opt,name=go_version,json=goVersion,proto3" json:"go_version,omitempty"`
|
||||
BuildDate string `protobuf:"bytes,5,opt,name=build_date,json=buildDate,proto3" json:"build_date,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Version) Reset() {
|
||||
*x = Version{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_pkg_api_server_operator_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Version) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Version) ProtoMessage() {}
|
||||
|
||||
func (x *Version) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_pkg_api_server_operator_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Version.ProtoReflect.Descriptor instead.
|
||||
func (*Version) Descriptor() ([]byte, []int) {
|
||||
return file_pkg_api_server_operator_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Version) GetVersion() string {
|
||||
if x != nil {
|
||||
return x.Version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Version) GetBuild() string {
|
||||
if x != nil {
|
||||
return x.Build
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Version) GetEdition() string {
|
||||
if x != nil {
|
||||
return x.Edition
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Version) GetGoVersion() string {
|
||||
if x != nil {
|
||||
return x.GoVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Version) GetBuildDate() string {
|
||||
if x != nil {
|
||||
return x.BuildDate
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_pkg_api_server_operator_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_pkg_api_server_operator_proto_rawDesc = []byte{
|
||||
0x0a, 0x1d, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x2f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||
0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79,
|
||||
0x22, 0x91, 0x01, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76,
|
||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x65, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65,
|
||||
0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x6f, 0x5f, 0x76, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x6f, 0x56, 0x65,
|
||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64,
|
||||
0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64,
|
||||
0x44, 0x61, 0x74, 0x65, 0x32, 0x3a, 0x0a, 0x08, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72,
|
||||
0x12, 0x2e, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0d,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x00,
|
||||
0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61,
|
||||
0x72, 0x61, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x6b, 0x75, 0x62, 0x65, 0x2d, 0x61, 0x72, 0x61,
|
||||
0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_pkg_api_server_operator_proto_rawDescOnce sync.Once
|
||||
file_pkg_api_server_operator_proto_rawDescData = file_pkg_api_server_operator_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_pkg_api_server_operator_proto_rawDescGZIP() []byte {
|
||||
file_pkg_api_server_operator_proto_rawDescOnce.Do(func() {
|
||||
file_pkg_api_server_operator_proto_rawDescData = protoimpl.X.CompressGZIP(file_pkg_api_server_operator_proto_rawDescData)
|
||||
})
|
||||
return file_pkg_api_server_operator_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_pkg_api_server_operator_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_pkg_api_server_operator_proto_goTypes = []interface{}{
|
||||
(*Empty)(nil), // 0: server.Empty
|
||||
(*Version)(nil), // 1: server.Version
|
||||
}
|
||||
var file_pkg_api_server_operator_proto_depIdxs = []int32{
|
||||
0, // 0: server.Operator.GetVersion:input_type -> server.Empty
|
||||
1, // 1: server.Operator.GetVersion:output_type -> server.Version
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_pkg_api_server_operator_proto_init() }
|
||||
func file_pkg_api_server_operator_proto_init() {
|
||||
if File_pkg_api_server_operator_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_pkg_api_server_operator_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Empty); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_pkg_api_server_operator_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Version); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_pkg_api_server_operator_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_pkg_api_server_operator_proto_goTypes,
|
||||
DependencyIndexes: file_pkg_api_server_operator_proto_depIdxs,
|
||||
MessageInfos: file_pkg_api_server_operator_proto_msgTypes,
|
||||
}.Build()
|
||||
File_pkg_api_server_operator_proto = out.File
|
||||
file_pkg_api_server_operator_proto_rawDesc = nil
|
||||
file_pkg_api_server_operator_proto_goTypes = nil
|
||||
file_pkg_api_server_operator_proto_depIdxs = nil
|
||||
}
|
39
pkg/api/server/operator.proto
Normal file
39
pkg/api/server/operator.proto
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option go_package = "github.com/arangodb/kube-arangodb/pkg/api/server";
|
||||
|
||||
package server;
|
||||
|
||||
service Operator {
|
||||
rpc GetVersion (Empty) returns (Version) {}
|
||||
}
|
||||
|
||||
message Empty {}
|
||||
|
||||
message Version {
|
||||
string version = 1;
|
||||
string build = 2;
|
||||
string edition = 3;
|
||||
string go_version = 4;
|
||||
string build_date = 5;
|
||||
}
|
105
pkg/api/server/operator_grpc.pb.go
Normal file
105
pkg/api/server/operator_grpc.pb.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc v3.21.1
|
||||
// source: pkg/api/server/operator.proto
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
// OperatorClient is the client API for Operator service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type OperatorClient interface {
|
||||
GetVersion(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Version, error)
|
||||
}
|
||||
|
||||
type operatorClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewOperatorClient(cc grpc.ClientConnInterface) OperatorClient {
|
||||
return &operatorClient{cc}
|
||||
}
|
||||
|
||||
func (c *operatorClient) GetVersion(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Version, error) {
|
||||
out := new(Version)
|
||||
err := c.cc.Invoke(ctx, "/server.Operator/GetVersion", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// OperatorServer is the server API for Operator service.
|
||||
// All implementations must embed UnimplementedOperatorServer
|
||||
// for forward compatibility
|
||||
type OperatorServer interface {
|
||||
GetVersion(context.Context, *Empty) (*Version, error)
|
||||
mustEmbedUnimplementedOperatorServer()
|
||||
}
|
||||
|
||||
// UnimplementedOperatorServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedOperatorServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedOperatorServer) GetVersion(context.Context, *Empty) (*Version, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetVersion not implemented")
|
||||
}
|
||||
func (UnimplementedOperatorServer) mustEmbedUnimplementedOperatorServer() {}
|
||||
|
||||
// UnsafeOperatorServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to OperatorServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeOperatorServer interface {
|
||||
mustEmbedUnimplementedOperatorServer()
|
||||
}
|
||||
|
||||
func RegisterOperatorServer(s grpc.ServiceRegistrar, srv OperatorServer) {
|
||||
s.RegisterService(&Operator_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Operator_GetVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Empty)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(OperatorServer).GetVersion(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/server.Operator/GetVersion",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(OperatorServer).GetVersion(ctx, req.(*Empty))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Operator_ServiceDesc is the grpc.ServiceDesc for Operator service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Operator_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "server.Operator",
|
||||
HandlerType: (*OperatorServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GetVersion",
|
||||
Handler: _Operator_GetVersion_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "pkg/api/server/operator.proto",
|
||||
}
|
91
pkg/api/tls.go
Normal file
91
pkg/api/tls.go
Normal file
|
@ -0,0 +1,91 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"time"
|
||||
|
||||
core "k8s.io/api/core/v1"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
typedCore "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
|
||||
"github.com/arangodb-helper/go-certificates"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
)
|
||||
|
||||
func prepareTLSConfig(cli typedCore.CoreV1Interface, cfg ServerConfig) (*tls.Config, error) {
|
||||
cert, key, err := loadOrSelfSignCertificate(cli, cfg)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
tlsConfig, err := createTLSConfig(cert, key)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
tlsConfig.BuildNameToCertificate()
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
// loadOrSelfSignCertificate loads TLS certificate from secret or creates a new one
|
||||
func loadOrSelfSignCertificate(cli typedCore.CoreV1Interface, cfg ServerConfig) (string, string, error) {
|
||||
if cfg.TLSSecretName != "" {
|
||||
// Load TLS certificate from secret
|
||||
s, err := cli.Secrets(cfg.Namespace).Get(context.Background(), cfg.TLSSecretName, meta.GetOptions{})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
certBytes, found := s.Data[core.TLSCertKey]
|
||||
if !found {
|
||||
return "", "", errors.Newf("No %s found in secret %s", core.TLSCertKey, cfg.TLSSecretName)
|
||||
}
|
||||
keyBytes, found := s.Data[core.TLSPrivateKeyKey]
|
||||
if !found {
|
||||
return "", "", errors.Newf("No %s found in secret %s", core.TLSPrivateKeyKey, cfg.TLSSecretName)
|
||||
}
|
||||
return string(certBytes), string(keyBytes), nil
|
||||
}
|
||||
// Secret not specified, create our own TLS certificate
|
||||
options := certificates.CreateCertificateOptions{
|
||||
CommonName: cfg.ServerName,
|
||||
Hosts: append([]string{cfg.ServerName}, cfg.ServerAltNames...),
|
||||
ValidFrom: time.Now(),
|
||||
ValidFor: time.Hour * 24 * 365 * 10,
|
||||
IsCA: false,
|
||||
ECDSACurve: "P256",
|
||||
}
|
||||
return certificates.CreateCertificate(options, nil)
|
||||
}
|
||||
|
||||
// createTLSConfig creates a TLS config based on given config
|
||||
func createTLSConfig(cert, key string) (*tls.Config, error) {
|
||||
var result *tls.Config
|
||||
c, err := tls.X509KeyPair([]byte(cert), []byte(key))
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
result = &tls.Config{
|
||||
Certificates: []tls.Certificate{c},
|
||||
}
|
||||
return result, nil
|
||||
}
|
2
pkg/generated/timezones/timezones.go
generated
2
pkg/generated/timezones/timezones.go
generated
|
@ -34,7 +34,7 @@ type Timezone struct {
|
|||
}
|
||||
|
||||
func (t Timezone) GetData() ([]byte, bool) {
|
||||
if d, ok := timezonesData[t.Parent]; ok {
|
||||
if d, ok := timezonesData[t.Name]; ok {
|
||||
if d, err := base64.StdEncoding.DecodeString(d); err == nil {
|
||||
return d, true
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue