Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support license #709

Merged
merged 10 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions apis/risingwave/v1alpha1/risingwave_license.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2024 RisingWave Labs
//
// 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.

package v1alpha1

// RisingWaveLicense is the license configuration for RisingWave.
type RisingWaveLicense struct {
// SecretName that contains the license. The license must be JWT formatted JSON.
// +optional
SecretName string `json:"secretName,omitempty"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mark it a required field.

Suggested change
SecretName string `json:"secretName,omitempty"`
SecretName string `json:"secretName"`

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also clarify the secret key that will be used.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mark it a required field.

Can you explain the motivation? I learned from

SecretName string `json:"secretName,omitempty"`

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably makes the semantic more clear. The example you quoted seems untuned 😄

Currently,

# valid but has no effect
spec:
  license:
    secretName: ""
# valid and effective
spec:
  license:
    secretName: "abc"
# valid and won't be misunderstood
spec:
  # no license field

After change, the k8s API service will reject

# no longer valid
spec:
  license:
    secretName: ""

Copy link
Member Author

@fuyufjh fuyufjh Sep 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either LGTM, but I'd like to keep it consistent with TLS config (RisingWaveTLSConfiguration). Do you think we need to change it as well?

}
3 changes: 3 additions & 0 deletions apis/risingwave/v1alpha1/risingwave_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ type RisingWaveSpec struct {
// This is only for backward compatibility and will be deprecated in the future.
// +kubebuilder:default=0
StandaloneMode int32 `json:"standaloneMode,omitempty"`

// License to enable paid features of RisingWave.
License *RisingWaveLicense `json:"license,omitempty"`
}

// ComponentGroupReplicasStatus are the running status of Pods in group.
Expand Down
20 changes: 20 additions & 0 deletions apis/risingwave/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -30323,6 +30323,14 @@ spec:
image:
description: Image for RisingWave component.
type: string
license:
description: License to enable paid features of RisingWave.
properties:
secretName:
description: SecretName that contains the license. The license
must be JWT formatted JSON.
type: string
type: object
metaStore:
default:
memory: true
Expand Down
8 changes: 8 additions & 0 deletions config/risingwave-operator-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30340,6 +30340,14 @@ spec:
image:
description: Image for RisingWave component.
type: string
license:
description: License to enable paid features of RisingWave.
properties:
secretName:
description: SecretName that contains the license. The license
must be JWT formatted JSON.
type: string
type: object
metaStore:
default:
memory: true
Expand Down
8 changes: 8 additions & 0 deletions config/risingwave-operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30340,6 +30340,14 @@ spec:
image:
description: Image for RisingWave component.
type: string
license:
description: License to enable paid features of RisingWave.
properties:
secretName:
description: SecretName that contains the license. The license
must be JWT formatted JSON.
type: string
type: object
metaStore:
default:
memory: true
Expand Down
56 changes: 56 additions & 0 deletions docs/general/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,19 @@ int32
This is only for backward compatibility and will be deprecated in the future.</p>
</td>
</tr>
<tr>
<td>
<code>license</code><br/>
<em>
<a href="#risingwave.risingwavelabs.com/v1alpha1.RisingWaveLicense">
RisingWaveLicense
</a>
</em>
</td>
<td>
<p>License to enable paid features of RisingWave.</p>
</td>
</tr>
</table>
</td>
</tr>
Expand Down Expand Up @@ -1582,6 +1595,36 @@ should not be updated in most cases.</p>
</tr>
</tbody>
</table>
<h3 id="risingwave.risingwavelabs.com/v1alpha1.RisingWaveLicense">RisingWaveLicense
</h3>
<p>
(<em>Appears on:</em><a href="#risingwave.risingwavelabs.com/v1alpha1.RisingWaveSpec">RisingWaveSpec</a>)
</p>
<div>
<p>RisingWaveLicense is the license configuration for RisingWave.</p>
</div>
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>secretName</code><br/>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>SecretName that contains the license. The license must be JWT formatted JSON.</p>
</td>
</tr>
</tbody>
</table>
<h3 id="risingwave.risingwavelabs.com/v1alpha1.RisingWaveMetaStoreBackend">RisingWaveMetaStoreBackend
</h3>
<p>
Expand Down Expand Up @@ -4652,6 +4695,19 @@ int32
This is only for backward compatibility and will be deprecated in the future.</p>
</td>
</tr>
<tr>
<td>
<code>license</code><br/>
<em>
<a href="#risingwave.risingwavelabs.com/v1alpha1.RisingWaveLicense">
RisingWaveLicense
</a>
</em>
</td>
<td>
<p>License to enable paid features of RisingWave.</p>
</td>
</tr>
</tbody>
</table>
<h3 id="risingwave.risingwavelabs.com/v1alpha1.RisingWaveStandaloneComponent">RisingWaveStandaloneComponent
Expand Down
1 change: 1 addition & 0 deletions pkg/factory/envs/risingwave.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const (
RWTotalMemoryBytes = "RW_TOTAL_MEMORY_BYTES"
RWSslCert = "RW_SSL_CERT"
RWSslKey = "RW_SSL_KEY"
RWLicense = "RW_LICENSE"
)

// MinIO.
Expand Down
22 changes: 22 additions & 0 deletions pkg/factory/risingwave_object_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,26 @@ func (f *RisingWaveObjectFactory) getDataDirectory() string {
return path.Join(rootPath, stateStore.DataDirectory)
}

func (f *RisingWaveObjectFactory) envsForLicense() []corev1.EnvVar {
license := f.risingwave.Spec.License
if license != nil && license.SecretName != "" {
return []corev1.EnvVar{
{
Name: envs.RWLicense,
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: license.SecretName,
},
Key: corev1.LicenseKey,
},
fuyufjh marked this conversation as resolved.
Show resolved Hide resolved
},
},
}
}
return nil
}

func (f *RisingWaveObjectFactory) coreEnvsForMeta(image string) []corev1.EnvVar {
metaStore := &f.risingwave.Spec.MetaStore
version := utils.GetVersionFromImage(image)
Expand Down Expand Up @@ -635,6 +655,8 @@ func (f *RisingWaveObjectFactory) coreEnvsForMeta(image string) []corev1.EnvVar
panic("unsupported meta storage type")
}

envVars = append(envVars, f.envsForLicense()...)
arkbriar marked this conversation as resolved.
Show resolved Hide resolved

return envVars
}

Expand Down
35 changes: 35 additions & 0 deletions pkg/factory/risingwave_object_factory_predicate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1040,3 +1040,38 @@ func tlsPredicates() []predicate[*corev1.PodTemplateSpec, tlsTestcase] {
},
}
}

func licensePredicates() []predicate[*corev1.PodTemplateSpec, licenseTestCase] {
return []predicate[*corev1.PodTemplateSpec, licenseTestCase]{
{
Name: "envs-contain",
Fn: func(obj *corev1.PodTemplateSpec, testcase licenseTestCase) bool {
if len(testcase.expectedEnvs) == 0 {
return true
}
if len(obj.Spec.Containers) == 0 {
return false
}
envs := obj.Spec.Containers[0].Env
// Contains all expected envs.
return listContainsByKey(envs, testcase.expectedEnvs, func(t *corev1.EnvVar) string { return t.Name }, deepEqual[corev1.EnvVar])
},
},
{
Name: "envs-not-contain",
Fn: func(obj *corev1.PodTemplateSpec, testcase licenseTestCase) bool {
if len(testcase.unexpectedEnvs) == 0 {
return true
}
if len(obj.Spec.Containers) == 0 {
return false
}
envs := obj.Spec.Containers[0].Env
// Contains none of unexpected envs.
return !lo.ContainsBy(envs, func(item corev1.EnvVar) bool {
return lo.Contains(testcase.unexpectedEnvs, item.Name)
})
},
},
}
}
23 changes: 23 additions & 0 deletions pkg/factory/risingwave_object_factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,29 @@ func TestRisingWaveObjectFactory_TlsSupport(t *testing.T) {
}
}

func TestRisingWaveObjectFactory_Lisense(t *testing.T) {
predicates := licensePredicates()

for name, tc := range licenseTestCases() {
t.Run(name, func(t *testing.T) {
factory := NewRisingWaveObjectFactory(newTestRisingwave(func(r *risingwavev1alpha1.RisingWave) {
r.Spec.MetaStore.Memory = ptr.To(true)
r.Spec.StateStore.Memory = ptr.To(true)
r.Spec.EnableStandaloneMode = ptr.To(false)
r.Spec.Components.Meta.NodeGroups = []risingwavev1alpha1.RisingWaveNodeGroup{
{
Name: "",
},
}
r.Spec.License = tc.license
}), testutils.Scheme, "")

template := factory.NewMetaStatefulSet("").Spec.Template
composeAssertions(predicates, t).assertTest(&template, tc)
})
}
}

func TestRisingWaveObjectFactory_DataDirectory(t *testing.T) {
testcases := map[string]struct {
stateStore risingwavev1alpha1.RisingWaveStateStoreBackend
Expand Down
46 changes: 45 additions & 1 deletion pkg/factory/risingwave_object_factory_testcases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ type testCaseType interface {
metaStoreTestCase |
metaStatefulSetTestCase |
metaAdvancedSTSTestCase |
tlsTestcase
tlsTestcase |
licenseTestCase
}

type kubeObject interface {
Expand Down Expand Up @@ -4094,3 +4095,46 @@ func tlsTestcases() map[string]tlsTestcase {
},
}
}

type licenseTestCase struct {
license *risingwavev1alpha1.RisingWaveLicense
expectedEnvs []corev1.EnvVar
unexpectedEnvs []string
}

func licenseTestCases() map[string]licenseTestCase {
return map[string]licenseTestCase{
"no-license": {
license: nil,
unexpectedEnvs: []string{
"RW_LICENSE",
},
},
"empty-license": {
license: &risingwavev1alpha1.RisingWaveLicense{
SecretName: "",
},
unexpectedEnvs: []string{
"RW_LICENSE",
},
},
"with-license": {
license: &risingwavev1alpha1.RisingWaveLicense{
SecretName: "the-license-secret",
},
expectedEnvs: []corev1.EnvVar{
{
Name: "RW_LICENSE",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: "the-license-secret",
},
Key: "license",
},
},
},
},
},
}
}
Loading