1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

[Feature] ConfigV1 Integration Service (#1704)

This commit is contained in:
Adam Janikowski 2024-08-26 14:57:50 +02:00 committed by GitHub
parent e97e425485
commit 25d636e2b5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 2389 additions and 61 deletions

View file

@ -99,6 +99,10 @@ linters-settings:
alias: pbAuthorizationV0
- pkg: github.com/arangodb/kube-arangodb/integrations/authorization/v0
alias: pbImplAuthorizationV0
- pkg: github.com/arangodb/kube-arangodb/integrations/config/v1/definition
alias: pbConfigV1
- pkg: github.com/arangodb/kube-arangodb/integrations/config/v1
alias: pbImplConfigV1
- pkg: github.com/arangodb/kube-arangodb/integrations/shared/v1/definition
alias: pbSharedV1
- pkg: github.com/arangodb/kube-arangodb/integrations/shared/v1

View file

@ -13,6 +13,7 @@
- (Maintenance) Switch to ubuntu:24.04 base image
- (Feature) Gateway Group for ArangoDeployment
- (Feature) Gateway config loader
- (Feature) ConfigV1 Integration Service
## [1.2.42](https://github.com/arangodb/kube-arangodb/tree/1.2.42) (2024-07-23)
- (Maintenance) Go 1.22.4 & Kubernetes 1.29.6 libraries

View file

@ -726,19 +726,9 @@ manifest-verify-helm-ee: manifests-verify-env-reset
.PHONY: run-unit-tests
run-unit-tests: $(SOURCES)
go test --count=1 --tags "$(GOBUILDTAGS)" $(TESTVERBOSEOPTIONS) \
$(REPOPATH)/pkg/apis/shared/... \
$(REPOPATH)/pkg/apis/backup/... \
$(REPOPATH)/pkg/apis/deployment/... \
$(REPOPATH)/pkg/apis/replication/... \
$(REPOPATH)/pkg/apis/storage/... \
$(REPOPATH)/pkg/apis/ml/... \
$(REPOPATH)/pkg/deployment/... \
$(REPOPATH)/pkg/storage/... \
$(REPOPATH)/pkg/crd/... \
$(REPOPATH)/pkg/util/... \
$(REPOPATH)/pkg/generated/metric_descriptions/... \
$(REPOPATH)/pkg/... \
$(REPOPATH)/cmd/... \
$(REPOPATH)/pkg/handlers/...
$(REPOPATH)/integrations/...
# Release building

View file

@ -182,7 +182,7 @@ Flags:
--kubernetes.max-batch-size int Size of batch during objects read (default 256)
--kubernetes.qps float32 Number of queries per second for k8s API (default 15)
--log.format string Set log format. Allowed values: 'pretty', 'JSON'. If empty, default format is used (default "pretty")
--log.level stringArray Set log levels in format <level> or <logger>=<level>. Possible loggers: action, agency, api-server, assertion, backup-operator, chaos-monkey, crd, deployment, deployment-ci, deployment-reconcile, deployment-replication, deployment-resilience, deployment-resources, deployment-storage, deployment-storage-pc, deployment-storage-service, http, inspector, integrations, k8s-client, monitor, networking-route-operator, operator, operator-arangojob-handler, operator-v2, operator-v2-event, operator-v2-worker, panics, pod_compare, root, root-event-recorder, server, server-authentication (default [info])
--log.level stringArray Set log levels in format <level> or <logger>=<level>. Possible loggers: action, agency, api-server, assertion, backup-operator, chaos-monkey, crd, deployment, deployment-ci, deployment-reconcile, deployment-replication, deployment-resilience, deployment-resources, deployment-storage, deployment-storage-pc, deployment-storage-service, http, inspector, integration-config-v1, integrations, k8s-client, monitor, networking-route-operator, operator, operator-arangojob-handler, operator-v2, operator-v2-event, operator-v2-worker, panics, pod_compare, root, root-event-recorder, server, server-authentication (default [info])
--log.sampling If true, operator will try to minimize duplication of logging events (default true)
--memory-limit uint Define memory limit for hard shutdown and the dump of goroutines. Used for testing
--metrics.excluded-prefixes stringArray List of the excluded metrics prefixes

View file

@ -40,10 +40,11 @@ func Test_Basic(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
s, err := newInternal(ctx, Configuration{
Path: directory,
TTL: time.Duration(0),
})
s, err := newInternal(ctx, NewConfiguration().With(func(c Configuration) Configuration {
c.Path = directory
c.TTL = 0
return c
}))
require.NoError(t, err)
// Create token

View file

@ -0,0 +1,40 @@
//
// DISCLAIMER
//
// Copyright 2024 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 v1
type Config struct {
Modules ModuleDefinitions `json:"modules,omitempty"`
}
func (c *Config) Init() {
for k := range c.Modules {
m := c.Modules[k]
m.Name = k
c.Modules[k] = m
}
}
type ModuleDefinitions map[string]ModuleDefinition
type ModuleDefinition struct {
Name string `json:"-"`
Path string `json:"path"`
}

View file

@ -0,0 +1,80 @@
//
// DISCLAIMER
//
// Copyright 2024 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 v1
import (
"fmt"
"os"
"testing"
"github.com/stretchr/testify/require"
)
func Test_ConfigCreation(t *testing.T) {
create := func(config Config) error {
_, err := New(config)
return err
}
dir := t.TempDir()
require.NoError(t, os.WriteFile(fmt.Sprintf("%s/file", dir), []byte{}, 0644))
require.EqualError(t, create(Config{}), "Requires at least 1 module")
require.EqualError(t, create(Config{
Modules: map[string]ModuleDefinition{
"test": {},
},
}), "Path for module `test` cannot be empty")
require.EqualError(t, create(Config{
Modules: map[string]ModuleDefinition{
"test": {
Path: "some/relative/path",
},
},
}), "Path `some/relative/path` for module `test` needs to be absolute")
require.EqualError(t, create(Config{
Modules: map[string]ModuleDefinition{
"test": {
Path: fmt.Sprintf("%s/non-existent", dir),
},
},
}), fmt.Sprintf("Path `%s/non-existent` for module `test` does not exists", dir))
require.EqualError(t, create(Config{
Modules: map[string]ModuleDefinition{
"test": {
Path: fmt.Sprintf("%s/file", dir),
},
},
}), fmt.Sprintf("Path `%s/file` for module `test` is not a directory", dir))
require.NoError(t, create(Config{
Modules: map[string]ModuleDefinition{
"test": {
Path: dir,
},
},
}))
}

View file

@ -0,0 +1,25 @@
//
// DISCLAIMER
//
// Copyright 2024 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 v1
const (
Name = "config.v1"
)

View file

@ -0,0 +1,652 @@
//
// DISCLAIMER
//
// Copyright 2024 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: integrations/config/v1/definition/config.proto
package definition
import (
definition "github.com/arangodb/kube-arangodb/integrations/shared/v1/definition"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
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)
)
// ConfigV1 Modules Call Response
type ConfigV1ModulesResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// List of registered modules
Modules []string `protobuf:"bytes,1,rep,name=modules,proto3" json:"modules,omitempty"`
}
func (x *ConfigV1ModulesResponse) Reset() {
*x = ConfigV1ModulesResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_integrations_config_v1_definition_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ConfigV1ModulesResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConfigV1ModulesResponse) ProtoMessage() {}
func (x *ConfigV1ModulesResponse) ProtoReflect() protoreflect.Message {
mi := &file_integrations_config_v1_definition_config_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 ConfigV1ModulesResponse.ProtoReflect.Descriptor instead.
func (*ConfigV1ModulesResponse) Descriptor() ([]byte, []int) {
return file_integrations_config_v1_definition_config_proto_rawDescGZIP(), []int{0}
}
func (x *ConfigV1ModulesResponse) GetModules() []string {
if x != nil {
return x.Modules
}
return nil
}
// ConfigV1 ModuleDetails Call Request
type ConfigV1ModuleDetailsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Name of the module
Module string `protobuf:"bytes,1,opt,name=module,proto3" json:"module,omitempty"`
// Define if checksum of module should be returned
Checksum *bool `protobuf:"varint,2,opt,name=checksum,proto3,oneof" json:"checksum,omitempty"`
}
func (x *ConfigV1ModuleDetailsRequest) Reset() {
*x = ConfigV1ModuleDetailsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_integrations_config_v1_definition_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ConfigV1ModuleDetailsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConfigV1ModuleDetailsRequest) ProtoMessage() {}
func (x *ConfigV1ModuleDetailsRequest) ProtoReflect() protoreflect.Message {
mi := &file_integrations_config_v1_definition_config_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 ConfigV1ModuleDetailsRequest.ProtoReflect.Descriptor instead.
func (*ConfigV1ModuleDetailsRequest) Descriptor() ([]byte, []int) {
return file_integrations_config_v1_definition_config_proto_rawDescGZIP(), []int{1}
}
func (x *ConfigV1ModuleDetailsRequest) GetModule() string {
if x != nil {
return x.Module
}
return ""
}
func (x *ConfigV1ModuleDetailsRequest) GetChecksum() bool {
if x != nil && x.Checksum != nil {
return *x.Checksum
}
return false
}
// ConfigV1 ModuleDetails Call Response
type ConfigV1ModuleDetailsResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Name of the module
Module string `protobuf:"bytes,1,opt,name=module,proto3" json:"module,omitempty"`
// List of the files
Files []*ConfigV1File `protobuf:"bytes,2,rep,name=files,proto3" json:"files,omitempty"`
// Sha256Sum of the module (if requested)
Checksum *string `protobuf:"bytes,3,opt,name=checksum,proto3,oneof" json:"checksum,omitempty"`
}
func (x *ConfigV1ModuleDetailsResponse) Reset() {
*x = ConfigV1ModuleDetailsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_integrations_config_v1_definition_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ConfigV1ModuleDetailsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConfigV1ModuleDetailsResponse) ProtoMessage() {}
func (x *ConfigV1ModuleDetailsResponse) ProtoReflect() protoreflect.Message {
mi := &file_integrations_config_v1_definition_config_proto_msgTypes[2]
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 ConfigV1ModuleDetailsResponse.ProtoReflect.Descriptor instead.
func (*ConfigV1ModuleDetailsResponse) Descriptor() ([]byte, []int) {
return file_integrations_config_v1_definition_config_proto_rawDescGZIP(), []int{2}
}
func (x *ConfigV1ModuleDetailsResponse) GetModule() string {
if x != nil {
return x.Module
}
return ""
}
func (x *ConfigV1ModuleDetailsResponse) GetFiles() []*ConfigV1File {
if x != nil {
return x.Files
}
return nil
}
func (x *ConfigV1ModuleDetailsResponse) GetChecksum() string {
if x != nil && x.Checksum != nil {
return *x.Checksum
}
return ""
}
// ConfigV1 ModuleDetails Call Request
type ConfigV1FileDetailsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Name of the module
Module string `protobuf:"bytes,1,opt,name=module,proto3" json:"module,omitempty"`
// Name of the file
File string `protobuf:"bytes,2,opt,name=file,proto3" json:"file,omitempty"`
// Define if checksum of module should be returned
Checksum *bool `protobuf:"varint,3,opt,name=checksum,proto3,oneof" json:"checksum,omitempty"`
}
func (x *ConfigV1FileDetailsRequest) Reset() {
*x = ConfigV1FileDetailsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_integrations_config_v1_definition_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ConfigV1FileDetailsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConfigV1FileDetailsRequest) ProtoMessage() {}
func (x *ConfigV1FileDetailsRequest) ProtoReflect() protoreflect.Message {
mi := &file_integrations_config_v1_definition_config_proto_msgTypes[3]
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 ConfigV1FileDetailsRequest.ProtoReflect.Descriptor instead.
func (*ConfigV1FileDetailsRequest) Descriptor() ([]byte, []int) {
return file_integrations_config_v1_definition_config_proto_rawDescGZIP(), []int{3}
}
func (x *ConfigV1FileDetailsRequest) GetModule() string {
if x != nil {
return x.Module
}
return ""
}
func (x *ConfigV1FileDetailsRequest) GetFile() string {
if x != nil {
return x.File
}
return ""
}
func (x *ConfigV1FileDetailsRequest) GetChecksum() bool {
if x != nil && x.Checksum != nil {
return *x.Checksum
}
return false
}
// ConfigV1 ModuleDetails Call Response
type ConfigV1FileDetailsResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Name of the module
Module string `protobuf:"bytes,1,opt,name=module,proto3" json:"module,omitempty"`
// Spec of the file
File *ConfigV1File `protobuf:"bytes,3,opt,name=file,proto3" json:"file,omitempty"`
}
func (x *ConfigV1FileDetailsResponse) Reset() {
*x = ConfigV1FileDetailsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_integrations_config_v1_definition_config_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ConfigV1FileDetailsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConfigV1FileDetailsResponse) ProtoMessage() {}
func (x *ConfigV1FileDetailsResponse) ProtoReflect() protoreflect.Message {
mi := &file_integrations_config_v1_definition_config_proto_msgTypes[4]
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 ConfigV1FileDetailsResponse.ProtoReflect.Descriptor instead.
func (*ConfigV1FileDetailsResponse) Descriptor() ([]byte, []int) {
return file_integrations_config_v1_definition_config_proto_rawDescGZIP(), []int{4}
}
func (x *ConfigV1FileDetailsResponse) GetModule() string {
if x != nil {
return x.Module
}
return ""
}
func (x *ConfigV1FileDetailsResponse) GetFile() *ConfigV1File {
if x != nil {
return x.File
}
return nil
}
// Information about configuration file
type ConfigV1File struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Relative path of the config file
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
// Size of the config file in bytes
Size int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"`
// Sha256Sum of the file (if requested)
Checksum *string `protobuf:"bytes,3,opt,name=checksum,proto3,oneof" json:"checksum,omitempty"`
// Timestamp of the file creation
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
// Timestamp of the file update
UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
}
func (x *ConfigV1File) Reset() {
*x = ConfigV1File{}
if protoimpl.UnsafeEnabled {
mi := &file_integrations_config_v1_definition_config_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ConfigV1File) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConfigV1File) ProtoMessage() {}
func (x *ConfigV1File) ProtoReflect() protoreflect.Message {
mi := &file_integrations_config_v1_definition_config_proto_msgTypes[5]
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 ConfigV1File.ProtoReflect.Descriptor instead.
func (*ConfigV1File) Descriptor() ([]byte, []int) {
return file_integrations_config_v1_definition_config_proto_rawDescGZIP(), []int{5}
}
func (x *ConfigV1File) GetPath() string {
if x != nil {
return x.Path
}
return ""
}
func (x *ConfigV1File) GetSize() int64 {
if x != nil {
return x.Size
}
return 0
}
func (x *ConfigV1File) GetChecksum() string {
if x != nil && x.Checksum != nil {
return *x.Checksum
}
return ""
}
func (x *ConfigV1File) GetCreatedAt() *timestamppb.Timestamp {
if x != nil {
return x.CreatedAt
}
return nil
}
func (x *ConfigV1File) GetUpdatedAt() *timestamppb.Timestamp {
if x != nil {
return x.UpdatedAt
}
return nil
}
var File_integrations_config_v1_definition_config_proto protoreflect.FileDescriptor
var file_integrations_config_v1_definition_config_proto_rawDesc = []byte{
0x0a, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74,
0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x12, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x67,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, 0x76,
0x31, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x65, 0x6d, 0x70,
0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x33, 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x56, 0x31, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01,
0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x64, 0x0a,
0x1c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x44,
0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a,
0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d,
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75,
0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b,
0x73, 0x75, 0x6d, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b,
0x73, 0x75, 0x6d, 0x22, 0x91, 0x01, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x31,
0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x2a, 0x0a,
0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, 0x46, 0x69,
0x6c, 0x65, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x08, 0x63, 0x68, 0x65,
0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x63,
0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63,
0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x22, 0x76, 0x0a, 0x1a, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x56, 0x31, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a,
0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c,
0x65, 0x12, 0x1f, 0x0a, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x03, 0x20,
0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x88,
0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x22,
0x5f, 0x0a, 0x1b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, 0x46, 0x69, 0x6c, 0x65, 0x44,
0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16,
0x0a, 0x06, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x28, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x03,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65,
0x22, 0xda, 0x01, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, 0x46, 0x69, 0x6c,
0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x08, 0x63, 0x68, 0x65,
0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x63,
0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72,
0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61,
0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74,
0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x32, 0xfb, 0x01,
0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, 0x12, 0x39, 0x0a, 0x07, 0x4d, 0x6f,
0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x0d, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x45,
0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x0d, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x44,
0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x24, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, 0x4d, 0x6f,
0x64, 0x75, 0x6c, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x0b, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69,
0x6c, 0x73, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x56, 0x31, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x74, 0x61,
0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x45, 0x5a, 0x43, 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, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69,
0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_integrations_config_v1_definition_config_proto_rawDescOnce sync.Once
file_integrations_config_v1_definition_config_proto_rawDescData = file_integrations_config_v1_definition_config_proto_rawDesc
)
func file_integrations_config_v1_definition_config_proto_rawDescGZIP() []byte {
file_integrations_config_v1_definition_config_proto_rawDescOnce.Do(func() {
file_integrations_config_v1_definition_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_integrations_config_v1_definition_config_proto_rawDescData)
})
return file_integrations_config_v1_definition_config_proto_rawDescData
}
var file_integrations_config_v1_definition_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_integrations_config_v1_definition_config_proto_goTypes = []interface{}{
(*ConfigV1ModulesResponse)(nil), // 0: config.ConfigV1ModulesResponse
(*ConfigV1ModuleDetailsRequest)(nil), // 1: config.ConfigV1ModuleDetailsRequest
(*ConfigV1ModuleDetailsResponse)(nil), // 2: config.ConfigV1ModuleDetailsResponse
(*ConfigV1FileDetailsRequest)(nil), // 3: config.ConfigV1FileDetailsRequest
(*ConfigV1FileDetailsResponse)(nil), // 4: config.ConfigV1FileDetailsResponse
(*ConfigV1File)(nil), // 5: config.ConfigV1File
(*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp
(*definition.Empty)(nil), // 7: shared.Empty
}
var file_integrations_config_v1_definition_config_proto_depIdxs = []int32{
5, // 0: config.ConfigV1ModuleDetailsResponse.files:type_name -> config.ConfigV1File
5, // 1: config.ConfigV1FileDetailsResponse.file:type_name -> config.ConfigV1File
6, // 2: config.ConfigV1File.created_at:type_name -> google.protobuf.Timestamp
6, // 3: config.ConfigV1File.updated_at:type_name -> google.protobuf.Timestamp
7, // 4: config.ConfigV1.Modules:input_type -> shared.Empty
1, // 5: config.ConfigV1.ModuleDetails:input_type -> config.ConfigV1ModuleDetailsRequest
3, // 6: config.ConfigV1.FileDetails:input_type -> config.ConfigV1FileDetailsRequest
0, // 7: config.ConfigV1.Modules:output_type -> config.ConfigV1ModulesResponse
2, // 8: config.ConfigV1.ModuleDetails:output_type -> config.ConfigV1ModuleDetailsResponse
4, // 9: config.ConfigV1.FileDetails:output_type -> config.ConfigV1FileDetailsResponse
7, // [7:10] is the sub-list for method output_type
4, // [4:7] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_integrations_config_v1_definition_config_proto_init() }
func file_integrations_config_v1_definition_config_proto_init() {
if File_integrations_config_v1_definition_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_integrations_config_v1_definition_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ConfigV1ModulesResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_integrations_config_v1_definition_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ConfigV1ModuleDetailsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_integrations_config_v1_definition_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ConfigV1ModuleDetailsResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_integrations_config_v1_definition_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ConfigV1FileDetailsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_integrations_config_v1_definition_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ConfigV1FileDetailsResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_integrations_config_v1_definition_config_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ConfigV1File); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_integrations_config_v1_definition_config_proto_msgTypes[1].OneofWrappers = []interface{}{}
file_integrations_config_v1_definition_config_proto_msgTypes[2].OneofWrappers = []interface{}{}
file_integrations_config_v1_definition_config_proto_msgTypes[3].OneofWrappers = []interface{}{}
file_integrations_config_v1_definition_config_proto_msgTypes[5].OneofWrappers = []interface{}{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_integrations_config_v1_definition_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_integrations_config_v1_definition_config_proto_goTypes,
DependencyIndexes: file_integrations_config_v1_definition_config_proto_depIdxs,
MessageInfos: file_integrations_config_v1_definition_config_proto_msgTypes,
}.Build()
File_integrations_config_v1_definition_config_proto = out.File
file_integrations_config_v1_definition_config_proto_rawDesc = nil
file_integrations_config_v1_definition_config_proto_goTypes = nil
file_integrations_config_v1_definition_config_proto_depIdxs = nil
}

View file

@ -0,0 +1,106 @@
//
// DISCLAIMER
//
// Copyright 2024 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";
package config;
import "google/protobuf/timestamp.proto";
import "integrations/shared/v1/definition/empty.proto";
option go_package = "github.com/arangodb/kube-arangodb/integrations/config/v1/definition";
// ConfigV1 Service implementation
service ConfigV1 {
rpc Modules(shared.Empty) returns (ConfigV1ModulesResponse);
rpc ModuleDetails(ConfigV1ModuleDetailsRequest) returns (ConfigV1ModuleDetailsResponse);
rpc FileDetails(ConfigV1FileDetailsRequest) returns (ConfigV1FileDetailsResponse);
}
// Calls
// ConfigV1 Modules Call Response
message ConfigV1ModulesResponse {
// List of registered modules
repeated string modules = 1;
}
// ConfigV1 ModuleDetails Call Request
message ConfigV1ModuleDetailsRequest {
// Name of the module
string module = 1;
// Define if checksum of module should be returned
optional bool checksum = 2;
}
// ConfigV1 ModuleDetails Call Response
message ConfigV1ModuleDetailsResponse {
// Name of the module
string module = 1;
// List of the files
repeated ConfigV1File files = 2;
// Sha256Sum of the module (if requested)
optional string checksum = 3;
}
// ConfigV1 ModuleDetails Call Request
message ConfigV1FileDetailsRequest {
// Name of the module
string module = 1;
// Name of the file
string file = 2;
// Define if checksum of module should be returned
optional bool checksum = 3;
}
// ConfigV1 ModuleDetails Call Response
message ConfigV1FileDetailsResponse {
// Name of the module
string module = 1;
// Spec of the file
ConfigV1File file = 3;
}
// Types
// Information about configuration file
message ConfigV1File {
// Relative path of the config file
string path = 1;
// Size of the config file in bytes
int64 size = 2;
// Sha256Sum of the file (if requested)
optional string checksum = 3;
// Timestamp of the file creation
google.protobuf.Timestamp created_at = 4;
// Timestamp of the file update
google.protobuf.Timestamp updated_at = 5;
}

View file

@ -0,0 +1,178 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.21.1
// source: integrations/config/v1/definition/config.proto
package definition
import (
context "context"
definition "github.com/arangodb/kube-arangodb/integrations/shared/v1/definition"
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
// ConfigV1Client is the client API for ConfigV1 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 ConfigV1Client interface {
Modules(ctx context.Context, in *definition.Empty, opts ...grpc.CallOption) (*ConfigV1ModulesResponse, error)
ModuleDetails(ctx context.Context, in *ConfigV1ModuleDetailsRequest, opts ...grpc.CallOption) (*ConfigV1ModuleDetailsResponse, error)
FileDetails(ctx context.Context, in *ConfigV1FileDetailsRequest, opts ...grpc.CallOption) (*ConfigV1FileDetailsResponse, error)
}
type configV1Client struct {
cc grpc.ClientConnInterface
}
func NewConfigV1Client(cc grpc.ClientConnInterface) ConfigV1Client {
return &configV1Client{cc}
}
func (c *configV1Client) Modules(ctx context.Context, in *definition.Empty, opts ...grpc.CallOption) (*ConfigV1ModulesResponse, error) {
out := new(ConfigV1ModulesResponse)
err := c.cc.Invoke(ctx, "/config.ConfigV1/Modules", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *configV1Client) ModuleDetails(ctx context.Context, in *ConfigV1ModuleDetailsRequest, opts ...grpc.CallOption) (*ConfigV1ModuleDetailsResponse, error) {
out := new(ConfigV1ModuleDetailsResponse)
err := c.cc.Invoke(ctx, "/config.ConfigV1/ModuleDetails", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *configV1Client) FileDetails(ctx context.Context, in *ConfigV1FileDetailsRequest, opts ...grpc.CallOption) (*ConfigV1FileDetailsResponse, error) {
out := new(ConfigV1FileDetailsResponse)
err := c.cc.Invoke(ctx, "/config.ConfigV1/FileDetails", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ConfigV1Server is the server API for ConfigV1 service.
// All implementations must embed UnimplementedConfigV1Server
// for forward compatibility
type ConfigV1Server interface {
Modules(context.Context, *definition.Empty) (*ConfigV1ModulesResponse, error)
ModuleDetails(context.Context, *ConfigV1ModuleDetailsRequest) (*ConfigV1ModuleDetailsResponse, error)
FileDetails(context.Context, *ConfigV1FileDetailsRequest) (*ConfigV1FileDetailsResponse, error)
mustEmbedUnimplementedConfigV1Server()
}
// UnimplementedConfigV1Server must be embedded to have forward compatible implementations.
type UnimplementedConfigV1Server struct {
}
func (UnimplementedConfigV1Server) Modules(context.Context, *definition.Empty) (*ConfigV1ModulesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Modules not implemented")
}
func (UnimplementedConfigV1Server) ModuleDetails(context.Context, *ConfigV1ModuleDetailsRequest) (*ConfigV1ModuleDetailsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ModuleDetails not implemented")
}
func (UnimplementedConfigV1Server) FileDetails(context.Context, *ConfigV1FileDetailsRequest) (*ConfigV1FileDetailsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method FileDetails not implemented")
}
func (UnimplementedConfigV1Server) mustEmbedUnimplementedConfigV1Server() {}
// UnsafeConfigV1Server may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ConfigV1Server will
// result in compilation errors.
type UnsafeConfigV1Server interface {
mustEmbedUnimplementedConfigV1Server()
}
func RegisterConfigV1Server(s grpc.ServiceRegistrar, srv ConfigV1Server) {
s.RegisterService(&ConfigV1_ServiceDesc, srv)
}
func _ConfigV1_Modules_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(definition.Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ConfigV1Server).Modules(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/config.ConfigV1/Modules",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ConfigV1Server).Modules(ctx, req.(*definition.Empty))
}
return interceptor(ctx, in, info, handler)
}
func _ConfigV1_ModuleDetails_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ConfigV1ModuleDetailsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ConfigV1Server).ModuleDetails(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/config.ConfigV1/ModuleDetails",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ConfigV1Server).ModuleDetails(ctx, req.(*ConfigV1ModuleDetailsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ConfigV1_FileDetails_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ConfigV1FileDetailsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ConfigV1Server).FileDetails(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/config.ConfigV1/FileDetails",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ConfigV1Server).FileDetails(ctx, req.(*ConfigV1FileDetailsRequest))
}
return interceptor(ctx, in, info, handler)
}
// ConfigV1_ServiceDesc is the grpc.ServiceDesc for ConfigV1 service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ConfigV1_ServiceDesc = grpc.ServiceDesc{
ServiceName: "config.ConfigV1",
HandlerType: (*ConfigV1Server)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Modules",
Handler: _ConfigV1_Modules_Handler,
},
{
MethodName: "ModuleDetails",
Handler: _ConfigV1_ModuleDetails_Handler,
},
{
MethodName: "FileDetails",
Handler: _ConfigV1_FileDetails_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "integrations/config/v1/definition/config.proto",
}

