add devops credential controller
Signed-off-by: runzexia <runzexia@yunify.com>
This commit is contained in:
56
pkg/apis/devops/v1alpha3/credential_types.go
Normal file
56
pkg/apis/devops/v1alpha3/credential_types.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package v1alpha3
|
||||||
|
|
||||||
|
import v1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
/**
|
||||||
|
We use a special type of secret as a credential for DevOps.
|
||||||
|
This file will not contain CRD, but the credential type constants and their fields.
|
||||||
|
*/
|
||||||
|
const (
|
||||||
|
CredentialFinalizerName = "credential.finalizers.kubesphere.io"
|
||||||
|
DevOpsCredentialPrefix = "credential.devops.kubesphere.io/"
|
||||||
|
// SecretTypeBasicAuth contains data needed for basic authentication.
|
||||||
|
//
|
||||||
|
// Required at least one of fields:
|
||||||
|
// - Secret.Data["username"] - username used for authentication
|
||||||
|
// - Secret.Data["password"] - password or token needed for authentication
|
||||||
|
SecretTypeBasicAuth v1.SecretType = DevOpsCredentialPrefix + "basic-auth"
|
||||||
|
// BasicAuthUsernameKey is the key of the username for SecretTypeBasicAuth secrets
|
||||||
|
BasicAuthUsernameKey = "username"
|
||||||
|
// BasicAuthPasswordKey is the key of the password or token for SecretTypeBasicAuth secrets
|
||||||
|
BasicAuthPasswordKey = "password"
|
||||||
|
|
||||||
|
// SecretTypeSSHAuth contains data needed for ssh authentication.
|
||||||
|
//
|
||||||
|
// Required at least one of fields:
|
||||||
|
// - Secret.Data["username"] - username used for authentication
|
||||||
|
// - Secret.Data["passphrase"] - passphrase needed for authentication
|
||||||
|
// - Secret.Data["privatekey"] - privatekey needed for authentication
|
||||||
|
SecretTypeSSHAuth v1.SecretType = DevOpsCredentialPrefix + "ssh-auth"
|
||||||
|
// SSHAuthUsernameKey is the key of the username for SecretTypeSSHAuth secrets
|
||||||
|
SSHAuthUsernameKey = "username"
|
||||||
|
// SSHAuthPrivateKey is the key of the passphrase for SecretTypeSSHAuth secrets
|
||||||
|
SSHAuthPassphraseKey = "passphrase"
|
||||||
|
// SSHAuthPrivateKey is the key of the privatekey for SecretTypeSSHAuth secrets
|
||||||
|
SSHAuthPrivateKey = "privatekey"
|
||||||
|
|
||||||
|
// SecretTypeSecretText contains data.
|
||||||
|
//
|
||||||
|
// Required at least one of fields:
|
||||||
|
// - Secret.Data["secret"] - secret
|
||||||
|
SecretTypeSecretText v1.SecretType = DevOpsCredentialPrefix + "secret-text"
|
||||||
|
// SecretTextSecretKey is the key of the secret for SecretTypeSecretText secrets
|
||||||
|
SecretTextSecretKey = "secret"
|
||||||
|
|
||||||
|
// SecretTypeKubeConfig contains data.
|
||||||
|
//
|
||||||
|
// Required at least one of fields:
|
||||||
|
// - Secret.Data["secret"] - secret
|
||||||
|
SecretTypeKubeConfig v1.SecretType = DevOpsCredentialPrefix + "kubeconfig"
|
||||||
|
// KubeConfigSecretKey is the key of the secret for SecretTypeKubeConfig secrets
|
||||||
|
KubeConfigSecretKey = "secret"
|
||||||
|
// CredentialAutoSyncAnnoKey is used to indicate whether the secret is automatically synchronized to devops.
|
||||||
|
// In the old version, the credential is stored in jenkins and cannot be obtained.
|
||||||
|
// This field is set to ensure that the secret is not overwritten by a nil value.
|
||||||
|
CredentialAutoSyncAnnoKey = DevOpsCredentialPrefix + "autosync"
|
||||||
|
)
|
||||||
284
pkg/controller/devopscredential/devopscredential_controller.go
Normal file
284
pkg/controller/devopscredential/devopscredential_controller.go
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
package devopscredential
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
corev1informer "k8s.io/client-go/informers/core/v1"
|
||||||
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
|
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
|
corev1lister "k8s.io/client-go/listers/core/v1"
|
||||||
|
"k8s.io/client-go/tools/cache"
|
||||||
|
"k8s.io/client-go/tools/record"
|
||||||
|
"k8s.io/client-go/util/workqueue"
|
||||||
|
"k8s.io/klog"
|
||||||
|
devopsv1alpha3 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
|
||||||
|
kubesphereclient "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
||||||
|
"kubesphere.io/kubesphere/pkg/constants"
|
||||||
|
devopsClient "kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||||
|
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||||
|
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
DevOps project controller is used to maintain the state of the DevOps project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
type Controller struct {
|
||||||
|
client clientset.Interface
|
||||||
|
kubesphereClient kubesphereclient.Interface
|
||||||
|
|
||||||
|
eventBroadcaster record.EventBroadcaster
|
||||||
|
eventRecorder record.EventRecorder
|
||||||
|
|
||||||
|
secretLister corev1lister.SecretLister
|
||||||
|
secretSynced cache.InformerSynced
|
||||||
|
|
||||||
|
namespaceLister corev1lister.NamespaceLister
|
||||||
|
namespaceSynced cache.InformerSynced
|
||||||
|
|
||||||
|
workqueue workqueue.RateLimitingInterface
|
||||||
|
|
||||||
|
workerLoopPeriod time.Duration
|
||||||
|
|
||||||
|
devopsClient devopsClient.Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewController(client clientset.Interface,
|
||||||
|
devopsClinet devopsClient.Interface,
|
||||||
|
namespaceInformer corev1informer.NamespaceInformer,
|
||||||
|
secretInformer corev1informer.SecretInformer) *Controller {
|
||||||
|
|
||||||
|
broadcaster := record.NewBroadcaster()
|
||||||
|
broadcaster.StartLogging(func(format string, args ...interface{}) {
|
||||||
|
klog.Info(fmt.Sprintf(format, args))
|
||||||
|
})
|
||||||
|
broadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: client.CoreV1().Events("")})
|
||||||
|
recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "pipeline-controller"})
|
||||||
|
|
||||||
|
v := &Controller{
|
||||||
|
client: client,
|
||||||
|
devopsClient: devopsClinet,
|
||||||
|
workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "pipeline"),
|
||||||
|
secretLister: secretInformer.Lister(),
|
||||||
|
secretSynced: secretInformer.Informer().HasSynced,
|
||||||
|
namespaceLister: namespaceInformer.Lister(),
|
||||||
|
namespaceSynced: namespaceInformer.Informer().HasSynced,
|
||||||
|
workerLoopPeriod: time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
v.eventBroadcaster = broadcaster
|
||||||
|
v.eventRecorder = recorder
|
||||||
|
|
||||||
|
secretInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||||
|
AddFunc: func(obj interface{}) {
|
||||||
|
secret := obj.(*v1.Secret)
|
||||||
|
if strings.HasPrefix(string(secret.Type), devopsv1alpha3.DevOpsCredentialPrefix) {
|
||||||
|
v.enqueueSecret(obj)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UpdateFunc: func(oldObj, newObj interface{}) {
|
||||||
|
old := oldObj.(*v1.Secret)
|
||||||
|
new := newObj.(*v1.Secret)
|
||||||
|
if old.ResourceVersion == new.ResourceVersion {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(string(new.Type), devopsv1alpha3.DevOpsCredentialPrefix) {
|
||||||
|
v.enqueueSecret(newObj)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
DeleteFunc: func(obj interface{}) {
|
||||||
|
secret := obj.(*v1.Secret)
|
||||||
|
if strings.HasPrefix(string(secret.Type), devopsv1alpha3.DevOpsCredentialPrefix) {
|
||||||
|
v.enqueueSecret(obj)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// enqueueSecret takes a Foo resource and converts it into a namespace/name
|
||||||
|
// string which is then put onto the work workqueue. This method should *not* be
|
||||||
|
// passed resources of any type other than DevOpsProject.
|
||||||
|
func (c *Controller) enqueueSecret(obj interface{}) {
|
||||||
|
var key string
|
||||||
|
var err error
|
||||||
|
if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
|
||||||
|
utilruntime.HandleError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.workqueue.Add(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) processNextWorkItem() bool {
|
||||||
|
obj, shutdown := c.workqueue.Get()
|
||||||
|
|
||||||
|
if shutdown {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
err := func(obj interface{}) error {
|
||||||
|
defer c.workqueue.Done(obj)
|
||||||
|
var key string
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
if key, ok = obj.(string); !ok {
|
||||||
|
c.workqueue.Forget(obj)
|
||||||
|
utilruntime.HandleError(fmt.Errorf("expected string in workqueue but got %#v", obj))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := c.syncHandler(key); err != nil {
|
||||||
|
c.workqueue.AddRateLimited(key)
|
||||||
|
return fmt.Errorf("error syncing '%s': %s, requeuing", key, err.Error())
|
||||||
|
}
|
||||||
|
c.workqueue.Forget(obj)
|
||||||
|
klog.V(5).Infof("Successfully synced '%s'", key)
|
||||||
|
return nil
|
||||||
|
}(obj)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err, "could not reconcile devopsProject")
|
||||||
|
utilruntime.HandleError(err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) worker() {
|
||||||
|
|
||||||
|
for c.processNextWorkItem() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) Start(stopCh <-chan struct{}) error {
|
||||||
|
return c.Run(1, stopCh)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) Run(workers int, stopCh <-chan struct{}) error {
|
||||||
|
defer utilruntime.HandleCrash()
|
||||||
|
defer c.workqueue.ShutDown()
|
||||||
|
|
||||||
|
klog.Info("starting pipeline controller")
|
||||||
|
defer klog.Info("shutting down pipeline controller")
|
||||||
|
|
||||||
|
if !cache.WaitForCacheSync(stopCh, c.secretSynced) {
|
||||||
|
return fmt.Errorf("failed to wait for caches to sync")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < workers; i++ {
|
||||||
|
go wait.Until(c.worker, c.workerLoopPeriod, stopCh)
|
||||||
|
}
|
||||||
|
|
||||||
|
<-stopCh
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// syncHandler compares the actual state with the desired, and attempts to
|
||||||
|
// converge the two. It then updates the Status block of the pipeline resource
|
||||||
|
// with the current status of the resource.
|
||||||
|
func (c *Controller) syncHandler(key string) error {
|
||||||
|
nsName, name, err := cache.SplitMetaNamespaceKey(key)
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err, fmt.Sprintf("could not split copySecret meta %s ", key))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
namespace, err := c.namespaceLister.Get(nsName)
|
||||||
|
if err != nil {
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
klog.Info(fmt.Sprintf("namespace '%s' in work queue no longer exists ", key))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
klog.Error(err, fmt.Sprintf("could not get namespace %s ", key))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !isDevOpsProjectAdminNamespace(namespace) {
|
||||||
|
err := fmt.Errorf("cound not create credential in normal namespaces %s", namespace.Name)
|
||||||
|
klog.Warning(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
secret, err := c.secretLister.Secrets(nsName).Get(name)
|
||||||
|
if err != nil {
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
klog.Info(fmt.Sprintf("secret '%s' in work queue no longer exists ", key))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
klog.Error(err, fmt.Sprintf("could not get secret %s ", key))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
copySecret := secret.DeepCopy()
|
||||||
|
// DeletionTimestamp.IsZero() means copySecret has not been deleted.
|
||||||
|
if copySecret.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||||
|
// https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#finalizers
|
||||||
|
if !sliceutil.HasString(copySecret.ObjectMeta.Finalizers, devopsv1alpha3.CredentialFinalizerName) {
|
||||||
|
copySecret.ObjectMeta.Finalizers = append(copySecret.ObjectMeta.Finalizers, devopsv1alpha3.CredentialFinalizerName)
|
||||||
|
}
|
||||||
|
// Check secret config exists, otherwise we will create it.
|
||||||
|
// if secret exists, update config
|
||||||
|
_, err := c.devopsClient.GetCredentialInProject(nsName, secret.Name)
|
||||||
|
if err != nil && devopsClient.GetDevOpsStatusCode(err) != http.StatusNotFound {
|
||||||
|
klog.Error(err, fmt.Sprintf("failed to get secret %s ", key))
|
||||||
|
return err
|
||||||
|
} else if err != nil {
|
||||||
|
_, err := c.devopsClient.CreateCredentialInProject(nsName, copySecret)
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err, fmt.Sprintf("failed to create secret %s ", key))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, ok := copySecret.Annotations[devopsv1alpha3.CredentialAutoSyncAnnoKey]; ok {
|
||||||
|
_, err := c.devopsClient.UpdateCredentialInProject(nsName, copySecret)
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err, fmt.Sprintf("failed to update secret %s ", key))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Finalizers processing logic
|
||||||
|
if sliceutil.HasString(copySecret.ObjectMeta.Finalizers, devopsv1alpha3.CredentialFinalizerName) {
|
||||||
|
_, err := c.devopsClient.GetCredentialInProject(nsName, secret.Name)
|
||||||
|
if err != nil && devopsClient.GetDevOpsStatusCode(err) != http.StatusNotFound {
|
||||||
|
klog.Error(err, fmt.Sprintf("failed to get secret %s ", key))
|
||||||
|
return err
|
||||||
|
} else if err != nil && devopsClient.GetDevOpsStatusCode(err) == http.StatusNotFound {
|
||||||
|
} else {
|
||||||
|
if _, err := c.devopsClient.DeleteCredentialInProject(nsName, secret.Name); err != nil {
|
||||||
|
klog.Error(err, fmt.Sprintf("failed to delete secret %s in devops", key))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
copySecret.ObjectMeta.Finalizers = sliceutil.RemoveString(copySecret.ObjectMeta.Finalizers, func(item string) bool {
|
||||||
|
return item == devopsv1alpha3.CredentialFinalizerName
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(secret, copySecret) {
|
||||||
|
_, err = c.client.CoreV1().Secrets(nsName).Update(copySecret)
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err, fmt.Sprintf("failed to update secret %s ", key))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDevOpsProjectAdminNamespace(namespace *v1.Namespace) bool {
|
||||||
|
_, ok := namespace.Labels[constants.DevOpsProjectLabelKey]
|
||||||
|
|
||||||
|
return ok && k8sutil.IsControlledBy(namespace.OwnerReferences,
|
||||||
|
devopsv1alpha3.ResourceKindDevOpsProject, "")
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,410 @@
|
|||||||
|
package devopscredential
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"kubesphere.io/kubesphere/pkg/constants"
|
||||||
|
fakeDevOps "kubesphere.io/kubesphere/pkg/simple/client/devops/fake"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/util/diff"
|
||||||
|
kubeinformers "k8s.io/client-go/informers"
|
||||||
|
k8sfake "k8s.io/client-go/kubernetes/fake"
|
||||||
|
core "k8s.io/client-go/testing"
|
||||||
|
"k8s.io/client-go/tools/cache"
|
||||||
|
"k8s.io/client-go/tools/record"
|
||||||
|
devops "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
alwaysReady = func() bool { return true }
|
||||||
|
noResyncPeriodFunc = func() time.Duration { return 0 }
|
||||||
|
)
|
||||||
|
|
||||||
|
type fixture struct {
|
||||||
|
t *testing.T
|
||||||
|
|
||||||
|
kubeclient *k8sfake.Clientset
|
||||||
|
namespaceLister []*v1.Namespace
|
||||||
|
secretLister []*v1.Secret
|
||||||
|
kubeactions []core.Action
|
||||||
|
|
||||||
|
kubeobjects []runtime.Object
|
||||||
|
// Objects from here preloaded into NewSimpleFake.
|
||||||
|
objects []runtime.Object
|
||||||
|
// Objects from here preloaded into devops
|
||||||
|
initDevOpsProject string
|
||||||
|
initCredential []*v1.Secret
|
||||||
|
expectCredential []*v1.Secret
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFixture(t *testing.T) *fixture {
|
||||||
|
f := &fixture{}
|
||||||
|
f.t = t
|
||||||
|
f.objects = []runtime.Object{}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNamespace(name string, projectName string) *v1.Namespace {
|
||||||
|
ns := &v1.Namespace{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "Namespace",
|
||||||
|
APIVersion: v1.SchemeGroupVersion.String(),
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Labels: map[string]string{constants.DevOpsProjectLabelKey: projectName},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
TRUE := true
|
||||||
|
ns.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
|
||||||
|
{
|
||||||
|
APIVersion: devops.SchemeGroupVersion.String(),
|
||||||
|
Kind: devops.ResourceKindDevOpsProject,
|
||||||
|
Name: projectName,
|
||||||
|
BlockOwnerDeletion: &TRUE,
|
||||||
|
Controller: &TRUE,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return ns
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSecret(namespace, name string, data map[string][]byte, withFinalizers bool, autoSync bool) *v1.Secret {
|
||||||
|
secret := &v1.Secret{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: devops.ResourceKindPipeline,
|
||||||
|
APIVersion: devops.SchemeGroupVersion.String(),
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
Data: data,
|
||||||
|
Type: devops.DevOpsCredentialPrefix + "test",
|
||||||
|
}
|
||||||
|
if withFinalizers {
|
||||||
|
secret.Finalizers = append(secret.Finalizers, devops.CredentialFinalizerName)
|
||||||
|
}
|
||||||
|
if autoSync{
|
||||||
|
if secret.Annotations == nil{
|
||||||
|
secret.Annotations = map[string]string{}
|
||||||
|
}
|
||||||
|
secret.Annotations[devops.CredentialAutoSyncAnnoKey] = "true"
|
||||||
|
}
|
||||||
|
return secret
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDeletingSecret(namespace, name string) *v1.Secret {
|
||||||
|
now := metav1.Now()
|
||||||
|
pipeline := &v1.Secret{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: devops.ResourceKindPipeline,
|
||||||
|
APIVersion: devops.SchemeGroupVersion.String(),
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
|
DeletionTimestamp: &now,
|
||||||
|
},
|
||||||
|
Type: devops.DevOpsCredentialPrefix + "test",
|
||||||
|
}
|
||||||
|
pipeline.Finalizers = append(pipeline.Finalizers, devops.CredentialFinalizerName)
|
||||||
|
|
||||||
|
return pipeline
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fixture) newController() (*Controller, kubeinformers.SharedInformerFactory, *fakeDevOps.Devops) {
|
||||||
|
f.kubeclient = k8sfake.NewSimpleClientset(f.kubeobjects...)
|
||||||
|
|
||||||
|
k8sI := kubeinformers.NewSharedInformerFactory(f.kubeclient, noResyncPeriodFunc())
|
||||||
|
dI := fakeDevOps.NewWithCredentials(f.initDevOpsProject, f.initCredential...)
|
||||||
|
|
||||||
|
c := NewController(f.kubeclient, dI, k8sI.Core().V1().Namespaces(),
|
||||||
|
k8sI.Core().V1().Secrets())
|
||||||
|
|
||||||
|
c.secretSynced = alwaysReady
|
||||||
|
c.eventRecorder = &record.FakeRecorder{}
|
||||||
|
|
||||||
|
for _, f := range f.secretLister {
|
||||||
|
k8sI.Core().V1().Secrets().Informer().GetIndexer().Add(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range f.namespaceLister {
|
||||||
|
k8sI.Core().V1().Namespaces().Informer().GetIndexer().Add(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, k8sI, dI
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fixture) run(fooName string) {
|
||||||
|
f.runController(fooName, true, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fixture) runExpectError(fooName string) {
|
||||||
|
f.runController(fooName, true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fixture) runController(name string, startInformers bool, expectError bool) {
|
||||||
|
c, k8sI, dI := f.newController()
|
||||||
|
if startInformers {
|
||||||
|
stopCh := make(chan struct{})
|
||||||
|
defer close(stopCh)
|
||||||
|
k8sI.Start(stopCh)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.syncHandler(name)
|
||||||
|
if !expectError && err != nil {
|
||||||
|
f.t.Errorf("error syncing foo: %v", err)
|
||||||
|
} else if expectError && err == nil {
|
||||||
|
f.t.Error("expected error syncing foo, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
k8sActions := filterInformerActions(f.kubeclient.Actions())
|
||||||
|
for i, action := range k8sActions {
|
||||||
|
if len(f.kubeactions) < i+1 {
|
||||||
|
f.t.Errorf("%d unexpected actions: %+v", len(k8sActions)-len(f.kubeactions), k8sActions[i:])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedAction := f.kubeactions[i]
|
||||||
|
checkAction(expectedAction, action, f.t)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(f.kubeactions) > len(k8sActions) {
|
||||||
|
f.t.Errorf("%d additional expected actions:%+v", len(f.kubeactions)-len(k8sActions), f.kubeactions[len(k8sActions):])
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dI.Credentials[f.initDevOpsProject]) != len(f.expectCredential) {
|
||||||
|
f.t.Errorf(" unexpected objects: %v", dI.Projects)
|
||||||
|
}
|
||||||
|
for _, credential := range f.expectCredential {
|
||||||
|
actualCredential := dI.Credentials[f.initDevOpsProject][credential.Name]
|
||||||
|
if !reflect.DeepEqual(actualCredential, credential) {
|
||||||
|
f.t.Errorf(" credential %+v not match \n %+v", credential, actualCredential)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkAction verifies that expected and actual actions are equal and both have
|
||||||
|
// same attached resources
|
||||||
|
func checkAction(expected, actual core.Action, t *testing.T) {
|
||||||
|
if !(expected.Matches(actual.GetVerb(), actual.GetResource().Resource) && actual.GetSubresource() == expected.GetSubresource()) {
|
||||||
|
t.Errorf("Expected\n\t%#v\ngot\n\t%#v", expected, actual)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if reflect.TypeOf(actual) != reflect.TypeOf(expected) {
|
||||||
|
t.Errorf("Action has wrong type. Expected: %t. Got: %t", expected, actual)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch a := actual.(type) {
|
||||||
|
case core.CreateActionImpl:
|
||||||
|
e, _ := expected.(core.CreateActionImpl)
|
||||||
|
expObject := e.GetObject()
|
||||||
|
object := a.GetObject()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expObject, object) {
|
||||||
|
t.Errorf("Action %s %s has wrong object\nDiff:\n %s",
|
||||||
|
a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintSideBySide(expObject, object))
|
||||||
|
}
|
||||||
|
case core.UpdateActionImpl:
|
||||||
|
e, _ := expected.(core.UpdateActionImpl)
|
||||||
|
expObject := e.GetObject()
|
||||||
|
object := a.GetObject()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expObject, object) {
|
||||||
|
t.Errorf("Action %s %s has wrong object\nDiff:\n %s",
|
||||||
|
a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintSideBySide(expObject, object))
|
||||||
|
}
|
||||||
|
case core.PatchActionImpl:
|
||||||
|
e, _ := expected.(core.PatchActionImpl)
|
||||||
|
expPatch := e.GetPatch()
|
||||||
|
patch := a.GetPatch()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expPatch, patch) {
|
||||||
|
t.Errorf("Action %s %s has wrong patch\nDiff:\n %s",
|
||||||
|
a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintSideBySide(expPatch, patch))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Errorf("Uncaptured Action %s %s, you should explicitly add a case to capture it",
|
||||||
|
actual.GetVerb(), actual.GetResource().Resource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// filterInformerActions filters list and watch actions for testing resources.
|
||||||
|
// Since list and watch don't change resource state we can filter it to lower
|
||||||
|
// nose level in our tests.
|
||||||
|
func filterInformerActions(actions []core.Action) []core.Action {
|
||||||
|
ret := []core.Action{}
|
||||||
|
for _, action := range actions {
|
||||||
|
if len(action.GetNamespace()) == 0 &&
|
||||||
|
(action.Matches("list", "secrets") ||
|
||||||
|
action.Matches("watch", "secrets") ||
|
||||||
|
action.Matches("list", "namespaces") ||
|
||||||
|
action.Matches("watch", "namespaces")) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret = append(ret, action)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fixture) expectUpdateSecretAction(p *v1.Secret) {
|
||||||
|
action := core.NewUpdateAction(schema.GroupVersionResource{
|
||||||
|
Version: "v1",
|
||||||
|
Resource: "secrets",
|
||||||
|
}, p.Namespace, p)
|
||||||
|
f.kubeactions = append(f.kubeactions, action)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKey(p *v1.Secret, t *testing.T) string {
|
||||||
|
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(p)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error getting key for pipeline %v: %v", p.Name, err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDoNothing(t *testing.T) {
|
||||||
|
f := newFixture(t)
|
||||||
|
nsName := "test-123"
|
||||||
|
secretName := "test"
|
||||||
|
projectName := "test_project"
|
||||||
|
|
||||||
|
ns := newNamespace(nsName, projectName)
|
||||||
|
secret := newSecret(nsName, secretName, nil, true, true)
|
||||||
|
|
||||||
|
f.secretLister = append(f.secretLister, secret)
|
||||||
|
f.namespaceLister = append(f.namespaceLister, ns)
|
||||||
|
f.objects = append(f.objects, secret)
|
||||||
|
f.initDevOpsProject = nsName
|
||||||
|
f.initCredential = []*v1.Secret{secret}
|
||||||
|
f.expectCredential = []*v1.Secret{secret}
|
||||||
|
|
||||||
|
f.run(getKey(secret, t))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddCredentialFinalizers(t *testing.T) {
|
||||||
|
f := newFixture(t)
|
||||||
|
nsName := "test-123"
|
||||||
|
secretName := "test"
|
||||||
|
projectName := "test_project"
|
||||||
|
|
||||||
|
ns := newNamespace(nsName, projectName)
|
||||||
|
secret := newSecret(nsName, secretName, nil, false, true)
|
||||||
|
|
||||||
|
expectSecret := newSecret(nsName, secretName, nil, true, true)
|
||||||
|
|
||||||
|
f.secretLister = append(f.secretLister, secret)
|
||||||
|
f.namespaceLister = append(f.namespaceLister, ns)
|
||||||
|
f.kubeobjects = append(f.kubeobjects, secret)
|
||||||
|
f.initDevOpsProject = nsName
|
||||||
|
f.initCredential = []*v1.Secret{secret}
|
||||||
|
f.expectCredential = []*v1.Secret{expectSecret}
|
||||||
|
f.expectUpdateSecretAction(expectSecret)
|
||||||
|
f.run(getKey(secret, t))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateCredential(t *testing.T) {
|
||||||
|
f := newFixture(t)
|
||||||
|
nsName := "test-123"
|
||||||
|
secretName := "test"
|
||||||
|
projectName := "test_project"
|
||||||
|
|
||||||
|
ns := newNamespace(nsName, projectName)
|
||||||
|
secret := newSecret(nsName, secretName, nil, true, true)
|
||||||
|
|
||||||
|
f.secretLister = append(f.secretLister, secret)
|
||||||
|
f.namespaceLister = append(f.namespaceLister, ns)
|
||||||
|
f.kubeobjects = append(f.kubeobjects, secret)
|
||||||
|
f.initDevOpsProject = nsName
|
||||||
|
f.expectCredential = []*v1.Secret{secret}
|
||||||
|
f.run(getKey(secret, t))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteCredential(t *testing.T) {
|
||||||
|
f := newFixture(t)
|
||||||
|
nsName := "test-123"
|
||||||
|
secretName := "test"
|
||||||
|
projectName := "test_project"
|
||||||
|
|
||||||
|
ns := newNamespace(nsName, projectName)
|
||||||
|
secret := newDeletingSecret(nsName, secretName)
|
||||||
|
|
||||||
|
expectSecret := secret.DeepCopy()
|
||||||
|
expectSecret.Finalizers = []string{}
|
||||||
|
f.secretLister = append(f.secretLister, secret)
|
||||||
|
f.namespaceLister = append(f.namespaceLister, ns)
|
||||||
|
f.kubeobjects = append(f.kubeobjects, secret)
|
||||||
|
f.initDevOpsProject = nsName
|
||||||
|
f.initCredential = []*v1.Secret{secret}
|
||||||
|
f.expectCredential = []*v1.Secret{}
|
||||||
|
f.expectUpdateSecretAction(expectSecret)
|
||||||
|
f.run(getKey(secret, t))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteNotExistCredential(t *testing.T) {
|
||||||
|
f := newFixture(t)
|
||||||
|
nsName := "test-123"
|
||||||
|
pipelineName := "test"
|
||||||
|
projectName := "test_project"
|
||||||
|
|
||||||
|
ns := newNamespace(nsName, projectName)
|
||||||
|
secret := newDeletingSecret(nsName, pipelineName)
|
||||||
|
|
||||||
|
expectSecret := secret.DeepCopy()
|
||||||
|
expectSecret.Finalizers = []string{}
|
||||||
|
f.secretLister = append(f.secretLister, secret)
|
||||||
|
f.namespaceLister = append(f.namespaceLister, ns)
|
||||||
|
f.kubeobjects = append(f.kubeobjects, secret)
|
||||||
|
f.initDevOpsProject = nsName
|
||||||
|
f.initCredential = []*v1.Secret{}
|
||||||
|
f.expectCredential = []*v1.Secret{}
|
||||||
|
f.expectUpdateSecretAction(expectSecret)
|
||||||
|
f.run(getKey(secret, t))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateCredential(t *testing.T) {
|
||||||
|
f := newFixture(t)
|
||||||
|
nsName := "test-123"
|
||||||
|
secretName := "test"
|
||||||
|
projectName := "test_project"
|
||||||
|
|
||||||
|
ns := newNamespace(nsName, projectName)
|
||||||
|
initSecret := newSecret(nsName, secretName, nil, true, true)
|
||||||
|
expectSecret := newSecret(nsName, secretName, map[string][]byte{"a":[]byte("aa")}, true, true)
|
||||||
|
f.secretLister = append(f.secretLister, expectSecret)
|
||||||
|
f.namespaceLister = append(f.namespaceLister, ns)
|
||||||
|
f.kubeobjects = append(f.kubeobjects, expectSecret)
|
||||||
|
f.initDevOpsProject = nsName
|
||||||
|
f.initCredential = []*v1.Secret{initSecret}
|
||||||
|
f.expectCredential = []*v1.Secret{expectSecret}
|
||||||
|
f.run(getKey(expectSecret, t))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotUpdateCredential(t *testing.T) {
|
||||||
|
f := newFixture(t)
|
||||||
|
nsName := "test-123"
|
||||||
|
secretName := "test"
|
||||||
|
projectName := "test_project"
|
||||||
|
|
||||||
|
ns := newNamespace(nsName, projectName)
|
||||||
|
initSecret := newSecret(nsName, secretName, nil, true, false)
|
||||||
|
expectSecret := newSecret(nsName, secretName, map[string][]byte{"a":[]byte("aa")}, true, false)
|
||||||
|
f.secretLister = append(f.secretLister, expectSecret)
|
||||||
|
f.namespaceLister = append(f.namespaceLister, ns)
|
||||||
|
f.kubeobjects = append(f.kubeobjects, expectSecret)
|
||||||
|
f.initDevOpsProject = nsName
|
||||||
|
f.initCredential = []*v1.Secret{initSecret}
|
||||||
|
f.expectCredential = []*v1.Secret{initSecret}
|
||||||
|
f.run(getKey(expectSecret, t))
|
||||||
|
}
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ func (c *Controller) syncHandler(key string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
copyPipeline.ObjectMeta.Finalizers = sliceutil.RemoveString(copyPipeline.ObjectMeta.Finalizers, func(item string) bool {
|
copyPipeline.ObjectMeta.Finalizers = sliceutil.RemoveString(copyPipeline.ObjectMeta.Finalizers, func(item string) bool {
|
||||||
return item == devopsv1alpha3.DevOpsProjectFinalizerName
|
return item == devopsv1alpha3.PipelineFinalizerName
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -354,12 +354,15 @@ func TestDeletePipeline(t *testing.T) {
|
|||||||
ns := newNamespace(nsName, projectName)
|
ns := newNamespace(nsName, projectName)
|
||||||
pipeline := newDeletingPipeline(nsName, pipelineName)
|
pipeline := newDeletingPipeline(nsName, pipelineName)
|
||||||
|
|
||||||
|
expectPipeline := pipeline.DeepCopy()
|
||||||
|
expectPipeline.Finalizers = []string{}
|
||||||
f.pipelineLister = append(f.pipelineLister, pipeline)
|
f.pipelineLister = append(f.pipelineLister, pipeline)
|
||||||
f.namespaceLister = append(f.namespaceLister, ns)
|
f.namespaceLister = append(f.namespaceLister, ns)
|
||||||
f.objects = append(f.objects, pipeline)
|
f.objects = append(f.objects, pipeline)
|
||||||
f.initDevOpsProject = nsName
|
f.initDevOpsProject = nsName
|
||||||
f.initPipeline = []*devops.Pipeline{pipeline}
|
f.initPipeline = []*devops.Pipeline{pipeline}
|
||||||
f.expectPipeline = []*devops.Pipeline{}
|
f.expectPipeline = []*devops.Pipeline{}
|
||||||
|
f.expectUpdatePipelineAction(expectPipeline)
|
||||||
f.run(getKey(pipeline, t))
|
f.run(getKey(pipeline, t))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,12 +375,15 @@ func TestDeleteNotExistPipeline(t *testing.T) {
|
|||||||
ns := newNamespace(nsName, projectName)
|
ns := newNamespace(nsName, projectName)
|
||||||
pipeline := newDeletingPipeline(nsName, pipelineName)
|
pipeline := newDeletingPipeline(nsName, pipelineName)
|
||||||
|
|
||||||
|
expectPipeline := pipeline.DeepCopy()
|
||||||
|
expectPipeline.Finalizers = []string{}
|
||||||
f.pipelineLister = append(f.pipelineLister, pipeline)
|
f.pipelineLister = append(f.pipelineLister, pipeline)
|
||||||
f.namespaceLister = append(f.namespaceLister, ns)
|
f.namespaceLister = append(f.namespaceLister, ns)
|
||||||
f.objects = append(f.objects, pipeline)
|
f.objects = append(f.objects, pipeline)
|
||||||
f.initDevOpsProject = nsName
|
f.initDevOpsProject = nsName
|
||||||
f.initPipeline = []*devops.Pipeline{}
|
f.initPipeline = []*devops.Pipeline{}
|
||||||
f.expectPipeline = []*devops.Pipeline{}
|
f.expectPipeline = []*devops.Pipeline{}
|
||||||
|
f.expectUpdatePipelineAction(expectPipeline)
|
||||||
f.run(getKey(pipeline, t))
|
f.run(getKey(pipeline, t))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ProjectPipelineHandler struct {
|
type ProjectPipelineHandler struct {
|
||||||
projectCredentialOperator devops.ProjectCredentialOperator
|
projectMemberOperator devops.ProjectMemberOperator
|
||||||
projectMemberOperator devops.ProjectMemberOperator
|
devopsOperator devops.DevopsOperator
|
||||||
devopsOperator devops.DevopsOperator
|
projectOperator devops.ProjectOperator
|
||||||
projectOperator devops.ProjectOperator
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PipelineSonarHandler struct {
|
type PipelineSonarHandler struct {
|
||||||
@@ -24,10 +23,9 @@ type PipelineSonarHandler struct {
|
|||||||
|
|
||||||
func NewProjectPipelineHandler(devopsClient devopsClient.Interface, dbClient *mysql.Database) ProjectPipelineHandler {
|
func NewProjectPipelineHandler(devopsClient devopsClient.Interface, dbClient *mysql.Database) ProjectPipelineHandler {
|
||||||
return ProjectPipelineHandler{
|
return ProjectPipelineHandler{
|
||||||
projectCredentialOperator: devops.NewProjectCredentialOperator(devopsClient, dbClient),
|
projectMemberOperator: devops.NewProjectMemberOperator(devopsClient, dbClient),
|
||||||
projectMemberOperator: devops.NewProjectMemberOperator(devopsClient, dbClient),
|
devopsOperator: devops.NewDevopsOperator(devopsClient),
|
||||||
devopsOperator: devops.NewDevopsOperator(devopsClient),
|
projectOperator: devops.NewProjectOperator(dbClient),
|
||||||
projectOperator: devops.NewProjectOperator(dbClient),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,6 +37,5 @@ func NewPipelineSonarHandler(devopsClient devopsClient.Interface, dbClient *mysq
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewS2iBinaryHandler(client versioned.Interface, informers externalversions.SharedInformerFactory, s3Client s3.Interface) S2iBinaryHandler {
|
func NewS2iBinaryHandler(client versioned.Interface, informers externalversions.SharedInformerFactory, s3Client s3.Interface) S2iBinaryHandler {
|
||||||
|
|
||||||
return S2iBinaryHandler{devops.NewS2iBinaryUploader(client, informers, s3Client)}
|
return S2iBinaryHandler{devops.NewS2iBinaryUploader(client, informers, s3Client)}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,121 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2019 The KubeSphere Authors.
|
|
||||||
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 v1alpha2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/emicklei/go-restful"
|
|
||||||
"k8s.io/klog"
|
|
||||||
"kubesphere.io/kubesphere/pkg/api"
|
|
||||||
"kubesphere.io/kubesphere/pkg/constants"
|
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (h ProjectPipelineHandler) CreateDevOpsProjectCredentialHandler(request *restful.Request, resp *restful.Response) {
|
|
||||||
|
|
||||||
projectId := request.PathParameter("devops")
|
|
||||||
username := request.HeaderParameter(constants.UserNameHeader)
|
|
||||||
var credential *devops.Credential
|
|
||||||
err := request.ReadEntity(&credential)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
api.HandleBadRequest(resp, nil, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
credentialId, err := h.projectCredentialOperator.CreateProjectCredential(projectId, username, credential)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
api.HandleInternalError(resp, nil, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
}{Name: credentialId})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h ProjectPipelineHandler) UpdateDevOpsProjectCredentialHandler(request *restful.Request, resp *restful.Response) {
|
|
||||||
|
|
||||||
projectId := request.PathParameter("devops")
|
|
||||||
credentialId := request.PathParameter("credential")
|
|
||||||
var credential *devops.Credential
|
|
||||||
err := request.ReadEntity(&credential)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
api.HandleBadRequest(resp, nil, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
credentialId, err = h.projectCredentialOperator.UpdateProjectCredential(projectId, credentialId, credential)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
api.HandleInternalError(resp, nil, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
}{Name: credentialId})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h ProjectPipelineHandler) DeleteDevOpsProjectCredentialHandler(request *restful.Request, resp *restful.Response) {
|
|
||||||
|
|
||||||
projectId := request.PathParameter("devops")
|
|
||||||
credentialId := request.PathParameter("credential")
|
|
||||||
|
|
||||||
credentialId, err := h.projectCredentialOperator.DeleteProjectCredential(projectId, credentialId)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
api.HandleInternalError(resp, nil, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
}{Name: credentialId})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h ProjectPipelineHandler) GetDevOpsProjectCredentialHandler(request *restful.Request, resp *restful.Response) {
|
|
||||||
|
|
||||||
projectId := request.PathParameter("devops")
|
|
||||||
credentialId := request.PathParameter("credential")
|
|
||||||
getContent := request.QueryParameter("content")
|
|
||||||
response, err := h.projectCredentialOperator.GetProjectCredential(projectId, credentialId, getContent)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
api.HandleInternalError(resp, nil, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.WriteAsJson(response)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h ProjectPipelineHandler) GetDevOpsProjectCredentialsHandler(request *restful.Request, resp *restful.Response) {
|
|
||||||
projectId := request.PathParameter("devops")
|
|
||||||
|
|
||||||
jenkinsCredentials, err := h.projectCredentialOperator.GetProjectCredentials(projectId)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
api.HandleInternalError(resp, nil, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resp.WriteAsJson(jenkinsCredentials)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -156,49 +156,6 @@ func AddToContainer(c *restful.Container, devopsClient devops.Interface,
|
|||||||
Param(webservice.PathParameter("member", "member's username, e.g. admin")).
|
Param(webservice.PathParameter("member", "member's username, e.g. admin")).
|
||||||
Writes(devops.ProjectMembership{}))
|
Writes(devops.ProjectMembership{}))
|
||||||
|
|
||||||
webservice.Route(webservice.POST("/devops/{devops}/credentials").
|
|
||||||
To(projectPipelineHander.CreateDevOpsProjectCredentialHandler).
|
|
||||||
Doc("Create a credential in the specified DevOps project").
|
|
||||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsProjectCredentialTag}).
|
|
||||||
Param(webservice.PathParameter("devops", "DevOps project's ID, e.g. project-RRRRAzLBlLEm")).
|
|
||||||
Reads(devops.Credential{}))
|
|
||||||
|
|
||||||
webservice.Route(webservice.PUT("/devops/{devops}/credentials/{credential}").
|
|
||||||
To(projectPipelineHander.UpdateDevOpsProjectCredentialHandler).
|
|
||||||
Doc("Update the specified credential of the DevOps project").
|
|
||||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsProjectCredentialTag}).
|
|
||||||
Param(webservice.PathParameter("devops", "DevOps project's ID, e.g. project-RRRRAzLBlLEm")).
|
|
||||||
Param(webservice.PathParameter("credential", "credential's ID, e.g. dockerhub-id")).
|
|
||||||
Reads(devops.Credential{}))
|
|
||||||
|
|
||||||
webservice.Route(webservice.DELETE("/devops/{devops}/credentials/{credential}").
|
|
||||||
To(projectPipelineHander.DeleteDevOpsProjectCredentialHandler).
|
|
||||||
Doc("Delete the specified credential of the DevOps project").
|
|
||||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsProjectCredentialTag}).
|
|
||||||
Param(webservice.PathParameter("devops", "DevOps project's ID, e.g. project-RRRRAzLBlLEm")).
|
|
||||||
Param(webservice.PathParameter("credential", "credential's ID, e.g. dockerhub-id")))
|
|
||||||
|
|
||||||
webservice.Route(webservice.GET("/devops/{devops}/credentials/{credential}").
|
|
||||||
To(projectPipelineHander.GetDevOpsProjectCredentialHandler).
|
|
||||||
Doc("Get the specified credential of the DevOps project").
|
|
||||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsProjectCredentialTag}).
|
|
||||||
Param(webservice.PathParameter("devops", "DevOps project's ID, e.g. project-RRRRAzLBlLEm")).
|
|
||||||
Param(webservice.PathParameter("credential", "credential's ID, e.g. dockerhub-id")).
|
|
||||||
Param(webservice.QueryParameter("content", `
|
|
||||||
Get extra credential content if this query parameter is set.
|
|
||||||
Specifically, there are three types of info in a credential. One is the basic info that must be returned for each query such as name, id, etc.
|
|
||||||
The second one is non-encrypted info such as the username of the username-password type of credential, which returns when the "content" parameter is set to non-empty.
|
|
||||||
The last one is encrypted info, such as the password of the username-password type of credential, which never returns.
|
|
||||||
`)).
|
|
||||||
Returns(http.StatusOK, RespOK, devops.Credential{}))
|
|
||||||
|
|
||||||
webservice.Route(webservice.GET("/devops/{devops}/credentials").
|
|
||||||
To(projectPipelineHander.GetDevOpsProjectCredentialsHandler).
|
|
||||||
Doc("Get all credentials of the specified DevOps project").
|
|
||||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsProjectCredentialTag}).
|
|
||||||
Param(webservice.PathParameter("devops", "DevOps project's ID, e.g. project-RRRRAzLBlLEm")).
|
|
||||||
Returns(http.StatusOK, RespOK, []devops.Credential{}))
|
|
||||||
|
|
||||||
// match Jenkisn api "/blue/rest/organizations/jenkins/pipelines/{devops}/{pipeline}"
|
// match Jenkisn api "/blue/rest/organizations/jenkins/pipelines/{devops}/{pipeline}"
|
||||||
webservice.Route(webservice.GET("/devops/{devops}/pipelines/{pipeline}").
|
webservice.Route(webservice.GET("/devops/{devops}/pipelines/{pipeline}").
|
||||||
To(projectPipelineHander.GetPipeline).
|
To(projectPipelineHander.GetPipeline).
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2019 The KubeSphere Authors.
|
|
||||||
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 devops
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ProjectCredentialTableName = "project_credential"
|
|
||||||
ProjectCredentialIdColumn = "credential_id"
|
|
||||||
ProjectCredentialDomainColumn = "domain"
|
|
||||||
ProjectCredentialProjectIdColumn = "project_id"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProjectCredential struct {
|
|
||||||
ProjectId string `json:"project_id"`
|
|
||||||
CredentialId string `json:"credential_id"`
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
Creator string `json:"creator"`
|
|
||||||
CreateTime time.Time `json:"create_time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var ProjectCredentialColumns = GetColumnsFromStruct(&ProjectCredential{})
|
|
||||||
|
|
||||||
func NewProjectCredential(projectId, credentialId, domain, creator string) *ProjectCredential {
|
|
||||||
if govalidator.IsNull(domain) {
|
|
||||||
domain = "_"
|
|
||||||
}
|
|
||||||
return &ProjectCredential{
|
|
||||||
ProjectId: projectId,
|
|
||||||
CredentialId: credentialId,
|
|
||||||
Domain: domain,
|
|
||||||
Creator: creator,
|
|
||||||
CreateTime: time.Now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,286 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2019 The KubeSphere Authors.
|
|
||||||
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 devops
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/emicklei/go-restful"
|
|
||||||
"github.com/gocraft/dbr"
|
|
||||||
"k8s.io/klog"
|
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/db"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProjectCredentialOperator interface {
|
|
||||||
CreateProjectCredential(projectId, username string, credentialRequest *devops.Credential) (string, error)
|
|
||||||
UpdateProjectCredential(projectId, credentialId string, credentialRequest *devops.Credential) (string, error)
|
|
||||||
DeleteProjectCredential(projectId, credentialId string) (string, error)
|
|
||||||
GetProjectCredential(projectId, credentialId, getContent string) (*devops.Credential, error)
|
|
||||||
GetProjectCredentials(projectId string) ([]*devops.Credential, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type projectCredentialOperator struct {
|
|
||||||
devopsClient devops.Interface
|
|
||||||
db *mysql.Database
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewProjectCredentialOperator(devopsClient devops.Interface, dbClient *mysql.Database) ProjectCredentialOperator {
|
|
||||||
return &projectCredentialOperator{devopsClient: devopsClient, db: dbClient}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *projectCredentialOperator) CreateProjectCredential(projectId, username string, credentialRequest *devops.Credential) (string, error) {
|
|
||||||
switch credentialRequest.Type {
|
|
||||||
case devops.CredentialTypeUsernamePassword:
|
|
||||||
if credentialRequest.UsernamePasswordCredential == nil {
|
|
||||||
err := fmt.Errorf("usename_password should not be nil")
|
|
||||||
klog.Error(err)
|
|
||||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
case devops.CredentialTypeSsh:
|
|
||||||
if credentialRequest.SshCredential == nil {
|
|
||||||
err := fmt.Errorf("ssh should not be nil")
|
|
||||||
klog.Error(err)
|
|
||||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
case devops.CredentialTypeSecretText:
|
|
||||||
if credentialRequest.SecretTextCredential == nil {
|
|
||||||
err := fmt.Errorf("secret_text should not be nil")
|
|
||||||
klog.Error(err)
|
|
||||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
case devops.CredentialTypeKubeConfig:
|
|
||||||
if credentialRequest.KubeconfigCredential == nil {
|
|
||||||
err := fmt.Errorf("kubeconfig should not be nil")
|
|
||||||
klog.Error(err)
|
|
||||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
err := fmt.Errorf("error unsupport credential type")
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
|
||||||
|
|
||||||
}
|
|
||||||
credentialId, err := o.devopsClient.CreateCredentialInProject(projectId, credentialRequest)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
err = o.insertCredentialToDb(projectId, *credentialId, credentialRequest.Domain, username)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return *credentialId, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *projectCredentialOperator) UpdateProjectCredential(projectId, credentialId string, credentialRequest *devops.Credential) (string, error) {
|
|
||||||
|
|
||||||
credential, err := o.devopsClient.GetCredentialInProject(projectId,
|
|
||||||
credentialId, false)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
switch credential.Type {
|
|
||||||
case devops.CredentialTypeUsernamePassword:
|
|
||||||
if credentialRequest.UsernamePasswordCredential == nil {
|
|
||||||
err := fmt.Errorf("usename_password should not be nil")
|
|
||||||
klog.Error(err)
|
|
||||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
case devops.CredentialTypeSsh:
|
|
||||||
if credentialRequest.SshCredential == nil {
|
|
||||||
err := fmt.Errorf("ssh should not be nil")
|
|
||||||
klog.Error(err)
|
|
||||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
case devops.CredentialTypeSecretText:
|
|
||||||
if credentialRequest.SecretTextCredential == nil {
|
|
||||||
err := fmt.Errorf("secret_text should not be nil")
|
|
||||||
klog.Error(err)
|
|
||||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
case devops.CredentialTypeKubeConfig:
|
|
||||||
if credentialRequest.KubeconfigCredential == nil {
|
|
||||||
err := fmt.Errorf("kubeconfig should not be nil")
|
|
||||||
klog.Error(err)
|
|
||||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
err := fmt.Errorf("error unsupport credential type")
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
credentialRequest.Id = credentialId
|
|
||||||
_, err = o.devopsClient.UpdateCredentialInProject(projectId, credentialRequest)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
return credentialId, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *projectCredentialOperator) DeleteProjectCredential(projectId, credentialId string) (string, error) {
|
|
||||||
|
|
||||||
_, err := o.devopsClient.GetCredentialInProject(projectId,
|
|
||||||
credentialId, false)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
id, err := o.devopsClient.DeleteCredentialInProject(projectId, credentialId)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteConditions := append(make([]dbr.Builder, 0), db.Eq(ProjectCredentialProjectIdColumn, projectId))
|
|
||||||
deleteConditions = append(deleteConditions, db.Eq(ProjectCredentialIdColumn, credentialId))
|
|
||||||
deleteConditions = append(deleteConditions, db.Eq(ProjectCredentialDomainColumn, "_"))
|
|
||||||
|
|
||||||
_, err = o.db.DeleteFrom(ProjectCredentialTableName).
|
|
||||||
Where(db.And(deleteConditions...)).Exec()
|
|
||||||
if err != nil && err != db.ErrNotFound {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return *id, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *projectCredentialOperator) GetProjectCredential(projectId, credentialId, getContent string) (*devops.Credential, error) {
|
|
||||||
|
|
||||||
content := false
|
|
||||||
if getContent != "" {
|
|
||||||
content = true
|
|
||||||
}
|
|
||||||
credential, err := o.devopsClient.GetCredentialInProject(projectId,
|
|
||||||
credentialId,
|
|
||||||
content)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
projectCredential := &ProjectCredential{}
|
|
||||||
err = o.db.Select(ProjectCredentialColumns...).
|
|
||||||
From(ProjectCredentialTableName).Where(
|
|
||||||
db.And(db.Eq(ProjectCredentialProjectIdColumn, projectId),
|
|
||||||
db.Eq(ProjectCredentialIdColumn, credentialId),
|
|
||||||
db.Eq(ProjectCredentialDomainColumn, credential.Domain))).LoadOne(projectCredential)
|
|
||||||
|
|
||||||
if err != nil && err != db.ErrNotFound {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return nil, restful.NewError(http.StatusInternalServerError, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
response := formatCredentialResponse(credential, projectCredential)
|
|
||||||
return response, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *projectCredentialOperator) GetProjectCredentials(projectId string) ([]*devops.Credential, error) {
|
|
||||||
|
|
||||||
credentialResponses, err := o.devopsClient.GetCredentialsInProject(projectId)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
selectCondition := db.Eq(ProjectCredentialProjectIdColumn, projectId)
|
|
||||||
projectCredentials := make([]*ProjectCredential, 0)
|
|
||||||
_, err = o.db.Select(ProjectCredentialColumns...).
|
|
||||||
From(ProjectCredentialTableName).Where(selectCondition).Load(&projectCredentials)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return nil, restful.NewError(http.StatusInternalServerError, err.Error())
|
|
||||||
}
|
|
||||||
response := formatCredentialsResponse(credentialResponses, projectCredentials)
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *projectCredentialOperator) insertCredentialToDb(projectId, credentialId, domain, username string) error {
|
|
||||||
|
|
||||||
projectCredential := NewProjectCredential(projectId, credentialId, domain, username)
|
|
||||||
_, err := o.db.InsertInto(ProjectCredentialTableName).Columns(ProjectCredentialColumns...).
|
|
||||||
Record(projectCredential).Exec()
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return restful.NewError(http.StatusInternalServerError, err.Error())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatCredentialResponse(
|
|
||||||
credentialResponse *devops.Credential,
|
|
||||||
dbCredentialResponse *ProjectCredential) *devops.Credential {
|
|
||||||
response := &devops.Credential{}
|
|
||||||
response.Id = credentialResponse.Id
|
|
||||||
response.Description = credentialResponse.Description
|
|
||||||
response.DisplayName = credentialResponse.DisplayName
|
|
||||||
if credentialResponse.Fingerprint != nil && credentialResponse.Fingerprint.Hash != "" {
|
|
||||||
response.Fingerprint = &struct {
|
|
||||||
FileName string `json:"file_name,omitempty" description:"Credential's display name and description"`
|
|
||||||
Hash string `json:"hash,omitempty" description:"Credential's hash"`
|
|
||||||
Usage []*struct {
|
|
||||||
Name string `json:"name,omitempty" description:"pipeline full name"`
|
|
||||||
Ranges struct {
|
|
||||||
Ranges []*struct {
|
|
||||||
Start int `json:"start,omitempty" description:"Start build number"`
|
|
||||||
End int `json:"end,omitempty" description:"End build number"`
|
|
||||||
} `json:"ranges,omitempty"`
|
|
||||||
} `json:"ranges,omitempty" description:"The build number of all pipelines that use this credential"`
|
|
||||||
} `json:"usage,omitempty" description:"all usage of Credential"`
|
|
||||||
}{}
|
|
||||||
response.Fingerprint.FileName = credentialResponse.Fingerprint.FileName
|
|
||||||
response.Fingerprint.Hash = credentialResponse.Fingerprint.Hash
|
|
||||||
for _, usage := range credentialResponse.Fingerprint.Usage {
|
|
||||||
response.Fingerprint.Usage = append(response.Fingerprint.Usage, usage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response.Domain = credentialResponse.Domain
|
|
||||||
|
|
||||||
if dbCredentialResponse != nil {
|
|
||||||
response.CreateTime = &dbCredentialResponse.CreateTime
|
|
||||||
response.Creator = dbCredentialResponse.Creator
|
|
||||||
}
|
|
||||||
|
|
||||||
credentialType, ok := devops.CredentialTypeMap[credentialResponse.Type]
|
|
||||||
if ok {
|
|
||||||
response.Type = credentialType
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
response.Type = credentialResponse.Type
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatCredentialsResponse(credentialsResponse []*devops.Credential,
|
|
||||||
projectCredentials []*ProjectCredential) []*devops.Credential {
|
|
||||||
responseSlice := make([]*devops.Credential, 0)
|
|
||||||
for _, credential := range credentialsResponse {
|
|
||||||
var dbCredential *ProjectCredential = nil
|
|
||||||
for _, projectCredential := range projectCredentials {
|
|
||||||
if projectCredential.CredentialId == credential.Id &&
|
|
||||||
projectCredential.Domain == credential.Domain {
|
|
||||||
dbCredential = projectCredential
|
|
||||||
}
|
|
||||||
}
|
|
||||||
responseSlice = append(responseSlice, formatCredentialResponse(credential, dbCredential))
|
|
||||||
}
|
|
||||||
return responseSlice
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package devops
|
package devops
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -50,28 +51,14 @@ type KubeconfigCredential struct {
|
|||||||
Content string `json:"content,omitempty" description:"content of kubeconfig"`
|
Content string `json:"content,omitempty" description:"content of kubeconfig"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
CredentialTypeUsernamePassword = "username_password"
|
|
||||||
CredentialTypeSsh = "ssh"
|
|
||||||
CredentialTypeSecretText = "secret_text"
|
|
||||||
CredentialTypeKubeConfig = "kubeconfig"
|
|
||||||
)
|
|
||||||
|
|
||||||
var CredentialTypeMap = map[string]string{
|
|
||||||
"SSH Username with private key": CredentialTypeSsh,
|
|
||||||
"Username with password": CredentialTypeUsernamePassword,
|
|
||||||
"Secret text": CredentialTypeSecretText,
|
|
||||||
"Kubernetes configuration (kubeconfig)": CredentialTypeKubeConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
type CredentialOperator interface {
|
type CredentialOperator interface {
|
||||||
CreateCredentialInProject(projectId string, credential *Credential) (*string, error)
|
CreateCredentialInProject(projectId string, credential *v1.Secret) (string, error)
|
||||||
|
|
||||||
UpdateCredentialInProject(projectId string, credential *Credential) (*string, error)
|
UpdateCredentialInProject(projectId string, credential *v1.Secret) (string, error)
|
||||||
|
|
||||||
GetCredentialInProject(projectId, id string, content bool) (*Credential, error)
|
GetCredentialInProject(projectId, id string) (*Credential, error)
|
||||||
|
|
||||||
GetCredentialsInProject(projectId string) ([]*Credential, error)
|
GetCredentialsInProject(projectId string) ([]*Credential, error)
|
||||||
|
|
||||||
DeleteCredentialInProject(projectId, id string) (*string, error)
|
DeleteCredentialInProject(projectId, id string) (string, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
devopsv1alpha3 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
|
devopsv1alpha3 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -17,6 +18,8 @@ type Devops struct {
|
|||||||
Projects map[string]interface{}
|
Projects map[string]interface{}
|
||||||
|
|
||||||
Pipelines map[string]map[string]*devopsv1alpha3.Pipeline
|
Pipelines map[string]map[string]*devopsv1alpha3.Pipeline
|
||||||
|
|
||||||
|
Credentials map[string]map[string]*v1.Secret
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(projects ...string) *Devops {
|
func New(projects ...string) *Devops {
|
||||||
@@ -45,12 +48,28 @@ func NewWithPipelines(project string, pipelines ...*devopsv1alpha3.Pipeline) *De
|
|||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewWithCredentials(project string, credentials ...*v1.Secret) *Devops {
|
||||||
|
d := &Devops{
|
||||||
|
Data: nil,
|
||||||
|
Projects: map[string]interface{}{},
|
||||||
|
Credentials: map[string]map[string]*v1.Secret{},
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Projects[project] = true
|
||||||
|
d.Credentials[project] = map[string]*v1.Secret{}
|
||||||
|
for _, f := range credentials {
|
||||||
|
d.Credentials[project][f.Name] = f
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Devops) CreateDevOpsProject(projectId string) (string, error) {
|
func (d *Devops) CreateDevOpsProject(projectId string) (string, error) {
|
||||||
if _, ok := d.Projects[projectId]; ok {
|
if _, ok := d.Projects[projectId]; ok {
|
||||||
return projectId, nil
|
return projectId, nil
|
||||||
}
|
}
|
||||||
d.Projects[projectId] = true
|
d.Projects[projectId] = true
|
||||||
d.Pipelines[projectId] = map[string]*devopsv1alpha3.Pipeline{}
|
d.Pipelines[projectId] = map[string]*devopsv1alpha3.Pipeline{}
|
||||||
|
d.Credentials[projectId] = map[string]*v1.Secret{}
|
||||||
return projectId, nil
|
return projectId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +77,7 @@ func (d *Devops) DeleteDevOpsProject(projectId string) error {
|
|||||||
if _, ok := d.Projects[projectId]; ok {
|
if _, ok := d.Projects[projectId]; ok {
|
||||||
delete(d.Projects, projectId)
|
delete(d.Projects, projectId)
|
||||||
delete(d.Pipelines, projectId)
|
delete(d.Pipelines, projectId)
|
||||||
|
delete(d.Credentials, projectId)
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return &devops.ErrorResponse{
|
return &devops.ErrorResponse{
|
||||||
@@ -264,19 +284,128 @@ func (d *Devops) ToJson(httpParameters *devops.HttpParameters) (*devops.ResJson,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CredentialOperator
|
// CredentialOperator
|
||||||
func (d *Devops) CreateCredentialInProject(projectId string, credential *devops.Credential) (*string, error) {
|
func (d *Devops) CreateCredentialInProject(projectId string, credential *v1.Secret) (string, error) {
|
||||||
return nil, nil
|
if _, ok := d.Credentials[projectId][credential.Name]; ok {
|
||||||
|
err := fmt.Errorf("credential name [%s] has been used", credential.Name)
|
||||||
|
return "", restful.NewError(http.StatusConflict, err.Error())
|
||||||
|
}
|
||||||
|
d.Credentials[projectId][credential.Name] = credential
|
||||||
|
return credential.Name, nil
|
||||||
}
|
}
|
||||||
func (d *Devops) UpdateCredentialInProject(projectId string, credential *devops.Credential) (*string, error) {
|
func (d *Devops) UpdateCredentialInProject(projectId string, credential *v1.Secret) (string, error) {
|
||||||
return nil, nil
|
if _, ok := d.Credentials[projectId][credential.Name]; !ok {
|
||||||
|
err := &devops.ErrorResponse{
|
||||||
|
Body: []byte{},
|
||||||
|
Response: &http.Response{
|
||||||
|
Status: "404 Not Found",
|
||||||
|
StatusCode: 404,
|
||||||
|
Proto: "HTTP/1.1",
|
||||||
|
ProtoMajor: 1,
|
||||||
|
ProtoMinor: 1,
|
||||||
|
ContentLength: 50,
|
||||||
|
Header: http.Header{
|
||||||
|
"Foo": []string{"Bar"},
|
||||||
|
},
|
||||||
|
Body: ioutil.NopCloser(strings.NewReader("foo")), // shouldn't be used
|
||||||
|
Request: &http.Request{
|
||||||
|
Method: "",
|
||||||
|
URL: &url.URL{
|
||||||
|
Scheme: "",
|
||||||
|
Opaque: "",
|
||||||
|
User: nil,
|
||||||
|
Host: "",
|
||||||
|
Path: "",
|
||||||
|
RawPath: "",
|
||||||
|
ForceQuery: false,
|
||||||
|
RawQuery: "",
|
||||||
|
Fragment: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "",
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
d.Credentials[projectId][credential.Name] = credential
|
||||||
|
return credential.Name, nil
|
||||||
}
|
}
|
||||||
func (d *Devops) GetCredentialInProject(projectId, id string, content bool) (*devops.Credential, error) {
|
|
||||||
return nil, nil
|
func (d *Devops) GetCredentialInProject(projectId, id string) (*devops.Credential, error) {
|
||||||
|
if _, ok := d.Credentials[projectId][id]; !ok {
|
||||||
|
err := &devops.ErrorResponse{
|
||||||
|
Body: []byte{},
|
||||||
|
Response: &http.Response{
|
||||||
|
Status: "404 Not Found",
|
||||||
|
StatusCode: 404,
|
||||||
|
Proto: "HTTP/1.1",
|
||||||
|
ProtoMajor: 1,
|
||||||
|
ProtoMinor: 1,
|
||||||
|
ContentLength: 50,
|
||||||
|
Header: http.Header{
|
||||||
|
"Foo": []string{"Bar"},
|
||||||
|
},
|
||||||
|
Body: ioutil.NopCloser(strings.NewReader("foo")), // shouldn't be used
|
||||||
|
Request: &http.Request{
|
||||||
|
Method: "",
|
||||||
|
URL: &url.URL{
|
||||||
|
Scheme: "",
|
||||||
|
Opaque: "",
|
||||||
|
User: nil,
|
||||||
|
Host: "",
|
||||||
|
Path: "",
|
||||||
|
RawPath: "",
|
||||||
|
ForceQuery: false,
|
||||||
|
RawQuery: "",
|
||||||
|
Fragment: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "",
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &devops.Credential{Id: id}, nil
|
||||||
}
|
}
|
||||||
func (d *Devops) GetCredentialsInProject(projectId string) ([]*devops.Credential, error) {
|
func (d *Devops) GetCredentialsInProject(projectId string) ([]*devops.Credential, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
func (d *Devops) DeleteCredentialInProject(projectId, id string) (*string, error) { return nil, nil }
|
func (d *Devops) DeleteCredentialInProject(projectId, id string) (string, error) {
|
||||||
|
if _, ok := d.Credentials[projectId][id]; !ok {
|
||||||
|
err := &devops.ErrorResponse{
|
||||||
|
Body: []byte{},
|
||||||
|
Response: &http.Response{
|
||||||
|
Status: "404 Not Found",
|
||||||
|
StatusCode: 404,
|
||||||
|
Proto: "HTTP/1.1",
|
||||||
|
ProtoMajor: 1,
|
||||||
|
ProtoMinor: 1,
|
||||||
|
ContentLength: 50,
|
||||||
|
Header: http.Header{
|
||||||
|
"Foo": []string{"Bar"},
|
||||||
|
},
|
||||||
|
Body: ioutil.NopCloser(strings.NewReader("foo")), // shouldn't be used
|
||||||
|
Request: &http.Request{
|
||||||
|
Method: "",
|
||||||
|
URL: &url.URL{
|
||||||
|
Scheme: "",
|
||||||
|
Opaque: "",
|
||||||
|
User: nil,
|
||||||
|
Host: "",
|
||||||
|
Path: "",
|
||||||
|
RawPath: "",
|
||||||
|
ForceQuery: false,
|
||||||
|
RawQuery: "",
|
||||||
|
Fragment: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "",
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
delete(d.Credentials[projectId], id)
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
// BuildGetter
|
// BuildGetter
|
||||||
func (d *Devops) GetProjectPipelineBuildByType(projectId, pipelineId string, status string) (*devops.Build, error) {
|
func (d *Devops) GetProjectPipelineBuildByType(projectId, pipelineId string, status string) (*devops.Build, error) {
|
||||||
@@ -306,6 +435,7 @@ func (d *Devops) CreateProjectPipeline(projectId string, pipeline *devopsv1alpha
|
|||||||
d.Pipelines[projectId][pipeline.Name] = pipeline
|
d.Pipelines[projectId][pipeline.Name] = pipeline
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Devops) DeleteProjectPipeline(projectId string, pipelineId string) (string, error) {
|
func (d *Devops) DeleteProjectPipeline(projectId string, pipelineId string) (string, error) {
|
||||||
if _, ok := d.Pipelines[projectId][pipelineId]; !ok {
|
if _, ok := d.Pipelines[projectId][pipelineId]; !ok {
|
||||||
err := &devops.ErrorResponse{
|
err := &devops.ErrorResponse{
|
||||||
@@ -343,6 +473,7 @@ func (d *Devops) DeleteProjectPipeline(projectId string, pipelineId string) (str
|
|||||||
delete(d.Pipelines[projectId], pipelineId)
|
delete(d.Pipelines[projectId], pipelineId)
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Devops) UpdateProjectPipeline(projectId string, pipeline *devopsv1alpha3.Pipeline) (string, error) {
|
func (d *Devops) UpdateProjectPipeline(projectId string, pipeline *devopsv1alpha3.Pipeline) (string, error) {
|
||||||
if _, ok := d.Pipelines[projectId][pipeline.Name]; !ok {
|
if _, ok := d.Pipelines[projectId][pipeline.Name]; !ok {
|
||||||
err := &devops.ErrorResponse{
|
err := &devops.ErrorResponse{
|
||||||
@@ -380,6 +511,7 @@ func (d *Devops) UpdateProjectPipeline(projectId string, pipeline *devopsv1alpha
|
|||||||
d.Pipelines[projectId][pipeline.Name] = pipeline
|
d.Pipelines[projectId][pipeline.Name] = pipeline
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Devops) GetProjectPipelineConfig(projectId, pipelineId string) (*devopsv1alpha3.Pipeline, error) {
|
func (d *Devops) GetProjectPipelineConfig(projectId, pipelineId string) (*devopsv1alpha3.Pipeline, error) {
|
||||||
if _, ok := d.Pipelines[projectId][pipelineId]; !ok {
|
if _, ok := d.Pipelines[projectId][pipelineId]; !ok {
|
||||||
err := &devops.ErrorResponse{
|
err := &devops.ErrorResponse{
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ package jenkins
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/PuerkitoBio/goquery"
|
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
|
devopsv1alpha3 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const SSHCrenditalStaplerClass = "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
|
const SSHCrenditalStaplerClass = "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
|
||||||
@@ -99,10 +99,15 @@ type CredentialResponse struct {
|
|||||||
Domain string `json:"domain"`
|
Domain string `json:"domain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSshCredential(id, username, passphrase, privateKey, description string) *SshCredential {
|
func NewSshCredential(secret *v1.Secret) *SshCredential {
|
||||||
|
id := secret.Name
|
||||||
|
username := string(secret.Data[devopsv1alpha3.SSHAuthUsernameKey])
|
||||||
|
passphrase := string(secret.Data[devopsv1alpha3.SSHAuthPassphraseKey])
|
||||||
|
privatekey := string(secret.Data[devopsv1alpha3.SSHAuthPrivateKey])
|
||||||
|
|
||||||
keySource := PrivateKeySource{
|
keySource := PrivateKeySource{
|
||||||
StaplerClass: DirectSSHCrenditalStaplerClass,
|
StaplerClass: DirectSSHCrenditalStaplerClass,
|
||||||
PrivateKey: privateKey,
|
PrivateKey: privatekey,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SshCredential{
|
return &SshCredential{
|
||||||
@@ -111,48 +116,52 @@ func NewSshCredential(id, username, passphrase, privateKey, description string)
|
|||||||
Username: username,
|
Username: username,
|
||||||
Passphrase: passphrase,
|
Passphrase: passphrase,
|
||||||
KeySource: keySource,
|
KeySource: keySource,
|
||||||
Description: description,
|
|
||||||
StaplerClass: SSHCrenditalStaplerClass,
|
StaplerClass: SSHCrenditalStaplerClass,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUsernamePasswordCredential(id, username, password, description string) *UsernamePasswordCredential {
|
func NewUsernamePasswordCredential(secret *v1.Secret) *UsernamePasswordCredential {
|
||||||
|
id := secret.Name
|
||||||
|
username := string(secret.Data[devopsv1alpha3.BasicAuthUsernameKey])
|
||||||
|
password := string(secret.Data[devopsv1alpha3.BasicAuthPasswordKey])
|
||||||
return &UsernamePasswordCredential{
|
return &UsernamePasswordCredential{
|
||||||
Scope: GLOBALScope,
|
Scope: GLOBALScope,
|
||||||
Id: id,
|
Id: id,
|
||||||
Username: username,
|
Username: username,
|
||||||
Password: password,
|
Password: password,
|
||||||
Description: description,
|
|
||||||
StaplerClass: UsernamePassswordCredentialStaplerClass,
|
StaplerClass: UsernamePassswordCredentialStaplerClass,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSecretTextCredential(id, secret, description string) *SecretTextCredential {
|
func NewSecretTextCredential(secret *v1.Secret) *SecretTextCredential {
|
||||||
|
id := secret.Name
|
||||||
|
secretContent := string(secret.Data[devopsv1alpha3.SecretTextSecretKey])
|
||||||
return &SecretTextCredential{
|
return &SecretTextCredential{
|
||||||
Scope: GLOBALScope,
|
Scope: GLOBALScope,
|
||||||
Id: id,
|
Id: id,
|
||||||
Secret: secret,
|
Secret: secretContent,
|
||||||
Description: description,
|
|
||||||
StaplerClass: SecretTextCredentialStaplerClass,
|
StaplerClass: SecretTextCredentialStaplerClass,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewKubeconfigCredential(id, content, description string) *KubeconfigCredential {
|
func NewKubeconfigCredential(secret *v1.Secret) *KubeconfigCredential {
|
||||||
|
id := secret.Name
|
||||||
|
secretContent := string(secret.Data[devopsv1alpha3.KubeConfigSecretKey])
|
||||||
|
|
||||||
credentialSource := KubeconfigSource{
|
credentialSource := KubeconfigSource{
|
||||||
StaplerClass: DirectKubeconfigCredentialStaperClass,
|
StaplerClass: DirectKubeconfigCredentialStaperClass,
|
||||||
Content: content,
|
Content: secretContent,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &KubeconfigCredential{
|
return &KubeconfigCredential{
|
||||||
Scope: GLOBALScope,
|
Scope: GLOBALScope,
|
||||||
Id: id,
|
Id: id,
|
||||||
Description: description,
|
|
||||||
KubeconfigSource: credentialSource,
|
KubeconfigSource: credentialSource,
|
||||||
StaplerClass: KubeconfigCredentialStaplerClass,
|
StaplerClass: KubeconfigCredentialStaplerClass,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Jenkins) GetCredentialInProject(projectId, id string, content bool) (*devops.Credential, error) {
|
func (j *Jenkins) GetCredentialInProject(projectId, id string) (*devops.Credential, error) {
|
||||||
responseStruct := &devops.Credential{}
|
responseStruct := &devops.Credential{}
|
||||||
|
|
||||||
domain := "_"
|
domain := "_"
|
||||||
@@ -169,54 +178,6 @@ func (j *Jenkins) GetCredentialInProject(projectId, id string, content bool) (*d
|
|||||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
||||||
}
|
}
|
||||||
responseStruct.Domain = domain
|
responseStruct.Domain = domain
|
||||||
if content {
|
|
||||||
|
|
||||||
}
|
|
||||||
contentString := ""
|
|
||||||
response, err = j.Requester.GetHtml(
|
|
||||||
fmt.Sprintf("/job/%s/credentials/store/folder/domain/%s/credential/%s/update", projectId, domain, id),
|
|
||||||
&contentString, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if response.StatusCode != http.StatusOK {
|
|
||||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
|
||||||
}
|
|
||||||
stringReader := strings.NewReader(contentString)
|
|
||||||
doc, err := goquery.NewDocumentFromReader(stringReader)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return nil, restful.NewError(http.StatusInternalServerError, err.Error())
|
|
||||||
}
|
|
||||||
switch responseStruct.Type {
|
|
||||||
case devops.CredentialTypeKubeConfig:
|
|
||||||
content := &devops.KubeconfigCredential{}
|
|
||||||
doc.Find("textarea[name*=content]").Each(func(i int, selection *goquery.Selection) {
|
|
||||||
value := selection.Text()
|
|
||||||
content.Content = value
|
|
||||||
})
|
|
||||||
responseStruct.KubeconfigCredential = content
|
|
||||||
case devops.CredentialTypeUsernamePassword:
|
|
||||||
content := &devops.UsernamePasswordCredential{}
|
|
||||||
doc.Find("input[name*=username]").Each(func(i int, selection *goquery.Selection) {
|
|
||||||
value, _ := selection.Attr("value")
|
|
||||||
content.Username = value
|
|
||||||
})
|
|
||||||
|
|
||||||
responseStruct.UsernamePasswordCredential = content
|
|
||||||
case devops.CredentialTypeSsh:
|
|
||||||
content := &devops.SshCredential{}
|
|
||||||
doc.Find("input[name*=username]").Each(func(i int, selection *goquery.Selection) {
|
|
||||||
value, _ := selection.Attr("value")
|
|
||||||
content.Username = value
|
|
||||||
})
|
|
||||||
|
|
||||||
doc.Find("textarea[name*=privateKey]").Each(func(i int, selection *goquery.Selection) {
|
|
||||||
value := selection.Text()
|
|
||||||
content.PrivateKey = value
|
|
||||||
})
|
|
||||||
responseStruct.SshCredential = content
|
|
||||||
}
|
|
||||||
return responseStruct, nil
|
return responseStruct, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,30 +204,23 @@ func (j *Jenkins) GetCredentialsInProject(projectId string) ([]*devops.Credentia
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Jenkins) CreateCredentialInProject(projectId string, credential *devops.Credential) (*string, error) {
|
func (j *Jenkins) CreateCredentialInProject(projectId string, credential *v1.Secret) (string, error) {
|
||||||
|
|
||||||
var request interface{}
|
var request interface{}
|
||||||
responseString := ""
|
responseString := ""
|
||||||
switch credential.Type {
|
switch credential.Type {
|
||||||
case devops.CredentialTypeUsernamePassword:
|
case devopsv1alpha3.SecretTypeBasicAuth:
|
||||||
request = NewUsernamePasswordCredential(credential.Id,
|
request = NewUsernamePasswordCredential(credential)
|
||||||
credential.UsernamePasswordCredential.Username, credential.UsernamePasswordCredential.Password,
|
case devopsv1alpha3.SecretTypeSSHAuth:
|
||||||
credential.Description)
|
request = NewSshCredential(credential)
|
||||||
|
case devopsv1alpha3.SecretTypeSecretText:
|
||||||
case devops.CredentialTypeSsh:
|
request = NewSecretTextCredential(credential)
|
||||||
request = NewSshCredential(credential.Id,
|
case devopsv1alpha3.SecretTypeKubeConfig:
|
||||||
credential.SshCredential.Username, credential.SshCredential.Passphrase,
|
request = NewKubeconfigCredential(credential)
|
||||||
credential.SshCredential.PrivateKey, credential.Description)
|
|
||||||
case devops.CredentialTypeSecretText:
|
|
||||||
request = NewSecretTextCredential(credential.Id,
|
|
||||||
credential.SecretTextCredential.Secret, credential.Description)
|
|
||||||
case devops.CredentialTypeKubeConfig:
|
|
||||||
request = NewKubeconfigCredential(credential.Id,
|
|
||||||
credential.KubeconfigCredential.Content, credential.Description)
|
|
||||||
default:
|
default:
|
||||||
err := fmt.Errorf("error unsupport credential type")
|
err := fmt.Errorf("error unsupport credential type")
|
||||||
klog.Errorf("%+v", err)
|
klog.Errorf("%+v", err)
|
||||||
return nil, restful.NewError(http.StatusBadRequest, err.Error())
|
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := j.Requester.Post(
|
response, err := j.Requester.Post(
|
||||||
@@ -277,65 +231,58 @@ func (j *Jenkins) CreateCredentialInProject(projectId string, credential *devops
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", err
|
||||||
}
|
}
|
||||||
if response.StatusCode != http.StatusOK {
|
if response.StatusCode != http.StatusOK {
|
||||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
return "", errors.New(strconv.Itoa(response.StatusCode))
|
||||||
}
|
}
|
||||||
return &credential.Id, nil
|
return credential.Name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Jenkins) UpdateCredentialInProject(projectId string, credential *devops.Credential) (*string, error) {
|
func (j *Jenkins) UpdateCredentialInProject(projectId string, credential *v1.Secret) (string, error) {
|
||||||
|
|
||||||
requestContent := ""
|
requestContent := ""
|
||||||
switch credential.Type {
|
switch credential.Type {
|
||||||
case devops.CredentialTypeUsernamePassword:
|
case devopsv1alpha3.SecretTypeBasicAuth:
|
||||||
requestStruct := NewUsernamePasswordCredential(credential.Id,
|
requestStruct := NewUsernamePasswordCredential(credential)
|
||||||
credential.UsernamePasswordCredential.Username, credential.UsernamePasswordCredential.Password,
|
|
||||||
credential.Description)
|
|
||||||
requestContent = makeJson(requestStruct)
|
requestContent = makeJson(requestStruct)
|
||||||
|
case devopsv1alpha3.SecretTypeSSHAuth:
|
||||||
case devops.CredentialTypeSsh:
|
requestStruct := NewSshCredential(credential)
|
||||||
requestStruct := NewSshCredential(credential.Id,
|
|
||||||
credential.SshCredential.Username, credential.SshCredential.Passphrase,
|
|
||||||
credential.SshCredential.PrivateKey, credential.Description)
|
|
||||||
requestContent = makeJson(requestStruct)
|
requestContent = makeJson(requestStruct)
|
||||||
case devops.CredentialTypeSecretText:
|
case devopsv1alpha3.SecretTypeSecretText:
|
||||||
requestStruct := NewSecretTextCredential(credential.Id,
|
requestStruct := NewSecretTextCredential(credential)
|
||||||
credential.SecretTextCredential.Secret, credential.Description)
|
|
||||||
requestContent = makeJson(requestStruct)
|
requestContent = makeJson(requestStruct)
|
||||||
case devops.CredentialTypeKubeConfig:
|
case devopsv1alpha3.SecretTypeKubeConfig:
|
||||||
requestStruct := NewKubeconfigCredential(credential.Id,
|
requestStruct := NewKubeconfigCredential(credential)
|
||||||
credential.KubeconfigCredential.Content, credential.Description)
|
|
||||||
requestContent = makeJson(requestStruct)
|
requestContent = makeJson(requestStruct)
|
||||||
default:
|
default:
|
||||||
err := fmt.Errorf("error unsupport credential type")
|
err := fmt.Errorf("error unsupport credential type")
|
||||||
klog.Errorf("%+v", err)
|
klog.Errorf("%+v", err)
|
||||||
return nil, restful.NewError(http.StatusBadRequest, err.Error())
|
return "", restful.NewError(http.StatusBadRequest, err.Error())
|
||||||
}
|
}
|
||||||
response, err := j.Requester.Post(
|
response, err := j.Requester.Post(
|
||||||
fmt.Sprintf("/job/%s/credentials/store/folder/domain/_/credential/%s/updateSubmit", projectId, credential.Id),
|
fmt.Sprintf("/job/%s/credentials/store/folder/domain/_/credential/%s/updateSubmit", projectId, credential.Name),
|
||||||
nil, nil, map[string]string{
|
nil, nil, map[string]string{
|
||||||
"json": requestContent,
|
"json": requestContent,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", err
|
||||||
}
|
}
|
||||||
if response.StatusCode != http.StatusOK {
|
if response.StatusCode != http.StatusOK {
|
||||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
return "", errors.New(strconv.Itoa(response.StatusCode))
|
||||||
}
|
}
|
||||||
return &credential.Id, nil
|
return credential.Name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Jenkins) DeleteCredentialInProject(projectId, id string) (*string, error) {
|
func (j *Jenkins) DeleteCredentialInProject(projectId, id string) (string, error) {
|
||||||
response, err := j.Requester.Post(
|
response, err := j.Requester.Post(
|
||||||
fmt.Sprintf("/job/%s/credentials/store/folder/domain/_/credential/%s/doDelete", projectId, id),
|
fmt.Sprintf("/job/%s/credentials/store/folder/domain/_/credential/%s/doDelete", projectId, id),
|
||||||
nil, nil, nil)
|
nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", err
|
||||||
}
|
}
|
||||||
if response.StatusCode != http.StatusOK {
|
if response.StatusCode != http.StatusOK {
|
||||||
return nil, errors.New(strconv.Itoa(response.StatusCode))
|
return "", errors.New(strconv.Itoa(response.StatusCode))
|
||||||
}
|
}
|
||||||
return &id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user