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

Merge branch 'master' into master

This commit is contained in:
Adam Janikowski 2024-11-29 15:11:21 +01:00 committed by GitHub
commit 0a9164e863
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
55 changed files with 1553 additions and 137 deletions

View file

@ -24,6 +24,10 @@
- (Feature) (Scheduler) Deployment Scale Functionality
- (Feature) (Platform) Chart Integration
- (Maintenance) Switch to google.golang.org/protobuf
- (Feature) Add DebugPackage to the OPS Binary
- (Feature) (Networking) ArangoRoute Protocol
- (Feature) (Platform) Platform Requirements support
- (Improvement) Drop slash requirement from ArangoRoute
## [1.2.43](https://github.com/arangodb/kube-arangodb/tree/1.2.43) (2024-10-14)
- (Feature) ArangoRoute CRD

View file

@ -34,6 +34,9 @@ func init() {
cmdMain.AddCommand(debugPackage)
cmdMain.AddCommand(debugPackageV2)
cmdOps.AddCommand(debugPackage)
cmdOps.AddCommand(debugPackageV2)
debugPackage.Flags().StringVarP(&debugPackageInput.Output, "output", "o", "out.tar.gz", "Output of the result gz file. If set to `-` then stdout is used")
debugPackageV2.Flags().StringVarP(&debugPackageInput.Output, "output", "o", "out.tar.gz", "Output of the result gz file. If set to `-` then stdout is used")

View file

@ -83,18 +83,34 @@ UID keeps the information about object UID
### .spec.destination.path
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_spec_destination.go#L39)</sup>
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_spec_destination.go#L46)</sup>
Path defines service path used for overrides
***
### .spec.destination.protocol
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_spec_destination.go#L40)</sup>
Protocol defines http protocol used for the route
Possible Values:
* `"http1"` (default) - HTTP 1.1 Protocol
* `"http2"` - HTTP 2 Protocol
***
### .spec.destination.schema
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_spec_destination.go#L33)</sup>
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_spec_destination.go#L35)</sup>
Schema defines HTTP/S schema used for connection
Possible Values:
* `"http"` (default) - HTTP Connection
* `"https"` - HTTPS Connection (HTTP with TLS)
***
### .spec.destination.service.checksum
@ -238,12 +254,20 @@ Type: `integer` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.
### .status.target.path
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_status_target.go#L43)</sup>
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_status_target.go#L46)</sup>
Path specifies request path override
***
### .status.target.protocol
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_status_target.go#L40)</sup>
Protocol defines http protocol used for the route
***
### .status.target.TLS.insecure
Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/networking/v1alpha1/route_status_target_tls.go#L27)</sup>

View file

@ -15,14 +15,14 @@ Usage:
Available Commands:
admin Administration operations
completion Generate the autocompletion script for the specified shell
crd CRD operations
debug-package Generate debug package for debugging
crd CRD operations
debug-package Generate debug package for debugging
exporter
features Describe all operator features
help Help about any command
integration
storage
task
task
version
Flags:

View file

@ -13,10 +13,11 @@ Usage:
arangodb_operator_ops [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
crd CRD operations
help Help about any command
task
completion Generate the autocompletion script for the specified shell
crd CRD operations
debug-package Generate debug package for debugging
help Help about any command
task
Flags:
-h, --help help for arangodb_operator_ops
@ -86,3 +87,33 @@ Global Flags:
--crd.validation-schema stringArray Controls which CRD should have validation schema <crd-name>=<true/false>.
```
[END_INJECT]: # (arangodb_operator_ops_cmd_crd_generate)
# ArangoDB Operator Ops CRD Install Subcommand
[START_INJECT]: # (arangodb_operator_ops_cmd_debug_package)
```
Generate debug package for debugging
Usage:
arangodb_operator_ops debug-package [flags]
Flags:
--generator.agency-dump Define if generator agency-dump is enabled (default true)
--generator.analytics Define if generator analytics is enabled (default true)
--generator.backupBackup Define if generator backupBackup is enabled (default true)
--generator.deployments Define if generator deployments is enabled (default true)
--generator.kubernetes-events Define if generator kubernetes-events is enabled (default true)
--generator.kubernetes-pods Define if generator kubernetes-pods is enabled (default true)
--generator.kubernetes-secrets Define if generator kubernetes-secrets is enabled (default true)
--generator.kubernetes-services Define if generator kubernetes-services is enabled (default true)
--generator.ml Define if generator ml is enabled (default true)
--generator.networking Define if generator networking is enabled (default true)
--generator.platform Define if generator platform is enabled (default true)
--generator.scheduler Define if generator scheduler is enabled (default true)
-h, --help help for debug-package
--hide-sensitive-data Hide sensitive data (default true)
-n, --namespace string Kubernetes namespace (default "default")
-o, --output - Output of the result gz file. If set to - then stdout is used (default "out.tar.gz")
--pod-logs Collect pod logs (default true)
```
[END_INJECT]: # (arangodb_operator_ops_cmd_debug_package)

View file

@ -1,3 +1,11 @@
---
layout: page
has_children: true
title: Integration Sidecars
parent: ArangoDBPlatform
has_toc: false
---
# Integration
## Profile
@ -13,8 +21,86 @@ Integration Sidecar is supported in a few resources managed by Operator:
- ArangoSchedulerCronJob (scheduler.arangodb.com/v1beta1)
- ArangoSchedulerPod (scheduler.arangodb.com/v1beta1)
To enable integration sidecar for specific deployment label needs to be defined:
```yaml
metadata:
labels:
profiles.arangodb.com/deployment: << deployment name >>
```
### Integrations
To enable integration in specific version, labels needs to be added:
```yaml
metadata:
labels:
integration.profiles.arangodb.com/<< integration name >>: << integration version >>
```
#### [Authentication V1](/docs/integration/authentication.v1.md)
Authentication Integration Sidecar
To enable:
```yaml
metadata:
labels:
integration.profiles.arangodb.com/authn: v1
```
#### [Authorization V0](/docs/integration/authorization.v0.md)
Authorization Integration Sidecar
To enable:
```yaml
metadata:
labels:
integration.profiles.arangodb.com/authz: v0
```
#### [Scheduler V2](/docs/integration/scheduler.v2.md)
Scheduler Integration Sidecar
To enable:
```yaml
metadata:
labels:
integration.profiles.arangodb.com/sched: v2
```
#### [Storage V2](/docs/integration/storage.v2.md)
Storage Integration Sidecar
To enable:
```yaml
metadata:
labels:
integration.profiles.arangodb.com/storage: v2
```
### Envs
#### INTEGRATION_API_ADDRESS
Integration Service API Address
Example: `localhost:1234`
#### INTEGRATION_SERVICE_ADDRESS
Integration Service API Address
Example: `localhost:1234`
#### ARANGO_DEPLOYMENT_NAME
ArangoDeployment name.
@ -25,4 +111,4 @@ Example: `deployment`
HTTP/S Endpoint of the ArangoDeployment Internal Service.
Example: `https://deployment.default.svc:8529`
Example: `https://deployment.default.svc:8529`

View file

@ -0,0 +1,11 @@
---
layout: page
title: Authentication V1
parent: ArangoDBPlatform
---
# Authentication V1
Definitions:
- [Service](../../integrations/authentication/v1/definition/definition.proto)

View file

@ -0,0 +1,12 @@
---
layout: page
title: Authentication V1
parent: ArangoDBPlatform
---
# Authorization V0
Definitions:
- [Service](../../integrations/authorization/v0/definition/definition.proto)

View file

@ -0,0 +1,12 @@
---
layout: page
title: Authentication V1
parent: ArangoDBPlatform
---
# Scheduler V2
Definitions:
- [Service](../../integrations/scheduler/v2/definition/definition.proto)

View file

@ -0,0 +1,12 @@
---
layout: page
title: Authentication V1
parent: ArangoDBPlatform
---
# Storage V2
Definitions:
- [Service](./definition.proto)

6
docs/platform.md Normal file
View file

@ -0,0 +1,6 @@
---
layout: page
has_children: true
title: ArangoDBPlatform
has_toc: false
---

2
go.mod
View file

@ -73,6 +73,7 @@ require (
)
require (
github.com/Masterminds/semver/v3 v3.3.0
github.com/aws/aws-sdk-go v1.55.5
helm.sh/helm/v3 v3.16.2
)
@ -85,7 +86,6 @@ require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect

View file

@ -50,6 +50,8 @@ type SchedulerV2ChartInfo struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// Chart Version
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
// Keeps the Platform details from the output
Platform *SchedulerV2ChartPlatform `protobuf:"bytes,3,opt,name=platform,proto3,oneof" json:"platform,omitempty"`
}
func (x *SchedulerV2ChartInfo) Reset() {
@ -98,6 +100,62 @@ func (x *SchedulerV2ChartInfo) GetVersion() string {
return ""
}
func (x *SchedulerV2ChartInfo) GetPlatform() *SchedulerV2ChartPlatform {
if x != nil {
return x.Platform
}
return nil
}
// Chart Platform Details
type SchedulerV2ChartPlatform struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// List of the requirements
Requirements map[string]string `protobuf:"bytes,1,rep,name=requirements,proto3" json:"requirements,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *SchedulerV2ChartPlatform) Reset() {
*x = SchedulerV2ChartPlatform{}
if protoimpl.UnsafeEnabled {
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SchedulerV2ChartPlatform) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SchedulerV2ChartPlatform) ProtoMessage() {}
func (x *SchedulerV2ChartPlatform) ProtoReflect() protoreflect.Message {
mi := &file_integrations_scheduler_v2_definition_chart_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 SchedulerV2ChartPlatform.ProtoReflect.Descriptor instead.
func (*SchedulerV2ChartPlatform) Descriptor() ([]byte, []int) {
return file_integrations_scheduler_v2_definition_chart_proto_rawDescGZIP(), []int{1}
}
func (x *SchedulerV2ChartPlatform) GetRequirements() map[string]string {
if x != nil {
return x.Requirements
}
return nil
}
// SchedulerV2 ListCharts Request
type SchedulerV2ListChartsRequest struct {
state protoimpl.MessageState
@ -111,7 +169,7 @@ type SchedulerV2ListChartsRequest struct {
func (x *SchedulerV2ListChartsRequest) Reset() {
*x = SchedulerV2ListChartsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[1]
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -124,7 +182,7 @@ func (x *SchedulerV2ListChartsRequest) String() string {
func (*SchedulerV2ListChartsRequest) ProtoMessage() {}
func (x *SchedulerV2ListChartsRequest) ProtoReflect() protoreflect.Message {
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[1]
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -137,7 +195,7 @@ func (x *SchedulerV2ListChartsRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use SchedulerV2ListChartsRequest.ProtoReflect.Descriptor instead.
func (*SchedulerV2ListChartsRequest) Descriptor() ([]byte, []int) {
return file_integrations_scheduler_v2_definition_chart_proto_rawDescGZIP(), []int{1}
return file_integrations_scheduler_v2_definition_chart_proto_rawDescGZIP(), []int{2}
}
func (x *SchedulerV2ListChartsRequest) GetItems() int64 {
@ -160,7 +218,7 @@ type SchedulerV2ListChartsResponse struct {
func (x *SchedulerV2ListChartsResponse) Reset() {
*x = SchedulerV2ListChartsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[2]
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -173,7 +231,7 @@ func (x *SchedulerV2ListChartsResponse) String() string {
func (*SchedulerV2ListChartsResponse) ProtoMessage() {}
func (x *SchedulerV2ListChartsResponse) ProtoReflect() protoreflect.Message {
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[2]
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -186,7 +244,7 @@ func (x *SchedulerV2ListChartsResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use SchedulerV2ListChartsResponse.ProtoReflect.Descriptor instead.
func (*SchedulerV2ListChartsResponse) Descriptor() ([]byte, []int) {
return file_integrations_scheduler_v2_definition_chart_proto_rawDescGZIP(), []int{2}
return file_integrations_scheduler_v2_definition_chart_proto_rawDescGZIP(), []int{3}
}
func (x *SchedulerV2ListChartsResponse) GetCharts() []string {
@ -209,7 +267,7 @@ type SchedulerV2GetChartRequest struct {
func (x *SchedulerV2GetChartRequest) Reset() {
*x = SchedulerV2GetChartRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[3]
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -222,7 +280,7 @@ func (x *SchedulerV2GetChartRequest) String() string {
func (*SchedulerV2GetChartRequest) ProtoMessage() {}
func (x *SchedulerV2GetChartRequest) ProtoReflect() protoreflect.Message {
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[3]
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -235,7 +293,7 @@ func (x *SchedulerV2GetChartRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use SchedulerV2GetChartRequest.ProtoReflect.Descriptor instead.
func (*SchedulerV2GetChartRequest) Descriptor() ([]byte, []int) {
return file_integrations_scheduler_v2_definition_chart_proto_rawDescGZIP(), []int{3}
return file_integrations_scheduler_v2_definition_chart_proto_rawDescGZIP(), []int{4}
}
func (x *SchedulerV2GetChartRequest) GetName() string {
@ -260,7 +318,7 @@ type SchedulerV2GetChartResponse struct {
func (x *SchedulerV2GetChartResponse) Reset() {
*x = SchedulerV2GetChartResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[4]
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -273,7 +331,7 @@ func (x *SchedulerV2GetChartResponse) String() string {
func (*SchedulerV2GetChartResponse) ProtoMessage() {}
func (x *SchedulerV2GetChartResponse) ProtoReflect() protoreflect.Message {
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[4]
mi := &file_integrations_scheduler_v2_definition_chart_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -286,7 +344,7 @@ func (x *SchedulerV2GetChartResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use SchedulerV2GetChartResponse.ProtoReflect.Descriptor instead.
func (*SchedulerV2GetChartResponse) Descriptor() ([]byte, []int) {
return file_integrations_scheduler_v2_definition_chart_proto_rawDescGZIP(), []int{4}
return file_integrations_scheduler_v2_definition_chart_proto_rawDescGZIP(), []int{5}
}
func (x *SchedulerV2GetChartResponse) GetChart() []byte {
@ -309,34 +367,51 @@ var file_integrations_scheduler_v2_definition_chart_proto_rawDesc = []byte{
0x0a, 0x30, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x73,
0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x64, 0x65, 0x66, 0x69,
0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x68, 0x61, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x12, 0x09, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x22, 0x44, 0x0a,
0x14, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x56, 0x32, 0x43, 0x68, 0x61, 0x72,
0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x22, 0x43, 0x0a, 0x1c, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72,
0x56, 0x32, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x72, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01,
0x28, 0x03, 0x48, 0x00, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x88, 0x01, 0x01, 0x42, 0x08,
0x0a, 0x06, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x37, 0x0a, 0x1d, 0x53, 0x63, 0x68, 0x65,
0x64, 0x75, 0x6c, 0x65, 0x72, 0x56, 0x32, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x72, 0x74,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x68, 0x61,
0x72, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x63, 0x68, 0x61, 0x72, 0x74,
0x73, 0x22, 0x30, 0x0a, 0x1a, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x56, 0x32,
0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
0x61, 0x6d, 0x65, 0x22, 0x68, 0x0a, 0x1b, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72,
0x56, 0x32, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x05, 0x63, 0x68, 0x61, 0x72, 0x74, 0x12, 0x33, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
0x74, 0x6f, 0x12, 0x09, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x22, 0x97, 0x01,
0x0a, 0x14, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x56, 0x32, 0x43, 0x68, 0x61,
0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
0x65, 0x72, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x56, 0x32, 0x43, 0x68,
0x61, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x42, 0x48, 0x5a,
0x46, 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,
0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x64, 0x65, 0x66,
0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x61, 0x72, 0x74, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x48, 0x00, 0x52, 0x08, 0x70,
0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70,
0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0xb6, 0x01, 0x0a, 0x18, 0x53, 0x63, 0x68, 0x65,
0x64, 0x75, 0x6c, 0x65, 0x72, 0x56, 0x32, 0x43, 0x68, 0x61, 0x72, 0x74, 0x50, 0x6c, 0x61, 0x74,
0x66, 0x6f, 0x72, 0x6d, 0x12, 0x59, 0x0a, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x73, 0x63, 0x68,
0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72,
0x56, 0x32, 0x43, 0x68, 0x61, 0x72, 0x74, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e,
0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x52, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x1a,
0x3f, 0x0a, 0x11, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
0x22, 0x43, 0x0a, 0x1c, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x56, 0x32, 0x4c,
0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x72, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x19, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48,
0x00, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f,
0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x37, 0x0a, 0x1d, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
0x65, 0x72, 0x56, 0x32, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x61, 0x72, 0x74, 0x73, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x72, 0x74, 0x73,
0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x63, 0x68, 0x61, 0x72, 0x74, 0x73, 0x22, 0x30,
0x0a, 0x1a, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x56, 0x32, 0x47, 0x65, 0x74,
0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x22, 0x68, 0x0a, 0x1b, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x56, 0x32, 0x47,
0x65, 0x74, 0x43, 0x68, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05,
0x63, 0x68, 0x61, 0x72, 0x74, 0x12, 0x33, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e,
0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x56, 0x32, 0x43, 0x68, 0x61, 0x72, 0x74,
0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x42, 0x48, 0x5a, 0x46, 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, 0x73, 0x63, 0x68,
0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69,
0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -351,21 +426,25 @@ func file_integrations_scheduler_v2_definition_chart_proto_rawDescGZIP() []byte
return file_integrations_scheduler_v2_definition_chart_proto_rawDescData
}
var file_integrations_scheduler_v2_definition_chart_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_integrations_scheduler_v2_definition_chart_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_integrations_scheduler_v2_definition_chart_proto_goTypes = []interface{}{
(*SchedulerV2ChartInfo)(nil), // 0: scheduler.SchedulerV2ChartInfo
(*SchedulerV2ListChartsRequest)(nil), // 1: scheduler.SchedulerV2ListChartsRequest
(*SchedulerV2ListChartsResponse)(nil), // 2: scheduler.SchedulerV2ListChartsResponse
(*SchedulerV2GetChartRequest)(nil), // 3: scheduler.SchedulerV2GetChartRequest
(*SchedulerV2GetChartResponse)(nil), // 4: scheduler.SchedulerV2GetChartResponse
(*SchedulerV2ChartPlatform)(nil), // 1: scheduler.SchedulerV2ChartPlatform
(*SchedulerV2ListChartsRequest)(nil), // 2: scheduler.SchedulerV2ListChartsRequest
(*SchedulerV2ListChartsResponse)(nil), // 3: scheduler.SchedulerV2ListChartsResponse
(*SchedulerV2GetChartRequest)(nil), // 4: scheduler.SchedulerV2GetChartRequest
(*SchedulerV2GetChartResponse)(nil), // 5: scheduler.SchedulerV2GetChartResponse
nil, // 6: scheduler.SchedulerV2ChartPlatform.RequirementsEntry
}
var file_integrations_scheduler_v2_definition_chart_proto_depIdxs = []int32{
0, // 0: scheduler.SchedulerV2GetChartResponse.info:type_name -> scheduler.SchedulerV2ChartInfo
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
1, // 0: scheduler.SchedulerV2ChartInfo.platform:type_name -> scheduler.SchedulerV2ChartPlatform
6, // 1: scheduler.SchedulerV2ChartPlatform.requirements:type_name -> scheduler.SchedulerV2ChartPlatform.RequirementsEntry
0, // 2: scheduler.SchedulerV2GetChartResponse.info:type_name -> scheduler.SchedulerV2ChartInfo
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_integrations_scheduler_v2_definition_chart_proto_init() }
@ -387,7 +466,7 @@ func file_integrations_scheduler_v2_definition_chart_proto_init() {
}
}
file_integrations_scheduler_v2_definition_chart_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SchedulerV2ListChartsRequest); i {
switch v := v.(*SchedulerV2ChartPlatform); i {
case 0:
return &v.state
case 1:
@ -399,7 +478,7 @@ func file_integrations_scheduler_v2_definition_chart_proto_init() {
}
}
file_integrations_scheduler_v2_definition_chart_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SchedulerV2ListChartsResponse); i {
switch v := v.(*SchedulerV2ListChartsRequest); i {
case 0:
return &v.state
case 1:
@ -411,7 +490,7 @@ func file_integrations_scheduler_v2_definition_chart_proto_init() {
}
}
file_integrations_scheduler_v2_definition_chart_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SchedulerV2GetChartRequest); i {
switch v := v.(*SchedulerV2ListChartsResponse); i {
case 0:
return &v.state
case 1:
@ -423,6 +502,18 @@ func file_integrations_scheduler_v2_definition_chart_proto_init() {
}
}
file_integrations_scheduler_v2_definition_chart_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SchedulerV2GetChartRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_integrations_scheduler_v2_definition_chart_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SchedulerV2GetChartResponse); i {
case 0:
return &v.state
@ -435,14 +526,15 @@ func file_integrations_scheduler_v2_definition_chart_proto_init() {
}
}
}
file_integrations_scheduler_v2_definition_chart_proto_msgTypes[1].OneofWrappers = []interface{}{}
file_integrations_scheduler_v2_definition_chart_proto_msgTypes[0].OneofWrappers = []interface{}{}
file_integrations_scheduler_v2_definition_chart_proto_msgTypes[2].OneofWrappers = []interface{}{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_integrations_scheduler_v2_definition_chart_proto_rawDesc,
NumEnums: 0,
NumMessages: 5,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},

View file

@ -30,6 +30,14 @@ message SchedulerV2ChartInfo {
string name = 1;
// Chart Version
string version = 2;
// Keeps the Platform details from the output
optional SchedulerV2ChartPlatform platform = 3;
}
// Chart Platform Details
message SchedulerV2ChartPlatform {
// List of the requirements
map<string, string> requirements = 1;
}
// SchedulerV2 ListCharts Request

View file

@ -23,14 +23,19 @@ package v2
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/require"
"helm.sh/helm/v3/pkg/action"
core "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
pbSchedulerV2 "github.com/arangodb/kube-arangodb/integrations/scheduler/v2/definition"
pbSharedV1 "github.com/arangodb/kube-arangodb/integrations/shared/v1/definition"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/helm"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/kerrors"
"github.com/arangodb/kube-arangodb/pkg/util/tests"
"github.com/arangodb/kube-arangodb/pkg/util/tests/suite"
)
func cleanup(t *testing.T, c helm.Client) func() {
@ -47,6 +52,32 @@ func cleanup(t *testing.T, c helm.Client) func() {
require.NoError(t, err)
})
}
t.Run("Remove NS", func(t *testing.T) {
if err := c.Client().Kubernetes().CoreV1().Namespaces().Delete(context.Background(), tests.FakeNamespace, meta.DeleteOptions{}); !kerrors.IsNotFound(err) {
require.NoError(t, err)
}
for {
time.Sleep(time.Second)
if _, err := c.Client().Kubernetes().CoreV1().Namespaces().Get(context.Background(), tests.FakeNamespace, meta.GetOptions{}); !kerrors.IsNotFound(err) {
require.NoError(t, err)
continue
}
break
}
})
t.Run("Create NS", func(t *testing.T) {
_, err = c.Client().Kubernetes().CoreV1().Namespaces().Create(context.Background(), &core.Namespace{
ObjectMeta: meta.ObjectMeta{
Name: tests.FakeNamespace,
},
}, meta.CreateOptions{})
require.NoError(t, err)
})
})
return func() {
@ -63,6 +94,23 @@ func cleanup(t *testing.T, c helm.Client) func() {
require.NoError(t, err)
})
}
t.Run("Remove NS", func(t *testing.T) {
if err := c.Client().Kubernetes().CoreV1().Namespaces().Delete(context.Background(), tests.FakeNamespace, meta.DeleteOptions{}); !kerrors.IsNotFound(err) {
require.NoError(t, err)
}
for {
time.Sleep(time.Second)
if _, err := c.Client().Kubernetes().CoreV1().Namespaces().Get(context.Background(), tests.FakeNamespace, meta.GetOptions{}); !kerrors.IsNotFound(err) {
require.NoError(t, err)
continue
}
break
}
})
})
}
}
@ -139,7 +187,7 @@ func Test_Implementation(t *testing.T) {
status, err := scheduler.Install(context.Background(), &pbSchedulerV2.SchedulerV2InstallRequest{
Name: "test",
Values: nil,
Chart: example_1_0_0,
Chart: suite.GetChart(t, "example", "1.0.0"),
})
require.NoError(t, err)
@ -154,7 +202,7 @@ func Test_Implementation(t *testing.T) {
})
t.Run("Install Outside", func(t *testing.T) {
resp, err := h.Install(context.Background(), example_1_0_0, nil, func(in *action.Install) {
resp, err := h.Install(context.Background(), suite.GetChart(t, "example", "1.0.0"), nil, func(in *action.Install) {
in.ReleaseName = "test-outside"
})
require.NoError(t, err)
@ -173,7 +221,7 @@ func Test_Implementation(t *testing.T) {
status, err := scheduler.Install(context.Background(), &pbSchedulerV2.SchedulerV2InstallRequest{
Name: "test-x",
Values: nil,
Chart: example_1_0_0,
Chart: suite.GetChart(t, "example", "1.0.0"),
Options: &pbSchedulerV2.SchedulerV2InstallRequestOptions{
Labels: map[string]string{
"X": "X",
@ -186,7 +234,7 @@ func Test_Implementation(t *testing.T) {
})
t.Run("Install Second Outside", func(t *testing.T) {
resp, err := h.Install(context.Background(), example_1_0_0, nil, func(in *action.Install) {
resp, err := h.Install(context.Background(), suite.GetChart(t, "example", "1.0.0"), nil, func(in *action.Install) {
in.ReleaseName = "test-outside-x"
in.Labels = map[string]string{
"X": "X",
@ -234,7 +282,20 @@ func Test_Implementation(t *testing.T) {
status, err := scheduler.Upgrade(context.Background(), &pbSchedulerV2.SchedulerV2UpgradeRequest{
Name: "test",
Values: values,
Chart: example_1_0_0,
Chart: suite.GetChart(t, "example", "1.0.0"),
})
require.NoError(t, err)
require.NotNil(t, status.GetAfter())
t.Logf("Data: %s", string(status.GetAfter().GetValues()))
require.Len(t, status.GetAfter().GetValues(), len(values))
})
t.Run("Upgrade to 1", func(t *testing.T) {
status, err := scheduler.Upgrade(context.Background(), &pbSchedulerV2.SchedulerV2UpgradeRequest{
Name: "test",
Values: values,
Chart: suite.GetChart(t, "example", "1.0.1"),
})
require.NoError(t, err)
@ -251,7 +312,7 @@ func Test_Implementation(t *testing.T) {
require.NotNil(t, status.GetRelease())
require.EqualValues(t, 2, status.GetRelease().GetVersion())
require.EqualValues(t, 3, status.GetRelease().GetVersion())
t.Logf("Data: %s", string(status.GetRelease().GetValues()))
require.Len(t, status.GetRelease().GetValues(), len(values))
})

View file

@ -44,9 +44,6 @@ func init() {
})
}
//go:embed suite/example-1.0.0.tgz
var example_1_0_0 []byte
func Handler(t *testing.T, ctx context.Context, client helm.Client, mods ...Mod) svc.Handler {
handler, err := New(client, NewConfiguration().With(mods...))
require.NoError(t, err)

View file

@ -71,6 +71,12 @@ func GenerateCLIArangoDBOperatorOpsReadme(root string) error {
readmeSections["arangodb_operator_ops_cmd_crd_generate"] = section
}
if section, err := GenerateHelpQuoted(cmd.CommandOps(), "debug-package"); err != nil {
return err
} else {
readmeSections["arangodb_operator_ops_cmd_debug_package"] = section
}
if err := md.ReplaceSectionsInFile(path.Join(root, "docs", "cli", "arangodb_operator_ops.md"), readmeSections); err != nil {
return err
}

View file

@ -30,8 +30,15 @@ type ArangoRouteSpecDestination struct {
Endpoints *ArangoRouteSpecDestinationEndpoints `json:"endpoints,omitempty"`
// Schema defines HTTP/S schema used for connection
// +doc/enum: http|HTTP Connection
// +doc/enum: https|HTTPS Connection (HTTP with TLS)
Schema *ArangoRouteSpecDestinationSchema `json:"schema,omitempty"`
// Protocol defines http protocol used for the route
// +doc/enum: http1|HTTP 1.1 Protocol
// +doc/enum: http2|HTTP 2 Protocol
Protocol *ArangoRouteDestinationProtocol `json:"protocol,omitempty"`
// TLS defines TLS Configuration
TLS *ArangoRouteSpecDestinationTLS `json:"tls,omitempty"`
@ -58,6 +65,14 @@ func (a *ArangoRouteSpecDestination) GetEndpoints() *ArangoRouteSpecDestinationE
return a.Endpoints
}
func (a *ArangoRouteSpecDestination) GetProtocol() *ArangoRouteDestinationProtocol {
if a == nil || a.Protocol == nil {
return nil
}
return a.Protocol
}
func (a *ArangoRouteSpecDestination) GetSchema() *ArangoRouteSpecDestinationSchema {
if a == nil || a.Schema == nil {
return nil
@ -100,6 +115,7 @@ func (a *ArangoRouteSpecDestination) Validate() error {
shared.ValidateOptionalInterfacePath("service", a.Service),
shared.ValidateOptionalInterfacePath("endpoints", a.Endpoints),
shared.ValidateOptionalInterfacePath("schema", a.Schema),
shared.ValidateOptionalInterfacePath("protocol", a.Protocol),
shared.ValidateOptionalInterfacePath("tls", a.TLS),
shared.ValidateOptionalInterfacePath("authentication", a.Authentication),
shared.PrefixResourceError("path", shared.ValidateAPIPath(a.GetPath())),

View file

@ -0,0 +1,55 @@
//
// 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 v1alpha1
import (
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/strings"
)
type ArangoRouteDestinationProtocol string
const (
ArangoRouteDestinationProtocolHTTP1 ArangoRouteDestinationProtocol = "http1"
ArangoRouteDestinationProtocolHTTP2 ArangoRouteDestinationProtocol = "http2"
ArangoRouteDestinationProtocolDefault = ArangoRouteDestinationProtocolHTTP1
)
func (a *ArangoRouteDestinationProtocol) Get() ArangoRouteDestinationProtocol {
if a == nil {
return ArangoRouteDestinationProtocolDefault
}
return ArangoRouteDestinationProtocol(strings.ToLower(string(*a)))
}
func (a *ArangoRouteDestinationProtocol) String() string {
return string(a.Get())
}
func (a *ArangoRouteDestinationProtocol) Validate() error {
switch x := a.Get(); x {
case ArangoRouteDestinationProtocolHTTP1, ArangoRouteDestinationProtocolHTTP2:
return nil
default:
return errors.Errorf("Invalid schema: %s", x.String())
}
}

View file

@ -36,6 +36,9 @@ type ArangoRouteStatusTarget struct {
// TLS Keeps target TLS Settings (if not nil, TLS is enabled)
TLS *ArangoRouteStatusTargetTLS `json:"TLS,omitempty"`
// Protocol defines http protocol used for the route
Protocol ArangoRouteDestinationProtocol `json:"protocol,omitempty"`
// Authentication specifies the authentication details
Authentication ArangoRouteStatusTargetAuthentication `json:"authentication,omitempty"`

View file

@ -147,6 +147,11 @@ func (in *ArangoRouteSpecDestination) DeepCopyInto(out *ArangoRouteSpecDestinati
*out = new(ArangoRouteSpecDestinationSchema)
**out = **in
}
if in.Protocol != nil {
in, out := &in.Protocol, &out.Protocol
*out = new(ArangoRouteDestinationProtocol)
**out = **in
}
if in.TLS != nil {
in, out := &in.TLS, &out.TLS
*out = new(ArangoRouteSpecDestinationTLS)

View file

@ -21,8 +21,17 @@
package v1alpha1
type ChartDetails struct {
Name string `json:"name,omitempty"`
Version string `json:"version,omitempty"`
Name string `json:"name,omitempty"`
Version string `json:"version,omitempty"`
Platform *ChartDetailsPlatform `json:"platform,omitempty"`
}
func (c *ChartDetails) GetPlatform() *ChartDetailsPlatform {
if c == nil {
return nil
}
return c.Platform
}
func (c *ChartDetails) GetName() string {

View file

@ -0,0 +1,33 @@
//
// 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 v1alpha1
type ChartDetailsPlatform struct {
Requirements ChartDetailsPlatformRequirements `json:"requirements,omitempty"`
}
func (c *ChartDetailsPlatform) GetRequirements() ChartDetailsPlatformRequirements {
if c == nil {
return nil
}
return c.Requirements
}

View file

@ -0,0 +1,37 @@
//
// 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 v1alpha1
import (
"github.com/arangodb/kube-arangodb/pkg/util"
)
type ChartDetailsPlatformRequirements map[string]ChartDetailsPlatformVersionConstrain
type ChartDetailsPlatformVersionConstrain string
func (c *ChartDetailsPlatformVersionConstrain) AsSemverConstrain() (util.VersionConstrain, error) {
if c == nil {
return nil, nil
}
return util.NewVersionConstrain(string(*c))
}

View file

@ -358,6 +358,11 @@ func (in *ArangoPlatformStorageStatus) DeepCopy() *ArangoPlatformStorageStatus {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ChartDetails) DeepCopyInto(out *ChartDetails) {
*out = *in
if in.Platform != nil {
in, out := &in.Platform, &out.Platform
*out = new(ChartDetailsPlatform)
(*in).DeepCopyInto(*out)
}
return
}
@ -371,6 +376,51 @@ func (in *ChartDetails) DeepCopy() *ChartDetails {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ChartDetailsPlatform) DeepCopyInto(out *ChartDetailsPlatform) {
*out = *in
if in.Requirements != nil {
in, out := &in.Requirements, &out.Requirements
*out = make(ChartDetailsPlatformRequirements, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChartDetailsPlatform.
func (in *ChartDetailsPlatform) DeepCopy() *ChartDetailsPlatform {
if in == nil {
return nil
}
out := new(ChartDetailsPlatform)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in ChartDetailsPlatformRequirements) DeepCopyInto(out *ChartDetailsPlatformRequirements) {
{
in := &in
*out = make(ChartDetailsPlatformRequirements, len(*in))
for key, val := range *in {
(*out)[key] = val
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChartDetailsPlatformRequirements.
func (in ChartDetailsPlatformRequirements) DeepCopy() ChartDetailsPlatformRequirements {
if in == nil {
return nil
}
out := new(ChartDetailsPlatformRequirements)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ChartStatusInfo) DeepCopyInto(out *ChartStatusInfo) {
*out = *in
@ -382,7 +432,7 @@ func (in *ChartStatusInfo) DeepCopyInto(out *ChartStatusInfo) {
if in.Details != nil {
in, out := &in.Details, &out.Details
*out = new(ChartDetails)
**out = **in
(*in).DeepCopyInto(*out)
}
return
}

View file

@ -36,7 +36,7 @@ import (
var (
resourceNameRE = regexp.MustCompile(`^([0-9\-\.a-z])+$`)
apiPathRE = regexp.MustCompile(`^/([_A-Za-z0-9\-]+/)*$`)
apiPathRE = regexp.MustCompile(`^(/[_A-Za-z0-9\-]+)*/?$`)
)
const (
@ -207,6 +207,19 @@ func ValidateList[T any](in []T, validator func(T) error, checks ...func(in []T)
return WithErrors(errors...)
}
// ValidateInterfaceMap Validates object if is not nil with path
func ValidateInterfaceMap[T ValidateInterface](in map[string]T) error {
errors := make([]error, 0, len(in))
for id := range in {
if err := PrefixResourceError(id, in[id].Validate()); err != nil {
errors = append(errors, err)
}
}
return WithErrors(errors...)
}
// ValidateMap validates all elements on the list
func ValidateMap[T any](in map[string]T, validator func(string, T) error, checks ...func(in map[string]T) error) error {
errors := make([]error, 0, len(in)+len(checks))

View file

@ -36,7 +36,7 @@ func Test_ValidateAPIPath(t *testing.T) {
require.NoError(t, ValidateAPIPath(""))
require.NoError(t, ValidateAPIPath("/"))
require.Error(t, ValidateAPIPath("//"))
require.Error(t, ValidateAPIPath("/api/zz"))
require.NoError(t, ValidateAPIPath("/api/zz"))
require.NoError(t, ValidateAPIPath("/api/"))
require.NoError(t, ValidateAPIPath("/api/test/qw/"))
require.NoError(t, ValidateAPIPath("/api/test/2/"))

View file

@ -49,8 +49,17 @@ v1alpha1:
path:
description: Path defines service path used for overrides
type: string
protocol:
description: Protocol defines http protocol used for the route
enum:
- http1
- http2
type: string
schema:
description: Schema defines HTTP/S schema used for connection
enum:
- http
- https
type: string
service:
description: Service defines service upstream reference

View file

@ -24,10 +24,8 @@ import (
"time"
clusterAPI "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
coreAPI "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
endpointAPI "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
routeAPI "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
upstreamHttpApi "github.com/envoyproxy/go-control-plane/envoy/extensions/upstreams/http/v3"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/durationpb"
@ -63,6 +61,8 @@ type ConfigDestination struct {
Type *ConfigDestinationType `json:"type,omitempty"`
Protocol *ConfigDestinationProtocol `json:"protocol,omitempty"`
Path *string `json:"path,omitempty"`
AuthExtension *ConfigAuthZExtension `json:"authExtension,omitempty"`
@ -77,6 +77,7 @@ func (c *ConfigDestination) Validate() error {
return shared.WithErrors(
shared.PrefixResourceError("targets", c.Targets.Validate()),
shared.PrefixResourceError("type", c.Type.Validate()),
shared.PrefixResourceError("protocol", c.Protocol.Validate()),
shared.PrefixResourceError("path", shared.ValidateAPIPath(c.GetPath())),
shared.PrefixResourceError("authExtension", c.AuthExtension.Validate()),
shared.PrefixResourceError("upgradeConfigs", c.UpgradeConfigs.Validate()),
@ -130,21 +131,7 @@ func (c *ConfigDestination) getUpgradeConfigs() ConfigDestinationsUpgrade {
}
func (c *ConfigDestination) RenderCluster(name string) (*clusterAPI.Cluster, error) {
hpo, err := anypb.New(&upstreamHttpApi.HttpProtocolOptions{
UpstreamProtocolOptions: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_{
ExplicitHttpConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig{
ProtocolConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_Http2ProtocolOptions{
Http2ProtocolOptions: &coreAPI.Http2ProtocolOptions{
ConnectionKeepalive: &coreAPI.KeepaliveSettings{
Interval: durationpb.New(15 * time.Second),
Timeout: durationpb.New(30 * time.Second),
ConnectionIdleInterval: durationpb.New(60 * time.Second),
},
},
},
},
},
})
hpo, err := anypb.New(c.Protocol.Options())
if err != nil {
return nil, err
}

View file

@ -0,0 +1,101 @@
//
// 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 gateway
import (
"time"
coreAPI "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
upstreamHttpApi "github.com/envoyproxy/go-control-plane/envoy/extensions/upstreams/http/v3"
"google.golang.org/protobuf/types/known/durationpb"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
)
type ConfigDestinationProtocol int
const (
ConfigDestinationProtocolHTTP1 ConfigDestinationProtocol = iota
ConfigDestinationProtocolHTTP2
)
func (c *ConfigDestinationProtocol) Get() ConfigDestinationProtocol {
if c == nil {
return ConfigDestinationProtocolHTTP1
}
switch v := *c; v {
case ConfigDestinationProtocolHTTP1, ConfigDestinationProtocolHTTP2:
return v
default:
return ConfigDestinationProtocolHTTP1
}
}
func (c *ConfigDestinationProtocol) Options() *upstreamHttpApi.HttpProtocolOptions {
switch c.Get() {
case ConfigDestinationProtocolHTTP1:
return &upstreamHttpApi.HttpProtocolOptions{
UpstreamProtocolOptions: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_{
ExplicitHttpConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig{
ProtocolConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_HttpProtocolOptions{
HttpProtocolOptions: &coreAPI.Http1ProtocolOptions{},
},
},
},
}
case ConfigDestinationProtocolHTTP2:
return &upstreamHttpApi.HttpProtocolOptions{
UpstreamProtocolOptions: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_{
ExplicitHttpConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig{
ProtocolConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_Http2ProtocolOptions{
Http2ProtocolOptions: &coreAPI.Http2ProtocolOptions{
ConnectionKeepalive: &coreAPI.KeepaliveSettings{
Interval: durationpb.New(15 * time.Second),
Timeout: durationpb.New(30 * time.Second),
ConnectionIdleInterval: durationpb.New(60 * time.Second),
},
},
},
},
},
}
default:
return &upstreamHttpApi.HttpProtocolOptions{
UpstreamProtocolOptions: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_{
ExplicitHttpConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig{
ProtocolConfig: &upstreamHttpApi.HttpProtocolOptions_ExplicitHttpConfig_HttpProtocolOptions{
HttpProtocolOptions: &coreAPI.Http1ProtocolOptions{},
},
},
},
}
}
}
func (c *ConfigDestinationProtocol) Validate() error {
switch c.Get() {
case ConfigDestinationProtocolHTTP1, ConfigDestinationProtocolHTTP2:
return nil
default:
return errors.Errorf("Invalid destination protocol")
}
}

View file

@ -120,6 +120,7 @@ func (h *handler) HandleArangoDestinationEndpoints(ctx context.Context, item ope
target.Path = dest.GetPath()
target.Type = networkingApi.ArangoRouteStatusTargetEndpointsType
target.Protocol = dest.GetProtocol().Get()
// Render Auth Settings

View file

@ -96,6 +96,149 @@ func Test_Handler_Destination_Endpoints_Valid(t *testing.T) {
require.Len(t, extension.Status.Target.RenderURLs(), 1)
require.EqualValues(t, "http://127.0.0.1:10244/", extension.Status.Target.RenderURLs()[0])
require.EqualValues(t, "http1", extension.Status.Target.Protocol)
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
}
func Test_Handler_Destination_Endpoints_Valid_HTTP1(t *testing.T) {
// Setup
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Deployment = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Protocol: util.NewType(networkingApi.ArangoRouteDestinationProtocolHTTP1),
Endpoints: &networkingApi.ArangoRouteSpecDestinationEndpoints{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
obj.Spec.Ports = []core.ServicePort{
{
Port: 10244,
},
}
})
endpoints := tests.NewMetaObject[*core.Endpoints](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Endpoints) {
obj.Subsets = []core.EndpointSubset{
{
Addresses: []core.EndpointAddress{
{
IP: "127.0.0.1",
},
},
Ports: []core.EndpointPort{
{
Name: "",
Port: 10244,
},
},
},
}
})
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc, &endpoints)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.SpecValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
require.Equal(t, networkingApi.ArangoRouteStatusTargetEndpointsType, extension.Status.Target.Type)
require.Len(t, extension.Status.Target.RenderURLs(), 1)
require.EqualValues(t, "http://127.0.0.1:10244/", extension.Status.Target.RenderURLs()[0])
require.EqualValues(t, "http1", extension.Status.Target.Protocol)
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
}
func Test_Handler_Destination_Endpoints_Valid_HTTP2(t *testing.T) {
// Setup
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Deployment = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Protocol: util.NewType(networkingApi.ArangoRouteDestinationProtocolHTTP2),
Endpoints: &networkingApi.ArangoRouteSpecDestinationEndpoints{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
obj.Spec.Ports = []core.ServicePort{
{
Port: 10244,
},
}
})
endpoints := tests.NewMetaObject[*core.Endpoints](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Endpoints) {
obj.Subsets = []core.EndpointSubset{
{
Addresses: []core.EndpointAddress{
{
IP: "127.0.0.1",
},
},
Ports: []core.EndpointPort{
{
Name: "",
Port: 10244,
},
},
},
}
})
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc, &endpoints)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.SpecValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
require.Equal(t, networkingApi.ArangoRouteStatusTargetEndpointsType, extension.Status.Target.Type)
require.Len(t, extension.Status.Target.RenderURLs(), 1)
require.EqualValues(t, "http://127.0.0.1:10244/", extension.Status.Target.RenderURLs()[0])
require.EqualValues(t, "http2", extension.Status.Target.Protocol)
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)

View file

@ -119,6 +119,7 @@ func (h *handler) HandleArangoDestinationService(ctx context.Context, item opera
target.Path = dest.GetPath()
target.Type = networkingApi.ArangoRouteStatusTargetServiceType
target.Protocol = dest.GetProtocol().Get()
// Render Auth Settings

View file

@ -119,6 +119,115 @@ func Test_Handler_Destination_Service_Valid(t *testing.T) {
require.Len(t, extension.Status.Target.RenderURLs(), 1)
require.EqualValues(t, "http://deployment.fake.svc:10244/", extension.Status.Target.RenderURLs()[0])
require.EqualValues(t, "http1", extension.Status.Target.Protocol)
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
}
func Test_Handler_Destination_Service_Valid_HTTP1(t *testing.T) {
// Setup
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Deployment = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Protocol: util.NewType(networkingApi.ArangoRouteDestinationProtocolHTTP1),
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
obj.Spec.Ports = []core.ServicePort{
{
Port: 10244,
},
}
})
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.SpecValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
require.Equal(t, networkingApi.ArangoRouteStatusTargetServiceType, extension.Status.Target.Type)
require.Len(t, extension.Status.Target.RenderURLs(), 1)
require.EqualValues(t, "http://deployment.fake.svc:10244/", extension.Status.Target.RenderURLs()[0])
require.EqualValues(t, "http1", extension.Status.Target.Protocol)
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Reason, "Destination Found")
require.EqualValues(t, c.Hash, extension.Status.Target.Hash())
}
func Test_Handler_Destination_Service_Valid_HTTP2(t *testing.T) {
// Setup
handler := newFakeHandler()
// Arrange
extension := tests.NewMetaObject[*networkingApi.ArangoRoute](t, tests.FakeNamespace, "test",
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Deployment = util.NewType("deployment")
},
func(t *testing.T, obj *networkingApi.ArangoRoute) {
obj.Spec.Destination = &networkingApi.ArangoRouteSpecDestination{
Protocol: util.NewType(networkingApi.ArangoRouteDestinationProtocolHTTP2),
Service: &networkingApi.ArangoRouteSpecDestinationService{
Object: &sharedApi.Object{
Name: "deployment",
},
Port: util.NewType(intstr.FromInt32(10244)),
},
}
})
deployment := tests.NewMetaObject[*api.ArangoDeployment](t, tests.FakeNamespace, "deployment")
svc := tests.NewMetaObject[*core.Service](t, tests.FakeNamespace, "deployment", func(t *testing.T, obj *core.Service) {
obj.Spec.Ports = []core.ServicePort{
{
Port: 10244,
},
}
})
refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &deployment, &extension, &svc)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Assert
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.SpecValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.DestinationValidCondition))
require.True(t, extension.Status.Conditions.IsTrue(networkingApi.ReadyCondition))
require.Equal(t, networkingApi.ArangoRouteStatusTargetServiceType, extension.Status.Target.Type)
require.Len(t, extension.Status.Target.RenderURLs(), 1)
require.EqualValues(t, "http://deployment.fake.svc:10244/", extension.Status.Target.RenderURLs()[0])
require.EqualValues(t, "http2", extension.Status.Target.Protocol)
c, ok := extension.Status.Conditions.Get(networkingApi.DestinationValidCondition)
require.True(t, ok)

View file

@ -29,6 +29,7 @@ import (
"github.com/arangodb/kube-arangodb/pkg/operatorV2/operation"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/tests"
"github.com/arangodb/kube-arangodb/pkg/util/tests/suite"
)
func Test_ChartReconcile_EmptyChart(t *testing.T) {
@ -78,7 +79,7 @@ func Test_ChartReconcile_EmptyChart(t *testing.T) {
t.Run("Invalid chart name", func(t *testing.T) {
// Arrange
tests.Apply(t, extension_invalid_name, func(t *testing.T, obj *platformApi.ArangoPlatformChart) {
obj.Spec.Definition = chart_1_0
obj.Spec.Definition = suite.GetChart(t, "example", "1.0.0")
})
tests.UpdateObjects(t, handler.kubeClient, handler.client, &extension_invalid_name)
@ -99,7 +100,7 @@ func Test_ChartReconcile_EmptyChart(t *testing.T) {
t.Run("Valid chart 1.0.0", func(t *testing.T) {
// Arrange
tests.Apply(t, extension, func(t *testing.T, obj *platformApi.ArangoPlatformChart) {
obj.Spec.Definition = chart_1_0
obj.Spec.Definition = suite.GetChart(t, "example", "1.0.0")
})
tests.UpdateObjects(t, handler.kubeClient, handler.client, &extension)
@ -117,14 +118,41 @@ func Test_ChartReconcile_EmptyChart(t *testing.T) {
require.NotNil(t, extension.Status.Info.Details)
require.EqualValues(t, "example", extension.Status.Info.Details.GetName())
require.EqualValues(t, "1.0.0", extension.Status.Info.Details.GetVersion())
require.EqualValues(t, util.SHA256(chart_1_0), extension.Status.Info.Checksum)
require.EqualValues(t, util.SHA256(suite.GetChart(t, "example", "1.0.0")), extension.Status.Info.Checksum)
require.Nil(t, extension.Status.Info.Details.Platform)
require.True(t, extension.Status.Conditions.IsTrue(platformApi.ReadyCondition))
})
t.Run("Valid chart 1.0.1", func(t *testing.T) {
// Arrange
tests.Apply(t, extension, func(t *testing.T, obj *platformApi.ArangoPlatformChart) {
obj.Spec.Definition = suite.GetChart(t, "example", "1.0.1")
})
tests.UpdateObjects(t, handler.kubeClient, handler.client, &extension)
// Test
require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension)))
// Refresh
refresh(t)
// Validate
require.True(t, extension.Status.Conditions.IsTrue(platformApi.SpecValidCondition))
require.NotNil(t, extension.Status.Info)
require.True(t, extension.Status.Info.Valid)
require.EqualValues(t, extension.Status.Info.Message, "")
require.NotNil(t, extension.Status.Info.Details)
require.EqualValues(t, "example", extension.Status.Info.Details.GetName())
require.EqualValues(t, "1.0.1", extension.Status.Info.Details.GetVersion())
require.EqualValues(t, util.SHA256(suite.GetChart(t, "example", "1.0.1")), extension.Status.Info.Checksum)
require.NotNil(t, extension.Status.Info.Details.Platform)
require.True(t, extension.Status.Conditions.IsTrue(platformApi.ReadyCondition))
})
t.Run("Valid chart 1.1.0", func(t *testing.T) {
// Arrange
tests.Apply(t, extension, func(t *testing.T, obj *platformApi.ArangoPlatformChart) {
obj.Spec.Definition = chart_1_1
obj.Spec.Definition = suite.GetChart(t, "example", "1.1.0")
})
tests.UpdateObjects(t, handler.kubeClient, handler.client, &extension)
@ -142,7 +170,8 @@ func Test_ChartReconcile_EmptyChart(t *testing.T) {
require.NotNil(t, extension.Status.Info.Details)
require.EqualValues(t, "example", extension.Status.Info.Details.GetName())
require.EqualValues(t, "1.1.0", extension.Status.Info.Details.GetVersion())
require.EqualValues(t, util.SHA256(chart_1_1), extension.Status.Info.Checksum)
require.Nil(t, extension.Status.Info.Details.Platform)
require.EqualValues(t, util.SHA256(suite.GetChart(t, "example", "1.1.0")), extension.Status.Info.Checksum)
require.True(t, extension.Status.Conditions.IsTrue(platformApi.ReadyCondition))
})
}

View file

@ -142,7 +142,7 @@ func (h *handler) HandleSpecData(ctx context.Context, item operation.Item, exten
return true, operator.Reconcile("Spec changed")
}
if chart.Name() != extension.GetName() {
if chart.Chart().Name() != extension.GetName() {
status.Info = &platformApi.ChartStatusInfo{
Definition: extension.Spec.Definition,
Checksum: extension.Spec.Definition.SHA256(),
@ -153,11 +153,23 @@ func (h *handler) HandleSpecData(ctx context.Context, item operation.Item, exten
return true, operator.Reconcile("Spec changed")
}
platform, err := chart.Platform()
if err != nil {
status.Info = &platformApi.ChartStatusInfo{
Definition: extension.Spec.Definition,
Checksum: extension.Spec.Definition.SHA256(),
Valid: false,
Message: "Chart is invalid: Unable to get platform details",
}
return true, operator.Reconcile("Spec changed")
}
status.Info = &platformApi.ChartStatusInfo{
Definition: extension.Spec.Definition,
Checksum: extension.Spec.Definition.SHA256(),
Valid: true,
Details: chartInfoExtract(chart),
Details: chartInfoExtract(chart.Chart(), platform),
}
return true, operator.Reconcile("Spec changed")
@ -169,13 +181,29 @@ func (h *handler) CanBeHandled(item operation.Item) bool {
item.Kind == Kind()
}
func chartInfoExtract(chart *chart.Chart) *platformApi.ChartDetails {
func chartInfoExtract(chart *chart.Chart, platform *helm.Platform) *platformApi.ChartDetails {
if chart == nil || chart.Metadata == nil {
return nil
}
return &platformApi.ChartDetails{
r := &platformApi.ChartDetails{
Name: chart.Name(),
Version: chart.Metadata.Version,
}
if platform != nil {
var c platformApi.ChartDetailsPlatform
if len(platform.Requirements) > 0 {
c.Requirements = make(platformApi.ChartDetailsPlatformRequirements, len(platform.Requirements))
for k, v := range platform.Requirements {
c.Requirements[k] = platformApi.ChartDetailsPlatformVersionConstrain(v)
}
}
r.Platform = &c
}
return r
}

View file

@ -33,12 +33,6 @@ import (
"github.com/arangodb/kube-arangodb/pkg/operatorV2/operation"
)
//go:embed suite/example-1.0.0.tgz
var chart_1_0 []byte
//go:embed suite/example-1.1.0.tgz
var chart_1_1 []byte
func newFakeHandler() *handler {
f := fakeClientSet.NewSimpleClientset()
k := fake.NewSimpleClientset()

View file

@ -30,8 +30,12 @@ import (
type Chart []byte
func (c Chart) Get() (*chart.Chart, error) {
return newChartReaderFromBytes(c)
func (c Chart) Get() (ChartData, error) {
return newChartFromData(c)
}
func (c Chart) Raw() []byte {
return c
}
func newChartReaderFromBytes(in []byte) (*chart.Chart, error) {

View file

@ -0,0 +1,58 @@
//
// 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 helm
import (
"helm.sh/helm/v3/pkg/chart"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
)
type ChartData interface {
Chart() *chart.Chart
Platform() (*Platform, error)
}
type chartData struct {
chart *chart.Chart
}
func (c chartData) Platform() (*Platform, error) {
return extractPlatform(c.chart)
}
func (c chartData) Chart() *chart.Chart {
return c.chart
}
func newChartFromData(data []byte) (ChartData, error) {
var c chartData
v, err := newChartReaderFromBytes(data)
if err != nil {
return nil, errors.Errorf("Unable to load chart")
}
c.chart = v
return c, nil
}

View file

@ -50,17 +50,17 @@ func Test_Manager(t *testing.T) {
vchart, err := vdata.Get()
require.NoError(t, err)
require.NotNil(t, vchart.Metadata)
require.NotNil(t, vchart.Chart().Metadata)
data, err := mgr.Chart(context.Background(), repo, "latest")
require.NoError(t, err)
chart, err := data.Get()
require.NoError(t, err)
require.NotNil(t, chart.Metadata)
require.NotNil(t, chart.Chart().Metadata)
require.EqualValues(t, v, vchart.Metadata.Version)
require.EqualValues(t, v, chart.Metadata.Version)
require.EqualValues(t, v, vchart.Chart().Metadata.Version)
require.EqualValues(t, v, chart.Chart().Metadata.Version)
})
t.Run("ByVersion", func(t *testing.T) {
for _, version := range limitArray(mgr.Versions(repo), 5) {
@ -71,8 +71,8 @@ func Test_Manager(t *testing.T) {
c, err := data.Get()
require.NoError(t, err)
require.NotNil(t, c.Metadata)
require.EqualValues(t, version, c.Metadata.Version)
require.NotNil(t, c.Chart().Metadata)
require.EqualValues(t, version, c.Chart().Metadata.Version)
})
}
})

View file

@ -184,7 +184,7 @@ func (c *client) Install(ctx context.Context, chart Chart, values Values, mods .
return nil, err
}
result, err := act.Run(chartData, valuesData)
result, err := act.Run(chartData.Chart(), valuesData)
if err != nil {
return nil, err
}
@ -217,7 +217,7 @@ func (c *client) Upgrade(ctx context.Context, name string, chart Chart, values V
}
if release != nil {
if meta := chartData.Metadata; meta != nil {
if meta := chartData.Chart().Metadata; meta != nil {
if release.GetChart().GetMetadata().GetVersion() == meta.Version {
// We are on the same version
if release.Values.Equals(values) {
@ -230,7 +230,7 @@ func (c *client) Upgrade(ctx context.Context, name string, chart Chart, values V
}
}
result, err := act.Run(name, chartData, valuesData)
result, err := act.Run(name, chartData.Chart(), valuesData)
if err != nil {
return nil, err
}

View file

@ -30,6 +30,7 @@ import (
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/arangodb/kube-arangodb/pkg/util/tests"
"github.com/arangodb/kube-arangodb/pkg/util/tests/suite"
)
func cleanup(t *testing.T, c Client) func() {
@ -81,7 +82,7 @@ func Test_Connection(t *testing.T) {
})
t.Run("Install", func(t *testing.T) {
resp, err := c.Install(context.Background(), example_1_0_0, nil, func(in *action.Install) {
resp, err := c.Install(context.Background(), suite.GetChart(t, "example", "1.0.0"), nil, func(in *action.Install) {
in.ReleaseName = "test"
})
require.NoError(t, err)
@ -90,7 +91,7 @@ func Test_Connection(t *testing.T) {
})
t.Run("Upgrade With No change", func(t *testing.T) {
resp, err := c.Upgrade(context.Background(), "test", example_1_0_0, nil)
resp, err := c.Upgrade(context.Background(), "test", suite.GetChart(t, "example", "1.0.0"), nil)
require.NoError(t, err)
require.NotNil(t, resp)
@ -99,7 +100,7 @@ func Test_Connection(t *testing.T) {
})
t.Run("Upgrade With change", func(t *testing.T) {
resp, err := c.Upgrade(context.Background(), "test", example_1_0_0, Values(`{"A":"X"}`))
resp, err := c.Upgrade(context.Background(), "test", suite.GetChart(t, "example", "1.0.0"), Values(`{"A":"X"}`))
require.NoError(t, err)
require.NotNil(t, resp)
@ -135,7 +136,7 @@ func Test_Connection(t *testing.T) {
})
t.Run("Reinstall", func(t *testing.T) {
resp, err := c.Install(context.Background(), example_1_0_0, nil, func(in *action.Install) {
resp, err := c.Install(context.Background(), suite.GetChart(t, "example", "1.0.0"), nil, func(in *action.Install) {
in.ReleaseName = "test"
in.Labels = map[string]string{
"X1": "X1",
@ -150,7 +151,7 @@ func Test_Connection(t *testing.T) {
defer cleanup(t, c)()
t.Run("Install", func(t *testing.T) {
resp, err := c.Install(context.Background(), example_1_0_0, nil, func(in *action.Install) {
resp, err := c.Install(context.Background(), suite.GetChart(t, "example", "1.0.0"), nil, func(in *action.Install) {
in.ReleaseName = "test-1"
in.Labels = map[string]string{
"X1": "X1",
@ -160,7 +161,7 @@ func Test_Connection(t *testing.T) {
require.Len(t, resp.Labels, 1)
resp, err = c.Install(context.Background(), example_1_0_0, nil, func(in *action.Install) {
resp, err = c.Install(context.Background(), suite.GetChart(t, "example", "1.0.0"), nil, func(in *action.Install) {
in.ReleaseName = "test-2"
in.Labels = map[string]string{
"X1": "X2",
@ -170,7 +171,7 @@ func Test_Connection(t *testing.T) {
require.Len(t, resp.Labels, 1)
resp, err = c.Install(context.Background(), example_1_0_0, nil, func(in *action.Install) {
resp, err = c.Install(context.Background(), suite.GetChart(t, "example", "1.0.0"), nil, func(in *action.Install) {
in.ReleaseName = "test-3"
in.Labels = map[string]string{
"X1": "X1",
@ -181,7 +182,7 @@ func Test_Connection(t *testing.T) {
require.Len(t, resp.Labels, 2)
resp, err = c.Install(context.Background(), example_1_0_0, nil, func(in *action.Install) {
resp, err = c.Install(context.Background(), suite.GetChart(t, "example", "1.0.0"), nil, func(in *action.Install) {
in.ReleaseName = "test-4"
})
require.NoError(t, err)
@ -236,7 +237,7 @@ func Test_Connection(t *testing.T) {
defer cleanup(t, c)()
t.Run("Install", func(t *testing.T) {
resp, err := c.Install(context.Background(), example_1_0_0, nil, func(in *action.Install) {
resp, err := c.Install(context.Background(), suite.GetChart(t, "example", "1.0.0"), nil, func(in *action.Install) {
in.ReleaseName = "test"
})
require.NoError(t, err)
@ -250,7 +251,7 @@ func Test_Connection(t *testing.T) {
})
t.Run("Update", func(t *testing.T) {
resp, err := c.Upgrade(context.Background(), "test", example_1_0_0, newValues(t, map[string]any{
resp, err := c.Upgrade(context.Background(), "test", suite.GetChart(t, "example", "1.0.0"), newValues(t, map[string]any{
"data": map[string]string{
"test": "test",
},

View file

@ -0,0 +1,54 @@
//
// 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 helm
import (
"helm.sh/helm/v3/pkg/chart"
"github.com/arangodb/kube-arangodb/pkg/util"
)
const (
PlatformFileName = "platform.yml"
)
func extractPlatform(chart *chart.Chart) (*Platform, error) {
if chart == nil {
return nil, nil
}
for _, file := range chart.Files {
if file == nil {
return nil, nil
}
if file.Name == PlatformFileName {
obj, err := util.JsonOrYamlUnmarshal[Platform](file.Data)
if err != nil {
return nil, err
}
return &obj, nil
}
}
return nil, nil
}

View file

@ -0,0 +1,29 @@
//
// 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 helm
type Platform struct {
Requirements PlatformRequirements `json:"requirements,omitempty"`
}
type PlatformRequirements map[string]PlatformVersionDefinition
type PlatformVersionDefinition string

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 helm
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/arangodb/kube-arangodb/pkg/util/tests/suite"
)
func Test_Platform(t *testing.T) {
c1, err := Chart(suite.GetChart(t, "example", "1.0.0")).Get()
require.NoError(t, err)
p1, err := c1.Platform()
require.NoError(t, err)
c2, err := Chart(suite.GetChart(t, "example", "1.0.1")).Get()
require.NoError(t, err)
p2, err := c2.Platform()
require.NoError(t, err)
require.Nil(t, p1)
require.NotNil(t, p2)
}

View file

@ -38,9 +38,6 @@ func init() {
})
}
//go:embed suite/example-1.0.0.tgz
var example_1_0_0 []byte
func newValues(t *testing.T, in any) Values {
v, err := NewValues(in)
require.NoError(t, err)

View file

@ -0,0 +1,55 @@
//
// 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 suite
import (
_ "embed"
"testing"
"github.com/stretchr/testify/require"
)
//go:embed chart/example-1.0.0.tgz
var chart_example_1_0_0 []byte
//go:embed chart/example-1.0.1.tgz
var chart_example_1_0_1 []byte
//go:embed chart/example-1.1.0.tgz
var chart_example_1_1_0 []byte
func GetChart(t *testing.T, name, version string) []byte {
switch name {
case "example":
switch version {
case "1.0.0":
return chart_example_1_0_0
case "1.0.1":
return chart_example_1_0_1
case "1.1.0":
return chart_example_1_1_0
}
}
require.Fail(t, "Chart with version not found")
return nil
}

Binary file not shown.

Binary file not shown.

57
pkg/util/version.go Normal file
View file

@ -0,0 +1,57 @@
//
// 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 "github.com/Masterminds/semver/v3"
type VersionConstrain interface {
Validate(version string) (bool, error)
}
type versionConstrain struct {
constrain *semver.Constraints
}
func (v versionConstrain) Validate(version string) (bool, error) {
ver, err := semver.NewVersion(version)
if err != nil {
return false, err
}
if ver.Prerelease() != "" {
nver, nerr := ver.SetPrerelease("")
if nerr != nil {
return false, nerr
}
ver = &nver
}
return v.constrain.Check(ver), nil
}
func NewVersionConstrain(constrain string) (VersionConstrain, error) {
c, err := semver.NewConstraint(constrain)
if err != nil {
return nil, err
}
return versionConstrain{constrain: c}, nil
}

127
pkg/util/version_test.go Normal file
View file

@ -0,0 +1,127 @@
//
// 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 (
"testing"
"github.com/stretchr/testify/require"
)
func Test_VersionConstrain(t *testing.T) {
type constrain struct {
version string
valid bool
}
validate := func(version string, checks ...constrain) {
t.Run(version, func(t *testing.T) {
vc, err := NewVersionConstrain(version)
require.NoError(t, err)
for _, el := range checks {
t.Run(el.version, func(t *testing.T) {
b, err := vc.Validate(el.version)
require.NoError(t, err)
if el.valid {
require.True(t, b)
} else {
require.False(t, b)
}
})
}
})
}
validate(">= 1.2.3 < 1.3.0",
constrain{
version: "1.2.3",
valid: true,
},
constrain{
version: "1.2.5",
valid: true,
},
constrain{
version: "1.3.0",
},
constrain{
version: "v1.2.3-abcdefg",
valid: true,
},
)
validate(">= 1.2.3 < 1.3.0 || >= 1.3.1 < 1.4.0",
constrain{
version: "1.2.3",
valid: true,
},
constrain{
version: "1.2.5",
valid: true,
},
constrain{
version: "1.3.0",
},
constrain{
version: "v1.2.3-abcdefg",
valid: true,
},
constrain{
version: "1.3.5",
valid: true,
},
constrain{
version: "1.4.0",
},
)
validate("~ 1",
constrain{
version: "1.2.3",
valid: true,
},
constrain{
version: "1.2.5",
valid: true,
},
constrain{
version: "1.3.0",
valid: true,
},
constrain{
version: "v1.2.3-abcdefg",
valid: true,
},
constrain{
version: "1.3.5",
valid: true,
},
constrain{
version: "1.4.0",
valid: true,
},
constrain{
version: "2.0.0",
},
)
}