View file

@ -0,0 +1,179 @@
//
// DISCLAIMER
//
// Copyright 2024 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 v1
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
pbConfigV1 "github.com/arangodb/kube-arangodb/integrations/config/v1/definition"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/tests"
"github.com/arangodb/kube-arangodb/pkg/util/tests/tgrpc"
)
func Test_Files_Details_Missing(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
},
})
require.NotNil(t, client)
_, err := client.FileDetails(ctx, &pbConfigV1.ConfigV1FileDetailsRequest{
Module: "test",
File: "non-existent",
})
tgrpc.AsGRPCError(t, err).Code(t, codes.NotFound).Errorf(t, "File `non-existent` not found within module `test`")
}
func Test_Files_Details_Empty(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
tests.NewFileGenerator(t, dir).FileR(t, "file", 0)
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
},
})
require.NotNil(t, client)
resp, err := client.FileDetails(ctx, &pbConfigV1.ConfigV1FileDetailsRequest{
Module: "test",
File: "file",
})
require.NoError(t, err)
require.Equal(t, "test", resp.GetModule())
require.NotNil(t, resp.GetFile())
require.Equal(t, "file", resp.GetFile().GetPath())
require.EqualValues(t, 0, resp.GetFile().GetSize())
require.Empty(t, resp.GetFile().GetChecksum())
}
func Test_Files_Details_Empty_WC(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
tests.NewFileGenerator(t, dir).FileR(t, "file", 0)
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
},
})
require.NotNil(t, client)
resp, err := client.FileDetails(ctx, &pbConfigV1.ConfigV1FileDetailsRequest{
Module: "test",
File: "file",
Checksum: util.NewType(true),
})
require.NoError(t, err)
require.Equal(t, "test", resp.GetModule())
require.NotNil(t, resp.GetFile())
require.Equal(t, "file", resp.GetFile().GetPath())
require.EqualValues(t, 0, resp.GetFile().GetSize())
require.Equal(t, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", resp.GetFile().GetChecksum())
}
func Test_Files_Details_Data(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
tests.NewFileGenerator(t, dir).File(t, "file", []byte("DATA"))
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
},
})
require.NotNil(t, client)
resp, err := client.FileDetails(ctx, &pbConfigV1.ConfigV1FileDetailsRequest{
Module: "test",
File: "file",
})
require.NoError(t, err)
require.Equal(t, "test", resp.GetModule())
require.NotNil(t, resp.GetFile())
require.Equal(t, "file", resp.GetFile().GetPath())
require.EqualValues(t, 4, resp.GetFile().GetSize())
require.Empty(t, resp.GetFile().GetChecksum())
}
func Test_Files_Details_Data_WC(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
tests.NewFileGenerator(t, dir).File(t, "file", []byte("DATA"))
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
},
})
require.NotNil(t, client)
resp, err := client.FileDetails(ctx, &pbConfigV1.ConfigV1FileDetailsRequest{
Module: "test",
File: "file",
Checksum: util.NewType(true),
})
require.NoError(t, err)
require.Equal(t, "test", resp.GetModule())
require.NotNil(t, resp.GetFile())
require.Equal(t, "file", resp.GetFile().GetPath())
require.EqualValues(t, 4, resp.GetFile().GetSize())
require.Equal(t, "c97c29c7a71b392b437ee03fd17f09bb10b75e879466fc0eb757b2c4a78ac938", resp.GetFile().GetChecksum())
}

