зеркало из https://github.com/Azure/ARO-RP.git
Merge pull request #1199 from mjudeikis/enrich.cluster.service.principal
Add Cluster Service Principal enrich
This commit is contained in:
Коммит
1bc0164f27
|
@ -107,6 +107,7 @@ func (f *frontend) _putOrPatchOpenShiftCluster(ctx context.Context, r *http.Requ
|
|||
}
|
||||
}
|
||||
|
||||
// If Put or Patch is executed we will enrich document with cluster data.
|
||||
if !isCreate {
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
|
@ -115,6 +116,9 @@ func (f *frontend) _putOrPatchOpenShiftCluster(ctx context.Context, r *http.Requ
|
|||
|
||||
var ext interface{}
|
||||
switch r.Method {
|
||||
// In case of PUT we will take customer request payload and store into database
|
||||
// Our base structure for unmarshal is skeleton document with values we
|
||||
// think is required. We expect payload to have everything else required.
|
||||
case http.MethodPut:
|
||||
ext = converter.ToExternal(&api.OpenShiftCluster{
|
||||
ID: doc.OpenShiftCluster.ID,
|
||||
|
@ -132,6 +136,10 @@ func (f *frontend) _putOrPatchOpenShiftCluster(ctx context.Context, r *http.Requ
|
|||
},
|
||||
})
|
||||
|
||||
// In case of PATCH we take current cluster document, which is enriched
|
||||
// from the cluster and use it as base for unmarshal. So customer can
|
||||
// provide single field json to be updated in the database.
|
||||
// Patch should be used for updating individual fields of the document.
|
||||
case http.MethodPatch:
|
||||
ext = converter.ToExternal(doc.OpenShiftCluster)
|
||||
}
|
||||
|
@ -210,6 +218,8 @@ func (f *frontend) _putOrPatchOpenShiftCluster(ctx context.Context, r *http.Requ
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// We remove sensitive data from document to prevent sensitive data being
|
||||
// returned to the customer.
|
||||
doc.OpenShiftCluster.Properties.ClusterProfile.PullSecret = ""
|
||||
doc.OpenShiftCluster.Properties.ServicePrincipalProfile.ClientSecret = ""
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package clusterdata
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
"github.com/Azure/ARO-RP/pkg/api"
|
||||
)
|
||||
|
||||
func newClusterServicePrincipalEnricherTask(log *logrus.Entry, restConfig *rest.Config, oc *api.OpenShiftCluster) (enricherTask, error) {
|
||||
client, err := kubernetes.NewForConfig(restConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &clusterServicePrincipalEnricherTask{
|
||||
log: log,
|
||||
client: client,
|
||||
oc: oc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type clusterServicePrincipalEnricherTask struct {
|
||||
log *logrus.Entry
|
||||
client kubernetes.Interface
|
||||
oc *api.OpenShiftCluster
|
||||
}
|
||||
|
||||
func (ef *clusterServicePrincipalEnricherTask) FetchData(ctx context.Context, callbacks chan<- func(), errs chan<- error) {
|
||||
secret, err := ef.client.CoreV1().Secrets("kube-system").Get(ctx, "azure-credentials", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
ef.log.Error(err)
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
callbacks <- func() {
|
||||
ef.oc.Properties.ServicePrincipalProfile.ClientID = string(secret.Data["azure_client_id"])
|
||||
ef.oc.Properties.ServicePrincipalProfile.ClientSecret = api.SecureString(secret.Data["azure_client_secret"])
|
||||
}
|
||||
}
|
||||
|
||||
func (ef *clusterServicePrincipalEnricherTask) SetDefaults() {}
|
|
@ -0,0 +1,105 @@
|
|||
package clusterdata
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
"github.com/Azure/ARO-RP/pkg/api"
|
||||
"github.com/Azure/ARO-RP/test/util/cmp"
|
||||
)
|
||||
|
||||
func TestClusterServidePrincipalEnricherTask(t *testing.T) {
|
||||
log := logrus.NewEntry(logrus.StandardLogger())
|
||||
|
||||
name := "azure-credentials"
|
||||
namespace := "kube-system"
|
||||
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
client kubernetes.Interface
|
||||
wantOc *api.OpenShiftCluster
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "enrich worked",
|
||||
client: fake.NewSimpleClientset(&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"azure_client_id": []byte("new-client-id"),
|
||||
"azure_client_secret": []byte("new-client-secret"),
|
||||
},
|
||||
}),
|
||||
wantOc: &api.OpenShiftCluster{
|
||||
Properties: api.OpenShiftClusterProperties{
|
||||
ServicePrincipalProfile: api.ServicePrincipalProfile{
|
||||
ClientID: "new-client-id",
|
||||
ClientSecret: api.SecureString("new-client-secret"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "enrich failed - stale data",
|
||||
client: fake.NewSimpleClientset(),
|
||||
wantOc: &api.OpenShiftCluster{
|
||||
Properties: api.OpenShiftClusterProperties{
|
||||
ServicePrincipalProfile: api.ServicePrincipalProfile{
|
||||
ClientID: "old-client-id",
|
||||
ClientSecret: "old-client-secret",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: "secrets \"azure-credentials\" not found",
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
oc := &api.OpenShiftCluster{
|
||||
Properties: api.OpenShiftClusterProperties{
|
||||
ServicePrincipalProfile: api.ServicePrincipalProfile{
|
||||
ClientID: "old-client-id",
|
||||
ClientSecret: api.SecureString("old-client-secret"),
|
||||
},
|
||||
},
|
||||
}
|
||||
e := &clusterServicePrincipalEnricherTask{
|
||||
log: log,
|
||||
client: tt.client,
|
||||
oc: oc,
|
||||
}
|
||||
e.SetDefaults()
|
||||
|
||||
callbacks := make(chan func())
|
||||
errors := make(chan error)
|
||||
go e.FetchData(context.Background(), callbacks, errors)
|
||||
|
||||
select {
|
||||
case f := <-callbacks:
|
||||
f()
|
||||
if !reflect.DeepEqual(oc, tt.wantOc) {
|
||||
t.Error(cmp.Diff(oc, tt.wantOc))
|
||||
}
|
||||
case err := <-errors:
|
||||
if tt.wantErr != err.Error() {
|
||||
t.Error(err)
|
||||
}
|
||||
// we want to make sure we see stale database data in case of failures
|
||||
if !reflect.DeepEqual(oc, tt.wantOc) {
|
||||
t.Error(cmp.Diff(oc, tt.wantOc))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -43,6 +43,7 @@ func NewBestEffortEnricher(log *logrus.Entry, dialer proxy.Dialer, m metrics.Int
|
|||
taskConstructors: []enricherTaskConstructor{
|
||||
newClusterVersionEnricherTask,
|
||||
newWorkerProfilesEnricherTask,
|
||||
newClusterServicePrincipalEnricherTask,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче