Skip to content

Commit b6b5275

Browse files
authored
[Feature] [Platform] Registry Secret (#1982)
1 parent b133c25 commit b6b5275

File tree

17 files changed

+200
-33
lines changed

17 files changed

+200
-33
lines changed

.golangci.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ linters-settings:
3333
importas:
3434
no-unaliased: true
3535
alias:
36+
- alias: lmanager
37+
pkg: github.com/arangodb/kube-arangodb/pkg/license_manager
3638
- alias: pbImplMetaV1
3739
pkg: github.com/arangodb/kube-arangodb/integrations/meta/v1
3840
- alias: pbMetaV1

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- (Feature) Simplify Operator ID Process
1212
- (Feature) (License) Activation API Integration
1313
- (Feature) (Platform) Chart & Service Kubernetes Events
14+
- (Feature) (Platform) Registry Secret
1415

1516
## [1.3.1](https://github.com/arangodb/kube-arangodb/tree/1.3.1) (2025-10-07)
1617
- (Documentation) Add ArangoPlatformStorage Docs & Examples

pkg/apis/deployment/v1/deployment_status_license.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ type DeploymentStatusLicense struct {
3030
// Hash Defines the License Hash
3131
Hash string `json:"hash,omitempty"`
3232

33+
// InputHash Defines the Input License Hash
34+
InputHash string `json:"inputHash,omitempty"`
35+
3336
// Expires Defines the expiration time of the License
3437
Expires meta.Time `json:"expires,omitempty"`
3538

pkg/apis/deployment/v2alpha1/deployment_status_license.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ type DeploymentStatusLicense struct {
3030
// Hash Defines the License Hash
3131
Hash string `json:"hash,omitempty"`
3232

33+
// InputHash Defines the Input License Hash
34+
InputHash string `json:"inputHash,omitempty"`
35+
3336
// Expires Defines the expiration time of the License
3437
Expires meta.Time `json:"expires,omitempty"`
3538

pkg/deployment/pod/encryption.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ func GetEncryptionFolderSecretName(name string) string {
108108
return n
109109
}
110110

111+
// GetLicenseRegistryCredentialsSecretName returns the secret name for storing registry credentials used to pull licensed images
112+
func GetLicenseRegistryCredentialsSecretName(name string) string {
113+
n := fmt.Sprintf("%s-rlm", name)
114+
115+
return n
116+
}
117+
111118
func IsEncryptionEnabled(i Input) bool {
112119
return i.Deployment.RocksDB.IsEncrypted()
113120
}

pkg/deployment/reconcile/action_license_generate.go

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,15 @@ import (
3232

3333
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
3434
"github.com/arangodb/kube-arangodb/pkg/deployment/client"
35-
"github.com/arangodb/kube-arangodb/pkg/license_manager"
35+
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
36+
lmanager "github.com/arangodb/kube-arangodb/pkg/license_manager"
3637
"github.com/arangodb/kube-arangodb/pkg/platform/inventory"
3738
"github.com/arangodb/kube-arangodb/pkg/util"
39+
utilConstants "github.com/arangodb/kube-arangodb/pkg/util/constants"
3840
"github.com/arangodb/kube-arangodb/pkg/util/globals"
3941
ugrpc "github.com/arangodb/kube-arangodb/pkg/util/grpc"
4042
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
43+
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/patcher"
4144
)
4245

4346
func newLicenseGenerateAction(action api.Action, actionCtx ActionContext) Action {
@@ -84,7 +87,7 @@ func (a *actionLicenseGenerate) Start(ctx context.Context) (bool, error) {
8487
return true, nil
8588
}
8689

87-
var req license_manager.LicenseRequest
90+
var req lmanager.LicenseRequest
8891
did, err := inventory.ExtractDeploymentID(ctx, c.Connection())
8992
if err != nil {
9093
a.log.Err(err).Error("Unable to get deployment id")
@@ -112,7 +115,7 @@ func (a *actionLicenseGenerate) Start(ctx context.Context) (bool, error) {
112115
req.TTL = util.NewType(ugrpc.NewObject(durationpb.New(q.Duration)))
113116
}
114117

115-
lm, err := license_manager.NewClient(license_manager.ArangoLicenseManagerEndpoint, l.API.ClientID, l.API.ClientSecret)
118+
lm, err := lmanager.NewClient(lmanager.ArangoLicenseManagerEndpoint, l.API.ClientID, l.API.ClientSecret)
116119
if err != nil {
117120
a.log.Err(err).Error("Unable to create inventory client")
118121
return true, nil
@@ -167,13 +170,60 @@ func (a *actionLicenseGenerate) Start(ctx context.Context) (bool, error) {
167170
expires = time.Now().Add(time.Duration(math.Round(float64(time.Until(license.Expires())) * api.LicenseExpirationGraceRatio)))
168171
}
169172

173+
cache := a.actionCtx.ACS().CurrentClusterCache()
174+
175+
if s, ok := cache.Secret().V1().GetSimple(pod.GetLicenseRegistryCredentialsSecretName(a.actionCtx.GetName())); ok {
176+
if string(util.Optional(s.Data, utilConstants.ChecksumKey, []byte{})) != l.API.Hash() {
177+
// Update
178+
179+
token, err := lm.RegistryConfig(ctx, lmanager.ArangoLicenseManagerEndpoint, l.API.ClientID, &l.API.ClientSecret, lmanager.StageDev, lmanager.StageQA, lmanager.StagePrd)
180+
if err != nil {
181+
a.log.Err(err).Debug("Failed to generate License Registry")
182+
return true, nil
183+
}
184+
185+
if _, _, err := patcher.Patcher[*core.Secret](ctx, cache.Client().Kubernetes().CoreV1().Secrets(a.actionCtx.GetNamespace()), s, meta.PatchOptions{},
186+
patcher.PatchSecretData(map[string][]byte{
187+
core.DockerConfigJsonKey: token,
188+
utilConstants.ChecksumKey: []byte(l.API.Hash()),
189+
})); err != nil {
190+
a.log.Err(err).Debug("Failed to patch License Secret")
191+
return true, nil
192+
}
193+
}
194+
} else {
195+
token, err := lm.RegistryConfig(ctx, lmanager.ArangoLicenseManagerEndpoint, l.API.ClientID, &l.API.ClientSecret, lmanager.StageDev, lmanager.StageQA, lmanager.StagePrd)
196+
if err != nil {
197+
a.log.Err(err).Debug("Failed to generate License Registry")
198+
return true, nil
199+
}
200+
201+
if _, err := cache.Client().Kubernetes().CoreV1().Secrets(a.actionCtx.GetNamespace()).Create(ctx, &core.Secret{
202+
ObjectMeta: meta.ObjectMeta{
203+
Name: pod.GetLicenseRegistryCredentialsSecretName(a.actionCtx.GetName()),
204+
OwnerReferences: []meta.OwnerReference{
205+
a.actionCtx.GetAPIObject().AsOwner(),
206+
},
207+
},
208+
Data: map[string][]byte{
209+
core.DockerConfigJsonKey: token,
210+
utilConstants.ChecksumKey: []byte(l.API.Hash()),
211+
},
212+
Type: core.SecretTypeDockerConfigJson,
213+
}, meta.CreateOptions{}); err != nil {
214+
a.log.Err(err).Debug("Failed to create License Secret")
215+
return true, nil
216+
}
217+
}
218+
170219
if err := a.actionCtx.WithStatusUpdate(ctx, func(s *api.DeploymentStatus) bool {
171220
s.License = &api.DeploymentStatusLicense{
172221
ID: generatedLicense.ID,
173222
Hash: license.Hash,
174223
Expires: meta.Time{Time: license.Expires()},
175224
Mode: api.LicenseModeAPI,
176225
Regenerate: meta.Time{Time: expires},
226+
InputHash: l.API.Hash(),
177227
}
178228
return true
179229
}); err != nil {

pkg/deployment/reconcile/action_license_set.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,10 @@ func (a *actionLicenseSet) Start(ctx context.Context) (bool, error) {
9090

9191
if err := a.actionCtx.WithStatusUpdate(ctx, func(s *api.DeploymentStatus) bool {
9292
s.License = &api.DeploymentStatusLicense{
93-
Hash: license.Hash,
94-
Expires: meta.Time{Time: license.Expires()},
95-
Mode: api.LicenseModeKey,
93+
Hash: license.Hash,
94+
Expires: meta.Time{Time: license.Expires()},
95+
Mode: api.LicenseModeKey,
96+
InputHash: l.V2.V2Hash(),
9697
}
9798
return true
9899
}); err != nil {

pkg/deployment/reconcile/plan_builder_license.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ import (
2727
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
2828
"github.com/arangodb/kube-arangodb/pkg/deployment/actions"
2929
"github.com/arangodb/kube-arangodb/pkg/deployment/client"
30+
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
3031
sharedReconcile "github.com/arangodb/kube-arangodb/pkg/deployment/reconcile/shared"
32+
"github.com/arangodb/kube-arangodb/pkg/util"
3133
"github.com/arangodb/kube-arangodb/pkg/util/arangod"
34+
utilConstants "github.com/arangodb/kube-arangodb/pkg/util/constants"
3235
"github.com/arangodb/kube-arangodb/pkg/util/errors"
3336
"github.com/arangodb/kube-arangodb/pkg/util/globals"
3437
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
@@ -165,7 +168,7 @@ func (r *Reconciler) updateClusterLicenseKey(ctx context.Context, spec api.Deplo
165168
return nil
166169
}
167170

168-
if status.License.Hash != license.Hash {
171+
if status.License.Hash != license.Hash || status.License.InputHash != l.V2.V2Hash() {
169172
return api.Plan{actions.NewClusterAction(api.ActionTypeLicenseClean, "Removing license reference - Invalid Hash")}
170173
}
171174

@@ -223,6 +226,11 @@ func (r *Reconciler) updateClusterLicenseAPI(ctx context.Context, spec api.Deplo
223226
return nil
224227
}
225228

229+
if status.License.InputHash != l.API.Hash() {
230+
// Invalid hash, cleanup
231+
return api.Plan{actions.NewClusterAction(api.ActionTypeLicenseClean, "Removing license reference - Invalid Input")}
232+
}
233+
226234
if currentLicense.Hash != status.License.Hash {
227235
// Invalid hash, cleanup
228236
return api.Plan{actions.NewClusterAction(api.ActionTypeLicenseClean, "Removing license reference - Invalid Hash")}
@@ -232,5 +240,15 @@ func (r *Reconciler) updateClusterLicenseAPI(ctx context.Context, spec api.Deplo
232240
return api.Plan{actions.NewClusterAction(api.ActionTypeLicenseClean, "Removing license reference - Regeneration Required")}
233241
}
234242

243+
cache := r.context.ACS().CurrentClusterCache()
244+
245+
if s, ok := cache.Secret().V1().GetSimple(pod.GetLicenseRegistryCredentialsSecretName(r.context.GetName())); ok {
246+
if string(util.Optional(s.Data, utilConstants.ChecksumKey, []byte{})) != l.API.Hash() {
247+
return api.Plan{actions.NewClusterAction(api.ActionTypeLicenseClean, "Removing license reference - Registry Change Required")}
248+
}
249+
} else {
250+
return api.Plan{actions.NewClusterAction(api.ActionTypeLicenseClean, "Removing license reference - Registry Change Required")}
251+
}
252+
235253
return nil
236254
}

pkg/deployment/resources/arango_profiles.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
schedulerPodResourcesApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1/pod/resources"
4040
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
4141
"github.com/arangodb/kube-arangodb/pkg/deployment/patch"
42+
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
4243
integrationsSidecar "github.com/arangodb/kube-arangodb/pkg/integrations/sidecar"
4344
"github.com/arangodb/kube-arangodb/pkg/metrics"
4445
"github.com/arangodb/kube-arangodb/pkg/util"
@@ -190,6 +191,7 @@ func (r *Resources) EnsureArangoProfiles(ctx context.Context, cachedStatus inspe
190191
r.arangoDeploymentCATemplate(),
191192
r.templateKubernetesEnvs(),
192193
r.templateResourceEnvs(),
194+
r.templateImagePullSecrets(),
193195
)
194196
if err != nil {
195197
return "", nil, err
@@ -361,6 +363,22 @@ func (r *Resources) templateKubernetesEnvs() *schedulerApi.ProfileTemplate {
361363
}
362364
}
363365

366+
func (r *Resources) templateImagePullSecrets() *schedulerApi.ProfileTemplate {
367+
if _, ok := r.context.ACS().CurrentClusterCache().Secret().V1().GetSimple(pod.GetLicenseRegistryCredentialsSecretName(r.name)); ok {
368+
return &schedulerApi.ProfileTemplate{
369+
Pod: &schedulerPodApi.Pod{
370+
Image: &schedulerPodResourcesApi.Image{
371+
ImagePullSecrets: []string{
372+
pod.GetLicenseRegistryCredentialsSecretName(r.name),
373+
},
374+
},
375+
},
376+
}
377+
}
378+
379+
return &schedulerApi.ProfileTemplate{}
380+
}
381+
364382
func (r *Resources) templateResourceEnvs() *schedulerApi.ProfileTemplate {
365383
return &schedulerApi.ProfileTemplate{
366384
Container: &schedulerApi.ProfileContainerTemplate{

pkg/license_manager/client.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package license_manager
2222

2323
import (
2424
"context"
25+
"encoding/json"
2526
"fmt"
2627
goHttp "net/http"
2728

@@ -76,6 +77,7 @@ type Client interface {
7677
License(ctx context.Context, req LicenseRequest) (LicenseResponse, error)
7778

7879
Registry(ctx context.Context) (RegistryResponse, error)
80+
RegistryConfig(ctx context.Context, endpoint, id string, token *string, stages ...Stage) ([]byte, error)
7981
}
8082

8183
type LicenseRequest struct {
@@ -98,6 +100,32 @@ type client struct {
98100
conn driver.Connection
99101
}
100102

103+
func (c client) RegistryConfig(ctx context.Context, endpoint, id string, token *string, stages ...Stage) ([]byte, error) {
104+
var t string
105+
106+
if token != nil {
107+
t = *token
108+
} else {
109+
tk, err := c.Registry(ctx)
110+
if err != nil {
111+
return nil, err
112+
}
113+
t = tk.Token
114+
}
115+
116+
r, err := NewRegistryAuth(endpoint, id, t, stages...)
117+
if err != nil {
118+
return nil, err
119+
}
120+
121+
data, err := json.Marshal(r)
122+
if err != nil {
123+
return nil, err
124+
}
125+
126+
return data, nil
127+
}
128+
101129
func (c client) License(ctx context.Context, req LicenseRequest) (LicenseResponse, error) {
102130
return arangod.PostRequest[LicenseRequest, LicenseResponse](ctx, c.conn, req, "_api", "v1", "license").AcceptCode(200).Response()
103131
}

0 commit comments

Comments
 (0)