View file

@ -0,0 +1,197 @@
//
// DISCLAIMER
//
// Copyright 2024 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 v1
import (
"context"
"fmt"
"io/fs"
"os"
"path"
"path/filepath"
"sort"
"strings"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
pbConfigV1 "github.com/arangodb/kube-arangodb/integrations/config/v1/definition"
pbSharedV1 "github.com/arangodb/kube-arangodb/integrations/shared/v1/definition"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/svc"
)
func New(config Config) (svc.Handler, error) {
config.Init()
if len(config.Modules) == 0 {
return nil, errors.Errorf("Requires at least 1 module")
}
for module, moduleConfig := range config.Modules {
if moduleConfig.Path == "" {
return nil, errors.Errorf("Path for module `%s` cannot be empty", module)
}
if !path.IsAbs(moduleConfig.Path) {
return nil, errors.Errorf("Path `%s` for module `%s` needs to be absolute", moduleConfig.Path, module)
}
info, err := os.Stat(moduleConfig.Path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil, errors.Errorf("Path `%s` for module `%s` does not exists", moduleConfig.Path, module)
}
return nil, errors.Wrapf(err, "Path `%s` for module `%s` received unknown error", moduleConfig.Path, module)
}
if !info.IsDir() {
return nil, errors.Errorf("Path `%s` for module `%s` is not a directory", moduleConfig.Path, module)
}
}
return &impl{
config: config,
}, nil
}
var _ pbConfigV1.ConfigV1Server = &impl{}
var _ svc.Handler = &impl{}
type impl struct {
pbConfigV1.UnsafeConfigV1Server
config Config
}
func (i *impl) Name() string {
return Name
}
func (i *impl) Health() svc.HealthState {
return svc.Healthy
}
func (i *impl) Register(registrar *grpc.Server) {
pbConfigV1.RegisterConfigV1Server(registrar, i)
}
func (i *impl) Modules(ctx context.Context, empty *pbSharedV1.Empty) (*pbConfigV1.ConfigV1ModulesResponse, error) {
res := &pbConfigV1.ConfigV1ModulesResponse{}
res.Modules = util.SortKeys(i.config.Modules)
return res, nil
}
func (i *impl) ModuleDetails(ctx context.Context, request *pbConfigV1.ConfigV1ModuleDetailsRequest) (*pbConfigV1.ConfigV1ModuleDetailsResponse, error) {
if request.GetModule() == "" {
return nil, status.Errorf(codes.InvalidArgument, "Module name cannot be empty")
}
module, ok := i.config.Modules[request.GetModule()]
if !ok {
return nil, status.Errorf(codes.NotFound, "Module `%s` not found", request.GetModule())
}
var resp pbConfigV1.ConfigV1ModuleDetailsResponse
resp.Module = request.GetModule()
var files []*pbConfigV1.ConfigV1File
if err := filepath.Walk(module.Path, func(p string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
if !info.Mode().IsRegular() {
return nil
}
if !strings.HasPrefix(p, fmt.Sprintf("%s/", module.Path)) {
return nil
}
f, err := i.fileDetails(module, strings.TrimPrefix(p, fmt.Sprintf("%s/", module.Path)), request.GetChecksum())
if err != nil {
return err
}
files = append(files, f)
return nil
}); err != nil {
if gErr, ok := svc.AsGRPCErrorStatus(err); ok {
return nil, gErr
}
return nil, status.Errorf(codes.Internal, "Unable to list directory for module `%s`", request.GetModule())
}
sort.Slice(files, func(i, j int) bool {
return files[i].GetPath() < files[j].GetPath()
})
resp.Files = files
if request.GetChecksum() {
checksums := make([]string, len(files))
for id := range files {
checksums[id] = fmt.Sprintf("%s:%s", files[id].GetPath(), files[id].GetChecksum())
}
resp.Checksum = util.NewType(util.SHA256FromStringArray(checksums...))
}
return &resp, nil
}
func (i *impl) FileDetails(ctx context.Context, request *pbConfigV1.ConfigV1FileDetailsRequest) (*pbConfigV1.ConfigV1FileDetailsResponse, error) {
if request.GetModule() == "" {
return nil, status.Errorf(codes.InvalidArgument, "Module name cannot be empty")
}
module, ok := i.config.Modules[request.GetModule()]
if !ok {
return nil, status.Errorf(codes.NotFound, "Module `%s` not found", request.GetModule())
}
if request.GetFile() == "" {
return nil, status.Errorf(codes.InvalidArgument, "File name cannot be empty")
}
if request.GetFile() == "" {
return nil, status.Errorf(codes.NotFound, "File name cannot be empty")
}
f, err := i.fileDetails(module, request.GetFile(), request.GetChecksum())
if err != nil {
return nil, err
}
return &pbConfigV1.ConfigV1FileDetailsResponse{
Module: request.GetModule(),
File: f,
}, nil
}

