Skip to content
3 changes: 3 additions & 0 deletions .changes/unreleased/Added-20250512-140119.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Added
body: '`insecurePort` can be specified in GRPC Service spec to create a Service with a second port (for non-tls grpc port in storage)'
time: 2025-05-12T14:01:19.020259248+02:00
3 changes: 3 additions & 0 deletions .changes/unreleased/Added-20250512-143551.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Added
body: Default 2135 port on the GRPC service can now be overridden
time: 2025-05-12T14:35:51.255373275+02:00
3 changes: 3 additions & 0 deletions .changes/unreleased/Fixed-20250513-113445.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Fixed
body: '[development] mutating\validating webhooks now run during medium tests (previously e2e only)'
time: 2025-05-13T11:34:45.560660001+02:00
8 changes: 6 additions & 2 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,18 @@ jobs:
- name: setup-go
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: '1.23'
- name: setup-medium-test-class-binaries
run: |
# This installs kube-apiserver and etcd binaries for `medium`
# class tests. Refer to the writing tests docs for more info.
make envtest
KUBEBUILDER_ASSETS=$(./bin/setup-envtest use 1.26 -p path)
echo "KUBEBUILDER_ASSETS=$KUBEBUILDER_ASSETS" >> $GITHUB_ENV
- name: render-webhook-manifests
run: |
# This renders webhook manifests to ./config/webhook
make manifests
- name: setup-gotestsum
run: |
go install gotest.tools/[email protected]
Expand Down Expand Up @@ -76,7 +80,7 @@ jobs:
- name: setup-go
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: '1.23'
- name: install-dependencies
run: |
sudo apt-get update
Expand Down
11 changes: 6 additions & 5 deletions api/v1alpha1/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ const (
DefaultDomainName = "cluster.local"
DNSDomainAnnotation = "dns.domain"

GRPCPort = 2135
GRPCServicePortName = "grpc"
GRPCProto = "grpc://"
GRPCSProto = "grpcs://"
GRPCServiceFQDNFormat = "%s-grpc.%s.svc.%s"
GRPCPort = 2135
GRPCServicePortName = "grpc"
GRPCServiceInsecurePortName = "insecure-grpc"
GRPCProto = "grpc://"
GRPCSProto = "grpcs://"
GRPCServiceFQDNFormat = "%s-grpc.%s.svc.%s"

InterconnectPort = 19001
InterconnectServicePortName = "interconnect"
Expand Down
3 changes: 3 additions & 0 deletions api/v1alpha1/service_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ type TLSConfiguration struct {
type GRPCService struct {
Service `json:""`

InsecurePort int32 `json:"insecurePort,omitempty"`
Port int32 `json:"port,omitempty"`

TLSConfiguration *TLSConfiguration `json:"tls,omitempty"`
ExternalHost string `json:"externalHost,omitempty"`
ExternalPort int32 `json:"externalPort,omitempty"`
Expand Down
119 changes: 110 additions & 9 deletions api/v1alpha1/storage_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,7 @@ func (r *Storage) GetGRPCServiceEndpoint() string {
}

func (r *Storage) GetHostFromConfigEndpoint() string {
var rawYamlConfiguration string
// skip handle error because we already checked in webhook
success, dynConfig, _ := ParseDynConfig(r.Spec.Configuration)
if success {
config, _ := yaml.Marshal(dynConfig.Config)
rawYamlConfiguration = string(config)
} else {
rawYamlConfiguration = r.Spec.Configuration
}
rawYamlConfiguration := r.getRawYamlConfiguration()

configuration, _ := ParseConfiguration(rawYamlConfiguration)
randNum := rand.Intn(len(configuration.Hosts)) // #nosec G404
Expand Down Expand Up @@ -443,6 +435,115 @@ func (r *Storage) ValidateUpdate(old runtime.Object) error {
return crdCheckError
}

if err := r.validateGrpcPorts(); err != nil {
return err
}

return nil
}

func (r *Storage) getRawYamlConfiguration() string {
var rawYamlConfiguration string
// skip handle error because we already checked in webhook
success, dynConfig, _ := ParseDynConfig(r.Spec.Configuration)
if success {
config, _ := yaml.Marshal(dynConfig.Config)
rawYamlConfiguration = string(config)
} else {
rawYamlConfiguration = r.Spec.Configuration
}

return rawYamlConfiguration
}

func (r *Storage) validateGrpcPorts() error {
// There are three possible ways to configure grpc ports:

// service:
// grpc: == this means one insecure port, tls is disabled
// port: 2135

// service:
// grpc:
// port: 2136 == this means one secure port, tls is enabled
// tls:
// enabled: true

// service:
// grpc:
// insecurePort: 2135 == this means two ports, one secure \ one insecure
// port: 2136
// tls:
// enabled: true

rawYamlConfiguration := r.getRawYamlConfiguration()
configuration, err := ParseConfiguration(rawYamlConfiguration)
if err != nil {
return fmt.Errorf("failed to parse configuration immediately after building it, should not happen, %w", err)
}
configurationPort := int32(GRPCPort)
if configuration.GrpcConfig.Port != 0 {
configurationPort = configuration.GrpcConfig.Port
}
configurationSslPort := int32(0)
if configuration.GrpcConfig.SslPort != 0 {
configurationSslPort = configuration.GrpcConfig.SslPort
}

if !r.Spec.Service.GRPC.TLSConfiguration.Enabled {
// there should be only 1 port, both in service and in config, insecure
servicePort := int32(GRPCPort)
if r.Spec.Service.GRPC.Port != 0 {
servicePort = r.Spec.Service.GRPC.Port
}
if configurationPort != servicePort {
return fmt.Errorf(
"inconsistent grpc ports: spec.service.grpc.port (%v) != configuration.grpc_config.port (%v)",
servicePort,
configurationPort,
)
}

if r.Spec.Service.GRPC.InsecurePort != 0 {
return fmt.Errorf(
"spec.service.grpc.tls.enabled is false, use `port` instead of `insecurePort` field to assign non-tls grpc port",
)
}
return nil
}

// otherwise, there might be 1 (secure only) port...
servicePort := int32(GRPCPort)
if r.Spec.Service.GRPC.Port != 0 {
servicePort = r.Spec.Service.GRPC.Port
}
if configurationSslPort == 0 {
return fmt.Errorf(
"configuration.grpc_config.ssl_port is absent in cluster configuration, but spec.service.grpc has tls enabled and port %v",
servicePort,
)
}
if configurationSslPort != servicePort {
return fmt.Errorf(
"inconsistent grpc ports: spec.service.grpc.port (%v) != configuration.grpc_config.ssl_port (%v)",
servicePort,
configurationSslPort,
)
}

// or, optionally, one more: insecure port
if r.Spec.Service.GRPC.InsecurePort != 0 {
serviceInsecurePort := r.Spec.Service.GRPC.InsecurePort

if configurationPort != serviceInsecurePort {
return fmt.Errorf(
"inconsistent grpc insecure ports: spec.service.grpc.insecure_port (%v) != configuration.grpc_config.port (%v)",
serviceInsecurePort,
configurationPort,
)
}
}

return nil
}

Expand Down
6 changes: 6 additions & 0 deletions deploy/ydb-operator/crds/database.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4078,6 +4078,9 @@ spec:
externalPort:
format: int32
type: integer
insecurePort:
format: int32
type: integer
ipDiscovery:
properties:
enabled:
Expand All @@ -4103,6 +4106,9 @@ spec:
description: IPFamilyPolicy represents the dual-stack-ness
requested or required by a Service
type: string
port:
format: int32
type: integer
tls:
properties:
CA:
Expand Down
6 changes: 6 additions & 0 deletions deploy/ydb-operator/crds/databasenodeset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2690,6 +2690,9 @@ spec:
externalPort:
format: int32
type: integer
insecurePort:
format: int32
type: integer
ipDiscovery:
properties:
enabled:
Expand All @@ -2715,6 +2718,9 @@ spec:
description: IPFamilyPolicy represents the dual-stack-ness
requested or required by a Service
type: string
port:
format: int32
type: integer
tls:
properties:
CA:
Expand Down
6 changes: 6 additions & 0 deletions deploy/ydb-operator/crds/remotedatabasenodeset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2691,6 +2691,9 @@ spec:
externalPort:
format: int32
type: integer
insecurePort:
format: int32
type: integer
ipDiscovery:
properties:
enabled:
Expand All @@ -2716,6 +2719,9 @@ spec:
description: IPFamilyPolicy represents the dual-stack-ness
requested or required by a Service
type: string
port:
format: int32
type: integer
tls:
properties:
CA:
Expand Down
6 changes: 6 additions & 0 deletions deploy/ydb-operator/crds/remotestoragenodeset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2718,6 +2718,9 @@ spec:
externalPort:
format: int32
type: integer
insecurePort:
format: int32
type: integer
ipDiscovery:
properties:
enabled:
Expand All @@ -2743,6 +2746,9 @@ spec:
description: IPFamilyPolicy represents the dual-stack-ness
requested or required by a Service
type: string
port:
format: int32
type: integer
tls:
properties:
CA:
Expand Down
6 changes: 6 additions & 0 deletions deploy/ydb-operator/crds/storage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5219,6 +5219,9 @@ spec:
externalPort:
format: int32
type: integer
insecurePort:
format: int32
type: integer
ipDiscovery:
properties:
enabled:
Expand All @@ -5244,6 +5247,9 @@ spec:
description: IPFamilyPolicy represents the dual-stack-ness
requested or required by a Service
type: string
port:
format: int32
type: integer
tls:
properties:
CA:
Expand Down
6 changes: 6 additions & 0 deletions deploy/ydb-operator/crds/storagenodeset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2717,6 +2717,9 @@ spec:
externalPort:
format: int32
type: integer
insecurePort:
format: int32
type: integer
ipDiscovery:
properties:
enabled:
Expand All @@ -2742,6 +2745,9 @@ spec:
description: IPFamilyPolicy represents the dual-stack-ness
requested or required by a Service
type: string
port:
format: int32
type: integer
tls:
properties:
CA:
Expand Down
1 change: 1 addition & 0 deletions internal/configuration/schema/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type Configuration struct {
DomainsConfig *DomainsConfig `yaml:"domains_config"`
Hosts []Host `yaml:"hosts,omitempty"`
KeyConfig *KeyConfig `yaml:"key_config,omitempty"`
GrpcConfig *GrpcConfig `yaml:"grpc_config,omitempty"`
}

type Metadata struct {
Expand Down
6 changes: 6 additions & 0 deletions internal/configuration/schema/grpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package schema

type GrpcConfig struct {
Port int32 `yaml:"port,omitempty"`
SslPort int32 `yaml:"ssl_port,omitempty"`
}
11 changes: 6 additions & 5 deletions internal/controllers/databasenodeset/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,11 @@ var _ = Describe("DatabaseNodeSet controller medium tests", func() {
}, test.Timeout, test.Interval).ShouldNot(HaveOccurred())

databaseSample = *testobjects.DefaultDatabase()
databaseSample.Spec.DatabaseNodeSpec.Nodes = 4
databaseSample.Spec.NodeSets = append(databaseSample.Spec.NodeSets, v1alpha1.DatabaseNodeSetSpecInline{
Name: testNodeSetName,
DatabaseNodeSpec: v1alpha1.DatabaseNodeSpec{
Nodes: 1,
Nodes: 4,
},
})

Expand Down Expand Up @@ -154,23 +155,23 @@ var _ = Describe("DatabaseNodeSet controller medium tests", func() {
v1alpha1.AnnotationUpdateStrategyOnDelete: "true",
}

foundDatabase.Spec.NodeSets = append(foundDatabase.Spec.NodeSets, v1alpha1.DatabaseNodeSetSpecInline{
foundDatabase.Spec.NodeSets = []v1alpha1.DatabaseNodeSetSpecInline{{
Name: testNodeSetName + "-labeled",
Labels: map[string]string{
testNodeSetLabel: "true",
},
DatabaseNodeSpec: v1alpha1.DatabaseNodeSpec{
Nodes: 1,
Nodes: 2,
},
})
}}

foundDatabase.Spec.NodeSets = append(foundDatabase.Spec.NodeSets, v1alpha1.DatabaseNodeSetSpecInline{
Name: testNodeSetName + "-annotated",
Annotations: map[string]string{
v1alpha1.AnnotationDataCenter: "envtest",
},
DatabaseNodeSpec: v1alpha1.DatabaseNodeSpec{
Nodes: 1,
Nodes: 2,
},
})

Expand Down
Loading