View file

@ -0,0 +1,80 @@
//
// DISCLAIMER
//
// Copyright 2024 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 v1
import (
"fmt"
"os"
"path"
"strings"
"syscall"
"time"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
pbConfigV1 "github.com/arangodb/kube-arangodb/integrations/config/v1/definition"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
)
func (i *impl) fileDetails(module ModuleDefinition, file string, checksum bool) (*pbConfigV1.ConfigV1File, error) {
expectedPath := path.Clean(path.Join(module.Path, file))
if !strings.HasPrefix(expectedPath, fmt.Sprintf("%s/", module.Path)) {
return nil, status.Errorf(codes.InvalidArgument, "File name cannot be empty")
}
stat, err := os.Stat(expectedPath)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil, status.Errorf(codes.NotFound, "File `%s` not found within module `%s`", file, module.Name)
}
logger.Err(err).Str("module", module.Name).Str("file", file).Str("real-path", expectedPath).Warn("Unable to get file")
return nil, status.Errorf(codes.Internal, "Unable to list directory for module `%s`", module.Name)
}
finfo, ok := stat.Sys().(*syscall.Stat_t)
if !ok {
logger.Str("module", module.Name).Str("file", file).Str("real-path", expectedPath).Warn("Invalid Stat Pointer for file")
return nil, status.Errorf(codes.Internal, "Fetch of file `%s` within module `%s` failed", file, module.Name)
}
var f pbConfigV1.ConfigV1File
f.Path = strings.TrimPrefix(expectedPath, fmt.Sprintf("%s/", module.Path))
f.Size = finfo.Size
f.CreatedAt = timestamppb.New(time.Unix(finfo.Ctimespec.Sec, finfo.Ctimespec.Nsec))
f.UpdatedAt = timestamppb.New(time.Unix(finfo.Mtimespec.Sec, finfo.Mtimespec.Nsec))
if checksum {
c, err := util.SHA256FromFile(expectedPath)
if err != nil {
logger.Str("module", module.Name).Str("file", file).Str("real-path", expectedPath).Warn("Unable to get file checksum")
return nil, status.Errorf(codes.Internal, "Unable to calculate checksum of file `%s` within module `%s` failed", file, module.Name)
}
f.Checksum = util.NewType(c)
}
return &f, nil
}

View file

@ -0,0 +1,80 @@
//
// DISCLAIMER
//
// Copyright 2024 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 v1
import (
"fmt"
"os"
"path"
"strings"
"syscall"
"time"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
pbConfigV1 "github.com/arangodb/kube-arangodb/integrations/config/v1/definition"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
)
func (i *impl) fileDetails(module ModuleDefinition, file string, checksum bool) (*pbConfigV1.ConfigV1File, error) {
expectedPath := path.Clean(path.Join(module.Path, file))
if !strings.HasPrefix(expectedPath, fmt.Sprintf("%s/", module.Path)) {
return nil, status.Errorf(codes.InvalidArgument, "File name cannot be empty")
}
stat, err := os.Stat(expectedPath)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil, status.Errorf(codes.NotFound, "File `%s` not found within module `%s`", file, module.Name)
}
logger.Err(err).Str("module", module.Name).Str("file", file).Str("real-path", expectedPath).Warn("Unable to get file")
return nil, status.Errorf(codes.Internal, "Unable to list directory for module `%s`", module.Name)
}
finfo, ok := stat.Sys().(*syscall.Stat_t)
if !ok {
logger.Str("module", module.Name).Str("file", file).Str("real-path", expectedPath).Warn("Invalid Stat Pointer for file")
return nil, status.Errorf(codes.Internal, "Fetch of file `%s` within module `%s` failed", file, module.Name)
}
var f pbConfigV1.ConfigV1File
f.Path = strings.TrimPrefix(expectedPath, fmt.Sprintf("%s/", module.Path))
f.Size = finfo.Size
f.CreatedAt = timestamppb.New(time.Unix(finfo.Ctim.Sec, finfo.Ctim.Nsec))
f.UpdatedAt = timestamppb.New(time.Unix(finfo.Mtim.Sec, finfo.Mtim.Nsec))
if checksum {
c, err := util.SHA256FromFile(expectedPath)
if err != nil {
logger.Str("module", module.Name).Str("file", file).Str("real-path", expectedPath).Warn("Unable to get file checksum")
return nil, status.Errorf(codes.Internal, "Unable to calculate checksum of file `%s` within module `%s` failed", file, module.Name)
}
f.Checksum = util.NewType(c)
}
return &f, nil
}

View file

@ -0,0 +1,25 @@
//
// DISCLAIMER
//
// Copyright 2024 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 v1
import "github.com/arangodb/kube-arangodb/pkg/logging"
var logger = logging.Global().RegisterAndGetLogger("integration-config-v1", logging.Info)

View file

@ -0,0 +1,192 @@
//
// DISCLAIMER
//
// Copyright 2024 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 v1
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
pbConfigV1 "github.com/arangodb/kube-arangodb/integrations/config/v1/definition"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/tests"
"github.com/arangodb/kube-arangodb/pkg/util/tests/tgrpc"
)
func Test_Modules_Details_Empty(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
},
})
require.NotNil(t, client)
_, err := client.ModuleDetails(ctx, &pbConfigV1.ConfigV1ModuleDetailsRequest{})
tgrpc.AsGRPCError(t, err).Code(t, codes.InvalidArgument).Errorf(t, "Module name cannot be empty")
}
func Test_Modules_Details_NotFound(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
},
})
require.NotNil(t, client)
_, err := client.ModuleDetails(ctx, &pbConfigV1.ConfigV1ModuleDetailsRequest{
Module: "some",
})
tgrpc.AsGRPCError(t, err).Code(t, codes.NotFound).Errorf(t, "Module `some` not found")
}
func Test_Modules_Details_Exists_EmptyFiles(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
},
})
require.NotNil(t, client)
module, err := client.ModuleDetails(ctx, &pbConfigV1.ConfigV1ModuleDetailsRequest{
Module: "test",
})
require.NoError(t, err)
require.Equal(t, "test", module.GetModule())
require.Len(t, module.GetFiles(), 0)
require.Equal(t, "", module.GetChecksum())
}
func Test_Modules_Details_Exists_EmptyFiles_WithChecksum(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
},
})
require.NotNil(t, client)
module, err := client.ModuleDetails(ctx, &pbConfigV1.ConfigV1ModuleDetailsRequest{
Module: "test",
Checksum: util.NewType(true),
})
require.NoError(t, err)
require.Equal(t, "test", module.GetModule())
require.Len(t, module.GetFiles(), 0)
require.Equal(t, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", module.GetChecksum())
}
func Test_Modules_Details_Exists_SomeFiles(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
tests.NewFileGenerator(t, dir).
FileR(t, "test", 128).
Directory(t, "sub").FileR(t, "test", 128)
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
},
})
require.NotNil(t, client)
module, err := client.ModuleDetails(ctx, &pbConfigV1.ConfigV1ModuleDetailsRequest{
Module: "test",
})
require.NoError(t, err)
require.Equal(t, "test", module.GetModule())
require.Len(t, module.GetFiles(), 2)
files := module.GetFiles()
require.Equal(t, "sub/test", files[0].GetPath())
require.Equal(t, "test", files[1].GetPath())
require.Equal(t, "", module.GetChecksum())
}
func Test_Modules_Details_Exists_SomeFiles_WithChecksum(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
tests.NewFileGenerator(t, dir).
File(t, "test", []byte("DATA")).
Directory(t, "sub").File(t, "test", []byte("DATA2"))
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
},
})
require.NotNil(t, client)
module, err := client.ModuleDetails(ctx, &pbConfigV1.ConfigV1ModuleDetailsRequest{
Module: "test",
Checksum: util.NewType(true),
})
require.NoError(t, err)
require.Equal(t, "test", module.GetModule())
require.Len(t, module.GetFiles(), 2)
files := module.GetFiles()
require.Equal(t, "sub/test", files[0].GetPath())
require.Equal(t, "test", files[1].GetPath())
require.Equal(t, "e357414aec56cf8e5e3988b53b766049521a1f4920ad72462d48ebbe16942915", module.GetChecksum())
}

View file

@ -0,0 +1,75 @@
//
// DISCLAIMER
//
// Copyright 2024 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 v1
import (
"context"
"testing"
"github.com/stretchr/testify/require"
pbSharedV1 "github.com/arangodb/kube-arangodb/integrations/shared/v1/definition"
)
func Test_Modules_Single(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
},
})
require.NotNil(t, client)
modules, err := client.Modules(ctx, &pbSharedV1.Empty{})
require.NoError(t, err)
require.Len(t, modules.GetModules(), 1)
}
func Test_Modules_Multi(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
dir := t.TempDir()
client := Client(t, ctx, Config{
Modules: ModuleDefinitions{
"test": {
Path: dir,
},
"test2": {
Path: dir,
},
},
})
require.NotNil(t, client)
modules, err := client.Modules(ctx, &pbSharedV1.Empty{})
require.NoError(t, err)
require.Len(t, modules.GetModules(), 2)
}

View file

@ -0,0 +1,46 @@
//
// DISCLAIMER
//
// Copyright 2024 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 v1
import (
"context"
"testing"
"github.com/stretchr/testify/require"
pbConfigV1 "github.com/arangodb/kube-arangodb/integrations/config/v1/definition"
"github.com/arangodb/kube-arangodb/pkg/util/svc"
"github.com/arangodb/kube-arangodb/pkg/util/tests/tgrpc"
)
func Client(t *testing.T, ctx context.Context, config Config) pbConfigV1.ConfigV1Client {
h, err := New(config)
require.NoError(t, err)
local := svc.NewService(svc.Configuration{
Address: "127.0.0.1:0",
}, h)
start := local.Start(ctx)
client := tgrpc.NewGRPCClient(t, ctx, pbConfigV1.NewConfigV1Client, start.Address())
return client
}

View file

@ -0,0 +1,25 @@
//
// DISCLAIMER
//
// Copyright 2024 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 v1
const (
Name = "scheduler.v1"
)

View file

@ -31,7 +31,7 @@ import (
)
func init() {
register(func() Integration {
registerer.Register(pbAuthenticationV1.Name, func() Integration {
return &authenticationV1{}
})
}

View file

@ -31,7 +31,7 @@ import (
)
func init() {
register(func() Integration {
registerer.Register(pbAuthorizationV0.Name, func() Integration {
return &authorizationV0{}
})
}

View file

@ -0,0 +1,77 @@
//
// DISCLAIMER
//
// Copyright 2024 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 integrations
import (
"context"
"github.com/spf13/cobra"
pbImplConfigV1 "github.com/arangodb/kube-arangodb/integrations/config/v1"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/strings"
"github.com/arangodb/kube-arangodb/pkg/util/svc"
)
func init() {
registerer.Register(pbImplConfigV1.Name, func() Integration {
return &configV1{}
})
}
type configV1 struct {
modules []string
}
func (a *configV1) Register(cmd *cobra.Command, arg ArgGen) error {
f := cmd.Flags()
f.StringSliceVar(&a.modules, arg("module"), nil, "Module in the reference <name>=<abs path>")
return nil
}
func (a *configV1) Handler(ctx context.Context) (svc.Handler, error) {
var cfg pbImplConfigV1.Config
cfg.Modules = map[string]pbImplConfigV1.ModuleDefinition{}
for _, module := range a.modules {
l := strings.SplitN(module, "=", 2)
if len(l) != 2 {
return nil, errors.Errorf("Invalid module definition: %s", module)
}
cfg.Modules[l[0]] = pbImplConfigV1.ModuleDefinition{
Path: l[1],
}
}
return pbImplConfigV1.New(cfg)
}
func (a *configV1) Name() string {
return pbImplConfigV1.Name
}
func (a *configV1) Description() string {
return "Enable ConfigV1 Integration Service"
}

View file

@ -30,7 +30,7 @@ import (
)
func init() {
register(func() Integration {
registerer.Register(pbImplEnvoyAuthV3.Name, func() Integration {
return &envoyAuthV3{}
})
}

View file

@ -23,26 +23,16 @@ package integrations
import (
"fmt"
"sort"
"sync"
"github.com/spf13/cobra"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/shutdown"
"github.com/arangodb/kube-arangodb/pkg/util/svc"
)
var (
lock sync.Mutex
registered []Factory
)
func register(i Factory) {
lock.Lock()
defer lock.Unlock()
registered = append(registered, i)
}
var registerer = util.NewRegisterer[string, Factory]()
func Register(cmd *cobra.Command) error {
var c configuration
@ -65,13 +55,9 @@ type configuration struct {
}
func (c *configuration) Register(cmd *cobra.Command) error {
lock.Lock()
defer lock.Unlock()
c.registered = make([]Integration, len(registered))
for id := range registered {
c.registered[id] = registered[id]()
}
c.registered = util.FormatList(registerer.Items(), func(a util.KV[string, Factory]) Integration {
return a.V()
})
sort.Slice(c.registered, func(i, j int) bool {
return c.registered[i].Name() < c.registered[j].Name()

View file

@ -33,7 +33,7 @@ import (
)
func init() {
register(func() Integration {
registerer.Register(pbImplSchedulerV1.Name, func() Integration {
return &schedulerV1{}
})
}
@ -43,7 +43,7 @@ type schedulerV1 struct {
}
func (b *schedulerV1) Name() string {
return "scheduler.v1"
return pbImplSchedulerV1.Name
}
func (b *schedulerV1) Description() string {

View file

@ -31,7 +31,7 @@ import (
)
func init() {
register(func() Integration {
registerer.Register(pbImplShutdownV1.Name, func() Integration {
return &shutdownV1{}
})
}

View file

@ -30,7 +30,7 @@ import (
)
func init() {
register(func() Integration {
registerer.Register(storage.Name, func() Integration {
return &storageV1{}
})
}
@ -40,7 +40,7 @@ type storageV1 struct {
}
func (b *storageV1) Name() string {
return "storage.v1"
return storage.Name
}
func (b *storageV1) Description() string {

23
pkg/ml/storage/consts.go Normal file
View file

@ -0,0 +1,23 @@
//
// DISCLAIMER
//
// Copyright 2024 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 storage
const Name = "storage.v1"

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2024 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.
@ -79,7 +79,7 @@ func Test_Verify_WrongOrder(t *testing.T) {
)
_, err := u.Execute(api.ArangoDeployment{}, nil, nil)
require.EqualError(t, err, "Invalid version in 1.1.1 - got 3, expected 2")
require.EqualError(t, err, "Invalid version in 1.1.1 - got 3, expected 1")
})
t.Run("Valid multi version", func(t *testing.T) {
var u Upgrades

View file

@ -24,6 +24,8 @@ import (
"crypto/md5"
"crypto/sha256"
"fmt"
"io"
"os"
"k8s.io/apimachinery/pkg/util/json"
@ -56,6 +58,27 @@ func SHA256(data []byte) string {
return fmt.Sprintf("%0x", sha256.Sum256(data))
}
func SHA256FromFile(file string) (string, error) {
in, err := os.OpenFile(file, os.O_RDONLY, 0644)
if err != nil {
return "", err
}
defer in.Close()
return SHA256FromIO(in)
}
func SHA256FromIO(in io.Reader) (string, error) {
c := sha256.New()
if _, err := io.CopyBuffer(c, in, make([]byte, 4096)); err != nil {
return "", err
}
return fmt.Sprintf("%0x", c.Sum(nil)), nil
}
func MD5FromString(data string) string {
return MD5([]byte(data))
}

View file

@ -22,7 +22,6 @@ package util
import (
"maps"
"reflect"
"sort"
)
@ -53,24 +52,34 @@ func Sort[IN any](in []IN, cmp func(i, j IN) bool) []IN {
return r
}
func SortKeys(m interface{}) []string {
if m == nil {
return []string{}
func MapValues[K comparable, V any](m map[K]V) []V {
r := make([]V, 0, len(m))
for k := range m {
r = append(r, m[k])
}
q := reflect.ValueOf(m).MapKeys()
r := make([]string, len(q))
for id, v := range q {
r[id] = v.String()
}
sort.Strings(r)
return r
}
func MapKeys[K comparable, V any](m map[K]V) []K {
r := make([]K, 0, len(m))
for k := range m {
r = append(r, k)
}
return r
}
func SortKeys[V any](m map[string]V) []string {
keys := MapKeys(m)
sort.Strings(keys)
return keys
}
func CopyFullMap[K comparable, V any](src map[K]V) map[K]V {
if src == nil {
return nil

71
pkg/util/registerer.go Normal file
View file

@ -0,0 +1,71 @@
//
// DISCLAIMER
//
// Copyright 2024 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 util
import "sync"
func NewRegisterer[K comparable, V any]() Registerer[K, V] {
return &registerer[K, V]{
items: make(map[K]V),
}
}
type Registerer[K comparable, V any] interface {
Register(key K, value V) bool
MustRegister(key K, value V)
Items() []KV[K, V]
}
type registerer[K comparable, V any] struct {
lock sync.Mutex
items map[K]V
}
func (r *registerer[K, V]) Register(key K, value V) bool {
r.lock.Lock()
defer r.lock.Unlock()
if _, ok := r.items[key]; ok {
return false
}
r.items[key] = value
return true
}
func (r *registerer[K, V]) MustRegister(key K, value V) {
r.lock.Lock()
defer r.lock.Unlock()
if !r.Register(key, value) {
panic("Unable to register item")
}
}
func (r *registerer[K, V]) Items() []KV[K, V] {
r.lock.Lock()
defer r.lock.Unlock()
return Extract(r.items)
}

View file

@ -130,6 +130,23 @@ func Split(s, sep string) []string {
return strings.Split(s, sep)
}
// SplitN slices s into substrings separated by sep and returns a slice of
// the substrings between those separators.
//
// The count determines the number of substrings to return:
//
// n > 0: at most n substrings; the last substring will be the unsplit remainder.
// n == 0: the result is nil (zero substrings)
// n < 0: all substrings
//
// Edge cases for s and sep (for example, empty strings) are handled
// as described in the documentation for [Split].
//
// To split around the first instance of a separator, see Cut.
func SplitN(s, sep string, n int) []string {
return strings.SplitN(s, sep, n)
}
// ToLower returns s with all Unicode letters mapped to their lower case.
func ToLower(s string) string {
return strings.ToLower(s)

View file

@ -20,7 +20,12 @@
package svc
import "context"
import (
"context"
"errors"
"google.golang.org/grpc/status"
)
type serviceError struct {
error
@ -45,3 +50,17 @@ func (p serviceError) Update(key string, state HealthState) {
func (p serviceError) Start(ctx context.Context) ServiceStarter {
return p
}
type GRPCErrorStatus interface {
error
GRPCStatus() *status.Status
}
func AsGRPCErrorStatus(err error) (GRPCErrorStatus, bool) {
var v GRPCErrorStatus
if errors.As(err, &v) {
return v, true
}
return nil, false
}

95
pkg/util/tests/path.go Normal file
View file

@ -0,0 +1,95 @@
//
// DISCLAIMER
//
// Copyright 2024 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 tests
import (
"os"
"path"
"testing"
"github.com/stretchr/testify/require"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
)
type FileGenerator interface {
Parent(t *testing.T) FileGenerator
Directory(t *testing.T, name string) FileGenerator
File(t *testing.T, name string, data []byte) FileGenerator
FileR(t *testing.T, name string, size int) FileGenerator
}
type fileGenerator struct {
root string
path string
}
func (f fileGenerator) FileR(t *testing.T, name string, size int) FileGenerator {
var data = make([]byte, size)
_, err := util.Rand().Read(data)
require.NoError(t, err)
return f.File(t, name, data)
}
func (f fileGenerator) Parent(t *testing.T) FileGenerator {
require.NotEqual(t, f.root, f.path, "Unable to jump above root")
return fileGenerator{
root: f.root,
path: path.Dir(f.path),
}
}
func (f fileGenerator) Directory(t *testing.T, name string) FileGenerator {
np := path.Join(f.path, name)
if err := os.Mkdir(np, 0755); err != nil {
if !errors.Is(err, os.ErrExist) {
require.NoError(t, err)
}
}
return fileGenerator{
root: f.root,
path: np,
}
}
func (f fileGenerator) File(t *testing.T, name string, data []byte) FileGenerator {
require.NoError(t, os.WriteFile(path.Join(f.path, name), data, 0644))
return f
}
func NewFileGenerator(t *testing.T, root string) FileGenerator {
if err := os.Mkdir(root, 0755); err != nil {
if !errors.Is(err, os.ErrExist) {
require.NoError(t, err)
}
}
return fileGenerator{root: root, path: root}
}

View file

@ -22,11 +22,16 @@ package tgrpc
import (
"context"
"fmt"
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/status"
"github.com/arangodb/kube-arangodb/pkg/util/svc"
)
func NewGRPCClient[T any](t *testing.T, ctx context.Context, in func(cc grpc.ClientConnInterface) T, addr string, opts ...grpc.DialOption) T {
@ -51,3 +56,30 @@ func NewGRPCConn(t *testing.T, ctx context.Context, addr string, opts ...grpc.Di
return conn
}
type ErrorStatusValidator interface {
Code(t *testing.T, code codes.Code) ErrorStatusValidator
Errorf(t *testing.T, msg string, args ...interface{}) ErrorStatusValidator
}
type errorStatusValidator struct {
st *status.Status
}
func (e errorStatusValidator) Errorf(t *testing.T, msg string, args ...interface{}) ErrorStatusValidator {
require.Equal(t, e.st.Message(), fmt.Sprintf(msg, args...))
return e
}
func (e errorStatusValidator) Code(t *testing.T, code codes.Code) ErrorStatusValidator {
require.Equal(t, code, e.st.Code())
return e
}
func AsGRPCError(t *testing.T, err error) ErrorStatusValidator {
v, ok := svc.AsGRPCErrorStatus(err)
require.True(t, ok)
st := v.GRPCStatus()
require.NotNil(t, st)
return errorStatusValidator{st: st}
}