This is a huge commit, it does following things: (#1942)

1. Remove ks-iam standalone binary, move it to ks-apiserver
2. Generate all devops apis inside kubesphere repository, no need to
import s2ioperator.
3. Reorganize ldap code, make it more flexible to use.
This commit is contained in:
zryfish
2020-03-10 13:50:17 +08:00
committed by GitHub
parent 7270307b66
commit 641615b299
235 changed files with 5538 additions and 38064 deletions

View File

@@ -9,8 +9,7 @@ git:
depth: false
go:
- "1.12.x"
- "tip"
- "1.13.x"
env:
- GO111MODULE=on
cache:
@@ -23,11 +22,10 @@ before_script:
script:
- diff -u <(echo -n) <(gofmt -d ./pkg ./cmd ./tools)
- make openapi
- make all
before_install:
- go get -t -v ./...
- go mod vendor
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@@ -39,7 +39,7 @@ define ALL_HELP_INFO
# debugging tools like delve.
endef
.PHONY: all
all: test hypersphere ks-apiserver ks-apigateway ks-iam controller-manager
all: test hypersphere ks-apiserver ks-apigateway controller-manager
# Build ks-apiserver binary
ks-apiserver: fmt vet
@@ -49,10 +49,6 @@ ks-apiserver: fmt vet
ks-apigateway: fmt vet
hack/gobuild.sh cmd/ks-apigateway
# Build ks-iam binary
ks-iam: fmt vet
hack/gobuild.sh cmd/ks-iam
# Build controller-manager binary
controller-manager: fmt vet
hack/gobuild.sh cmd/controller-manager

View File

@@ -24,7 +24,27 @@ API rule violation: list_type_missing,k8s.io/apimachinery/pkg/apis/meta/v1,Table
API rule violation: list_type_missing,k8s.io/apimachinery/pkg/apis/meta/v1,TableRow,Cells
API rule violation: list_type_missing,k8s.io/apimachinery/pkg/apis/meta/v1,TableRow,Conditions
API rule violation: list_type_missing,k8s.io/apimachinery/pkg/apis/meta/v1,UpdateOptions,DryRun
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,ContainerConfig,Env
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,ContainerInfo,BuildVolumes
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,ContainerInfo,RuntimeArtifacts
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,Parameter,OptValues
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iAutoScale,Containers
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iBinaryList,Items
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iBuildResult,ImageRepoTags
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iBuilderList,Items
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iBuilderTemplateList,Items
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iBuilderTemplateSpec,ContainerInfo
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iBuilderTemplateSpec,Parameters
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,AddHost
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,BuildVolumes
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,DropCapabilities
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,Environment
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,Injections
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,NodeAffinityValues
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,RuntimeArtifacts
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,SecurityOpt
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iRunList,Items
API rule violation: list_type_missing,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,UserDefineTemplate,Parameters
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,APIResourceList,APIResources
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,Duration,Duration
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,InternalEvent,Object
@@ -32,4 +52,13 @@ API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,InternalEve
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,MicroTime,Time
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,StatusCause,Type
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,Time,Time
API rule violation: names_match,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,ContainerConfig,Env
API rule violation: names_match,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,ContainerConfig,Labels
API rule violation: names_match,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,DockerConfig,Endpoint
API rule violation: names_match,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iBinarySpec,MD5
API rule violation: names_match,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iBuilderTemplateSpec,Parameters
API rule violation: names_match,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,CGroupLimits
API rule violation: names_match,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,CallbackURL
API rule violation: names_match,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,ImageScriptsURL
API rule violation: names_match,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,ScriptsURL
API rule violation: names_match,kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1,S2iConfig,SourceURL

View File

@@ -18,122 +18,74 @@
package app
import (
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/controller/application"
"kubesphere.io/kubesphere/pkg/controller/destinationrule"
"kubesphere.io/kubesphere/pkg/controller/job"
"kubesphere.io/kubesphere/pkg/controller/s2ibinary"
"kubesphere.io/kubesphere/pkg/controller/s2irun"
"kubesphere.io/kubesphere/pkg/controller/storage/expansion"
//"kubesphere.io/kubesphere/pkg/controller/job"
"kubesphere.io/kubesphere/pkg/controller/virtualservice"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"sigs.k8s.io/controller-runtime/pkg/manager"
"time"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
applicationclientset "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned"
applicationinformers "github.com/kubernetes-sigs/application/pkg/client/informers/externalversions"
s2iclientset "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned"
s2iinformers "github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions"
istioclientset "istio.io/client-go/pkg/clientset/versioned"
istioinformers "istio.io/client-go/pkg/informers/externalversions"
kubesphereclientset "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
kubesphereinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
)
const defaultResync = 600 * time.Second
func AddControllers(
mgr manager.Manager,
client k8s.Client,
informerFactory informers.InformerFactory,
stopCh <-chan struct{}) error {
var log = logf.Log.WithName("controller-manager")
kubernetesInformer := informerFactory.KubernetesSharedInformerFactory()
istioInformer := informerFactory.IstioSharedInformerFactory()
kubesphereInformer := informerFactory.KubeSphereSharedInformerFactory()
applicationInformer := informerFactory.ApplicationSharedInformerFactory()
func AddControllers(mgr manager.Manager, cfg *rest.Config, stopCh <-chan struct{}) error {
kubeClient, err := kubernetes.NewForConfig(cfg)
if err != nil {
log.Error(err, "building kubernetes client failed")
}
istioclient, err := istioclientset.NewForConfig(cfg)
if err != nil {
log.Error(err, "create istio client failed")
return err
}
applicationClient, err := applicationclientset.NewForConfig(cfg)
if err != nil {
log.Error(err, "create application client failed")
return err
}
s2iclient, err := s2iclientset.NewForConfig(cfg)
if err != nil {
log.Error(err, "create s2i client failed")
return err
}
kubesphereclient, err := kubesphereclientset.NewForConfig(cfg)
if err != nil {
log.Error(err, "create kubesphere client failed")
return err
}
informerFactory := informers.NewSharedInformerFactory(kubeClient, defaultResync)
istioInformer := istioinformers.NewSharedInformerFactory(istioclient, defaultResync)
applicationInformer := applicationinformers.NewSharedInformerFactory(applicationClient, defaultResync)
s2iInformer := s2iinformers.NewSharedInformerFactory(s2iclient, defaultResync)
kubesphereInformer := kubesphereinformers.NewSharedInformerFactory(kubesphereclient, defaultResync)
vsController := virtualservice.NewVirtualServiceController(informerFactory.Core().V1().Services(),
vsController := virtualservice.NewVirtualServiceController(kubernetesInformer.Core().V1().Services(),
istioInformer.Networking().V1alpha3().VirtualServices(),
istioInformer.Networking().V1alpha3().DestinationRules(),
kubesphereInformer.Servicemesh().V1alpha2().Strategies(),
kubeClient,
istioclient,
kubesphereclient)
client.Kubernetes(),
client.Istio(),
client.KubeSphere())
drController := destinationrule.NewDestinationRuleController(informerFactory.Apps().V1().Deployments(),
drController := destinationrule.NewDestinationRuleController(kubernetesInformer.Apps().V1().Deployments(),
istioInformer.Networking().V1alpha3().DestinationRules(),
informerFactory.Core().V1().Services(),
kubernetesInformer.Core().V1().Services(),
kubesphereInformer.Servicemesh().V1alpha2().ServicePolicies(),
kubeClient,
istioclient,
kubesphereclient)
client.Kubernetes(),
client.Istio(),
client.KubeSphere())
apController := application.NewApplicationController(informerFactory.Core().V1().Services(),
informerFactory.Apps().V1().Deployments(),
informerFactory.Apps().V1().StatefulSets(),
apController := application.NewApplicationController(kubernetesInformer.Core().V1().Services(),
kubernetesInformer.Apps().V1().Deployments(),
kubernetesInformer.Apps().V1().StatefulSets(),
kubesphereInformer.Servicemesh().V1alpha2().Strategies(),
kubesphereInformer.Servicemesh().V1alpha2().ServicePolicies(),
applicationInformer.App().V1beta1().Applications(),
kubeClient,
applicationClient)
client.Kubernetes(),
client.Application())
jobController := job.NewJobController(informerFactory.Batch().V1().Jobs(), kubeClient)
jobController := job.NewJobController(kubernetesInformer.Batch().V1().Jobs(), client.Kubernetes())
s2iBinaryController := s2ibinary.NewController(kubesphereclient,
kubeClient,
s2iBinaryController := s2ibinary.NewController(client.KubeSphere(),
client.Kubernetes(),
kubesphereInformer.Devops().V1alpha1().S2iBinaries())
s2iRunController := s2irun.NewController(kubesphereclient, s2iclient, kubeClient,
s2iRunController := s2irun.NewS2iRunController(client.KubeSphere(),
client.Kubernetes(),
kubesphereInformer.Devops().V1alpha1().S2iBinaries(),
s2iInformer.Devops().V1alpha1().S2iRuns())
kubesphereInformer.Devops().V1alpha1().S2iRuns())
volumeExpansionController := expansion.NewVolumeExpansionController(
kubeClient,
informerFactory.Core().V1().PersistentVolumeClaims(),
informerFactory.Storage().V1().StorageClasses(),
informerFactory.Core().V1().Pods(),
informerFactory.Apps().V1().Deployments(),
informerFactory.Apps().V1().ReplicaSets(),
informerFactory.Apps().V1().StatefulSets())
kubesphereInformer.Start(stopCh)
istioInformer.Start(stopCh)
informerFactory.Start(stopCh)
applicationInformer.Start(stopCh)
s2iInformer.Start(stopCh)
client.Kubernetes(),
kubernetesInformer.Core().V1().PersistentVolumeClaims(),
kubernetesInformer.Storage().V1().StorageClasses(),
kubernetesInformer.Core().V1().Pods(),
kubernetesInformer.Apps().V1().Deployments(),
kubernetesInformer.Apps().V1().ReplicaSets(),
kubernetesInformer.Apps().V1().StatefulSets())
controllers := map[string]manager.Runnable{
"virtualservice-controller": vsController,
@@ -146,9 +98,8 @@ func AddControllers(mgr manager.Manager, cfg *rest.Config, stopCh <-chan struct{
}
for name, ctrl := range controllers {
err = mgr.Add(ctrl)
if err != nil {
log.Error(err, "add controller to manager failed", "name", name)
if err := mgr.Add(ctrl); err != nil {
klog.Error(err, "add controller to manager failed", "name", name)
return err
}
}

View File

@@ -6,9 +6,10 @@ import (
"k8s.io/client-go/tools/leaderelection"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/klog"
kubesphereconfig "kubesphere.io/kubesphere/pkg/server/config"
kubesphereconfig "kubesphere.io/kubesphere/pkg/apiserver/config"
"kubesphere.io/kubesphere/pkg/simple/client/devops/jenkins"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"kubesphere.io/kubesphere/pkg/simple/client/s3"
"strings"
@@ -20,6 +21,7 @@ type KubeSphereControllerManagerOptions struct {
DevopsOptions *jenkins.Options
S3Options *s3.Options
OpenPitrixOptions *openpitrix.Options
KubeSphereOptions *kubesphere.Options
LeaderElection *leaderelection.LeaderElectionConfig
}
@@ -30,6 +32,7 @@ func NewKubeSphereControllerManagerOptions() *KubeSphereControllerManagerOptions
DevopsOptions: jenkins.NewDevopsOptions(),
S3Options: s3.NewS3Options(),
OpenPitrixOptions: openpitrix.NewOptions(),
KubeSphereOptions: kubesphere.NewKubeSphereOptions(),
LeaderElection: &leaderelection.LeaderElectionConfig{
LeaseDuration: 30 * time.Second,
RenewDeadline: 15 * time.Second,
@@ -47,13 +50,13 @@ func (s *KubeSphereControllerManagerOptions) ApplyTo(conf *kubesphereconfig.Conf
s.OpenPitrixOptions.ApplyTo(conf.OpenPitrixOptions)
}
func (s *KubeSphereControllerManagerOptions) Flags(o *KubeSphereControllerManagerOptions) cliflag.NamedFlagSets {
func (s *KubeSphereControllerManagerOptions) Flags() cliflag.NamedFlagSets {
fss := cliflag.NamedFlagSets{}
s.KubernetesOptions.AddFlags(fss.FlagSet("kubernetes"), o.KubernetesOptions)
s.DevopsOptions.AddFlags(fss.FlagSet("devops"), o.DevopsOptions)
s.S3Options.AddFlags(fss.FlagSet("s3"), o.S3Options)
s.OpenPitrixOptions.AddFlags(fss.FlagSet("openpitrix"), o.OpenPitrixOptions)
s.KubernetesOptions.AddFlags(fss.FlagSet("kubernetes"), s.KubernetesOptions)
s.DevopsOptions.AddFlags(fss.FlagSet("devops"), s.DevopsOptions)
s.S3Options.AddFlags(fss.FlagSet("s3"), s.S3Options)
s.OpenPitrixOptions.AddFlags(fss.FlagSet("openpitrix"), s.OpenPitrixOptions)
fs := fss.FlagSet("leaderelection")
s.bindLeaderElectionFlags(s.LeaderElection, fs)

View File

@@ -32,10 +32,14 @@ import (
"k8s.io/klog"
"kubesphere.io/kubesphere/cmd/controller-manager/app/options"
"kubesphere.io/kubesphere/pkg/apis"
controllerconfig "kubesphere.io/kubesphere/pkg/apiserver/config"
"kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme"
"kubesphere.io/kubesphere/pkg/controller"
controllerconfig "kubesphere.io/kubesphere/pkg/server/config"
"kubesphere.io/kubesphere/pkg/simple/client"
"kubesphere.io/kubesphere/pkg/controller/namespace"
"kubesphere.io/kubesphere/pkg/controller/workspace"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
kclient "kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"kubesphere.io/kubesphere/pkg/utils/term"
"os"
"sigs.k8s.io/controller-runtime/pkg/manager"
@@ -44,20 +48,20 @@ import (
func NewControllerManagerCommand() *cobra.Command {
s := options.NewKubeSphereControllerManagerOptions()
conf, err := controllerconfig.TryLoadFromDisk()
if err == nil {
s = &options.KubeSphereControllerManagerOptions{
KubernetesOptions: conf.KubernetesOptions,
DevopsOptions: conf.DevopsOptions,
S3Options: conf.S3Options,
OpenPitrixOptions: conf.OpenPitrixOptions,
}
}
cmd := &cobra.Command{
Use: "controller-manager",
Long: `KubeSphere controller manager is a daemon that`,
Run: func(cmd *cobra.Command, args []string) {
err := controllerconfig.Load()
if err != nil {
klog.Fatal(err)
os.Exit(1)
}
s = Complete(s)
if errs := s.Validate(); len(errs) != 0 {
klog.Error(utilerrors.NewAggregate(errs))
os.Exit(1)
@@ -69,10 +73,8 @@ func NewControllerManagerCommand() *cobra.Command {
},
}
conf := loadConfFromFile()
fs := cmd.Flags()
namedFlagSets := s.Flags(conf)
namedFlagSets := s.Flags()
for _, f := range namedFlagSets.FlagSets {
fs.AddFlagSet(f)
@@ -87,68 +89,43 @@ func NewControllerManagerCommand() *cobra.Command {
return cmd
}
func Complete(s *options.KubeSphereControllerManagerOptions) *options.KubeSphereControllerManagerOptions {
conf := controllerconfig.Get()
conf.Apply(&controllerconfig.Config{
DevopsOptions: s.DevopsOptions,
KubernetesOptions: s.KubernetesOptions,
S3Options: s.S3Options,
OpenPitrixOptions: s.OpenPitrixOptions,
})
out := &options.KubeSphereControllerManagerOptions{
KubernetesOptions: conf.KubernetesOptions,
DevopsOptions: conf.DevopsOptions,
S3Options: conf.S3Options,
OpenPitrixOptions: conf.OpenPitrixOptions,
LeaderElection: s.LeaderElection,
}
return out
}
func CreateClientSet(conf *controllerconfig.Config, stopCh <-chan struct{}) error {
csop := &client.ClientSetOptions{}
csop.SetKubernetesOptions(conf.KubernetesOptions).
SetDevopsOptions(conf.DevopsOptions).
SetS3Options(conf.S3Options).
SetOpenPitrixOptions(conf.OpenPitrixOptions).
SetKubeSphereOptions(conf.KubeSphereOptions)
client.NewClientSetFactory(csop, stopCh)
return nil
}
func loadConfFromFile() *options.KubeSphereControllerManagerOptions {
err := controllerconfig.Load()
if err != nil {
klog.Fatalf("error happened while loading config file")
}
conf := controllerconfig.Get()
return &options.KubeSphereControllerManagerOptions{
KubernetesOptions: conf.KubernetesOptions,
DevopsOptions: conf.DevopsOptions,
S3Options: conf.S3Options,
OpenPitrixOptions: conf.OpenPitrixOptions,
}
}
func Run(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{}) error {
err := CreateClientSet(controllerconfig.Get(), stopCh)
kubernetesClient, err := k8s.NewKubernetesClient(s.KubernetesOptions)
if err != nil {
klog.Error(err)
klog.Errorf("Failed to create kubernetes clientset %v", err)
return err
}
config := client.ClientSets().K8s().Config()
kubesphereClient := kclient.NewKubeSphereClient(s.KubeSphereOptions)
openpitrixClient, err := openpitrix.NewClient(s.OpenPitrixOptions)
if err != nil {
klog.Errorf("Failed to create openpitrix client %v", err)
return err
}
/*
devopsClient, err := jenkins.NewDevopsClient(s.DevopsOptions)
if err != nil {
klog.Errorf("Failed to create devops client %v", err)
return err
}
s3Client, err := s3.NewS3Client(s.S3Options)
if err != nil {
klog.Errorf("Failed to create s3 client", err)
return err
}
*/
informerFactory := informers.NewInformerFactories(kubernetesClient.Kubernetes(), kubernetesClient.KubeSphere(), kubernetesClient.Istio(), kubernetesClient.Application())
informerFactory.Start(stopCh)
run := func(ctx context.Context) {
klog.V(0).Info("setting up manager")
mgr, err := manager.New(config, manager.Options{})
mgr, err := manager.New(kubernetesClient.Config(), manager.Options{})
if err != nil {
klog.Fatalf("unable to set up overall controller manager: %v", err)
}
@@ -159,16 +136,22 @@ func Run(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{})
}
klog.V(0).Info("Setting up controllers")
if err := controller.AddToManager(mgr); err != nil {
err = workspace.Add(mgr, kubesphereClient)
if err != nil {
klog.Fatal("Unable to create workspace controller")
}
err = namespace.Add(mgr, openpitrixClient)
if err != nil {
klog.Fatal("Unable to create namespace controller")
}
if err := AddControllers(mgr, kubernetesClient, informerFactory, stopCh); err != nil {
klog.Fatalf("unable to register controllers to the manager: %v", err)
}
if err := AddControllers(mgr, config, stopCh); err != nil {
klog.Fatalf("unable to register controllers to the manager: %v", err)
}
klog.V(0).Info("Starting the Cmd.")
if err := mgr.Start(stopCh); err != nil {
klog.V(0).Info("Starting the controllers.")
if err = mgr.Start(stopCh); err != nil {
klog.Fatalf("unable to run the manager: %v", err)
}
@@ -197,8 +180,8 @@ func Run(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{})
lock, err := resourcelock.New(resourcelock.LeasesResourceLock,
"kubesphere-system",
"ks-controller-manager",
client.ClientSets().K8s().Kubernetes().CoreV1(),
client.ClientSets().K8s().Kubernetes().CoordinationV1(),
kubernetesClient.Kubernetes().CoreV1(),
kubernetesClient.Kubernetes().CoordinationV1(),
resourcelock.ResourceLockConfig{
Identity: id,
EventRecorder: record.NewBroadcaster().NewRecorder(scheme.Scheme, v1.EventSource{

View File

@@ -10,7 +10,6 @@ import (
controllermanager "kubesphere.io/kubesphere/cmd/controller-manager/app"
ksapigateway "kubesphere.io/kubesphere/cmd/ks-apigateway/app"
ksapiserver "kubesphere.io/kubesphere/cmd/ks-apiserver/app"
ksaiam "kubesphere.io/kubesphere/cmd/ks-iam/app"
"os"
)
@@ -46,13 +45,11 @@ func commandFor(basename string, defaultCommand *cobra.Command, commands []func(
func NewHyperSphereCommand() (*cobra.Command, []func() *cobra.Command) {
apiserver := func() *cobra.Command { return ksapiserver.NewAPIServerCommand() }
controllermanager := func() *cobra.Command { return controllermanager.NewControllerManagerCommand() }
iam := func() *cobra.Command { return ksaiam.NewAPIServerCommand() }
apigateway := func() *cobra.Command { return ksapigateway.NewAPIGatewayCommand() }
commandFns := []func() *cobra.Command{
apiserver,
controllermanager,
iam,
apigateway,
}

View File

@@ -5,8 +5,6 @@ import (
"github.com/mholt/caddy/caddy/caddymain"
"github.com/mholt/caddy/caddyhttp/httpserver"
"github.com/spf13/cobra"
apiserverconfig "kubesphere.io/kubesphere/pkg/server/config"
"kubesphere.io/kubesphere/pkg/simple/client"
"kubesphere.io/kubesphere/pkg/utils/signals"
"kubesphere.io/kubesphere/pkg/apigateway"
@@ -21,12 +19,6 @@ for proxy request to the right backend. API Gateway also proxy
Kubernetes API Server for KubeSphere authorization purpose.
`,
RunE: func(cmd *cobra.Command, args []string) error {
err := apiserverconfig.Load()
if err != nil {
return err
}
apigateway.RegisterPlugins()
return Run(signals.SetupSignalHandler())
@@ -39,11 +31,6 @@ Kubernetes API Server for KubeSphere authorization purpose.
}
func Run(stopCh <-chan struct{}) error {
csop := &client.ClientSetOptions{}
csop.SetKubernetesOptions(apiserverconfig.Get().KubernetesOptions)
client.NewClientSetFactory(csop, stopCh)
httpserver.RegisterDevDirective("authenticate", "jwt")
httpserver.RegisterDevDirective("authentication", "jwt")
httpserver.RegisterDevDirective("swagger", "jwt")

View File

@@ -1,12 +1,18 @@
package options
import (
"crypto/tls"
"flag"
"fmt"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api/iam"
"kubesphere.io/kubesphere/pkg/apiserver"
genericoptions "kubesphere.io/kubesphere/pkg/server/options"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
"kubesphere.io/kubesphere/pkg/simple/client/devops/jenkins"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
esclient "kubesphere.io/kubesphere/pkg/simple/client/logging/elasticsearch"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring/prometheus"
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
@@ -14,6 +20,7 @@ import (
"kubesphere.io/kubesphere/pkg/simple/client/s3"
"kubesphere.io/kubesphere/pkg/simple/client/servicemesh"
"kubesphere.io/kubesphere/pkg/simple/client/sonarqube"
"net/http"
"strings"
)
@@ -29,6 +36,9 @@ type ServerRunOptions struct {
S3Options *s3.Options
OpenPitrixOptions *openpitrix.Options
LoggingOptions *esclient.Options
LdapOptions *ldap.Options
CacheOptions *cache.Options
AuthenticateOptions *iam.AuthenticationOptions
}
func NewServerRunOptions() *ServerRunOptions {
@@ -44,22 +54,28 @@ func NewServerRunOptions() *ServerRunOptions {
S3Options: s3.NewS3Options(),
OpenPitrixOptions: openpitrix.NewOptions(),
LoggingOptions: esclient.NewElasticSearchOptions(),
LdapOptions: ldap.NewOptions(),
CacheOptions: cache.NewRedisOptions(),
AuthenticateOptions: iam.NewAuthenticateOptions(),
}
return &s
}
func (s *ServerRunOptions) Flags(c *ServerRunOptions) (fss cliflag.NamedFlagSets) {
s.GenericServerRunOptions.AddFlags(fss.FlagSet("generic"), c.GenericServerRunOptions)
s.KubernetesOptions.AddFlags(fss.FlagSet("kubernetes"), c.KubernetesOptions)
s.MySQLOptions.AddFlags(fss.FlagSet("mysql"), c.MySQLOptions)
s.DevopsOptions.AddFlags(fss.FlagSet("devops"), c.DevopsOptions)
s.SonarQubeOptions.AddFlags(fss.FlagSet("sonarqube"), c.SonarQubeOptions)
s.S3Options.AddFlags(fss.FlagSet("s3"), c.S3Options)
s.OpenPitrixOptions.AddFlags(fss.FlagSet("openpitrix"), c.OpenPitrixOptions)
s.ServiceMeshOptions.AddFlags(fss.FlagSet("servicemesh"), c.ServiceMeshOptions)
s.MonitoringOptions.AddFlags(fss.FlagSet("monitoring"), c.MonitoringOptions)
s.LoggingOptions.AddFlags(fss.FlagSet("logging"), c.LoggingOptions)
func (s *ServerRunOptions) Flags() (fss cliflag.NamedFlagSets) {
s.GenericServerRunOptions.AddFlags(fss.FlagSet("generic"), s.GenericServerRunOptions)
s.KubernetesOptions.AddFlags(fss.FlagSet("kubernetes"), s.KubernetesOptions)
s.AuthenticateOptions.AddFlags(fss.FlagSet("authenticate"), s.AuthenticateOptions)
s.MySQLOptions.AddFlags(fss.FlagSet("mysql"), s.MySQLOptions)
s.DevopsOptions.AddFlags(fss.FlagSet("devops"), s.DevopsOptions)
s.SonarQubeOptions.AddFlags(fss.FlagSet("sonarqube"), s.SonarQubeOptions)
s.LdapOptions.AddFlags(fss.FlagSet("ldap"), s.LdapOptions)
s.CacheOptions.AddFlags(fss.FlagSet("cache"), s.CacheOptions)
s.S3Options.AddFlags(fss.FlagSet("s3"), s.S3Options)
s.OpenPitrixOptions.AddFlags(fss.FlagSet("openpitrix"), s.OpenPitrixOptions)
s.ServiceMeshOptions.AddFlags(fss.FlagSet("servicemesh"), s.ServiceMeshOptions)
s.MonitoringOptions.AddFlags(fss.FlagSet("monitoring"), s.MonitoringOptions)
s.LoggingOptions.AddFlags(fss.FlagSet("logging"), s.LoggingOptions)
fs := fss.FlagSet("klog")
local := flag.NewFlagSet("klog", flag.ExitOnError)
@@ -71,3 +87,62 @@ func (s *ServerRunOptions) Flags(c *ServerRunOptions) (fss cliflag.NamedFlagSets
return fss
}
func (s *ServerRunOptions) NewAPIServer(stopCh <-chan struct{}) (*apiserver.APIServer, error) {
kubernetesClient, err := k8s.NewKubernetesClient(s.KubernetesOptions)
if err != nil {
return nil, err
}
monitoringClient := prometheus.NewPrometheus(s.MonitoringOptions)
loggingClient, err := esclient.NewElasticsearch(s.LoggingOptions)
if err != nil {
return nil, err
}
s3Client, err := s3.NewS3Client(s.S3Options)
if err != nil {
return nil, err
}
devopsClient, err := jenkins.NewDevopsClient(s.DevopsOptions)
if err != nil {
return nil, err
}
ldapClient, err := ldap.NewLdapClient(s.LdapOptions, stopCh)
if err != nil {
return nil, err
}
cacheClient, err := cache.NewRedisClient(s.CacheOptions, stopCh)
if err != nil {
return nil, err
}
server := &http.Server{
Addr: fmt.Sprintf(":%d", s.GenericServerRunOptions.InsecurePort),
}
if s.GenericServerRunOptions.SecurePort != 0 {
certificate, err := tls.LoadX509KeyPair(s.GenericServerRunOptions.TlsCertFile, s.GenericServerRunOptions.TlsPrivateKey)
if err != nil {
return nil, err
}
server.TLSConfig.Certificates = []tls.Certificate{certificate}
}
apiServer := &apiserver.APIServer{
Server: server,
KubernetesClient: kubernetesClient,
MonitoringClient: monitoringClient,
LoggingClient: loggingClient,
S3Client: s3Client,
DevopsClient: devopsClient,
LdapClient: ldapClient,
CacheClient: cacheClient,
}
return apiServer, nil
}

View File

@@ -5,6 +5,7 @@ package options
func (s *ServerRunOptions) Validate() []error {
var errors []error
errors = append(errors, s.GenericServerRunOptions.Validate()...)
errors = append(errors, s.DevopsOptions.Validate()...)
errors = append(errors, s.KubernetesOptions.Validate()...)
errors = append(errors, s.MySQLOptions.Validate()...)

View File

@@ -21,31 +21,35 @@ import (
"fmt"
kconfig "github.com/kiali/kiali/config"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime/schema"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/klog"
"kubesphere.io/kubesphere/cmd/ks-apiserver/app/options"
"kubesphere.io/kubesphere/pkg/apiserver"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
apiserverconfig "kubesphere.io/kubesphere/pkg/apiserver/config"
"kubesphere.io/kubesphere/pkg/apiserver/servicemesh/tracing"
kinformers "kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/kapis"
"kubesphere.io/kubesphere/pkg/server"
apiserverconfig "kubesphere.io/kubesphere/pkg/server/config"
"kubesphere.io/kubesphere/pkg/server/filter"
"kubesphere.io/kubesphere/pkg/simple/client"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"kubesphere.io/kubesphere/pkg/simple/client/s3"
"kubesphere.io/kubesphere/pkg/utils/signals"
"kubesphere.io/kubesphere/pkg/utils/term"
"net/http"
)
func NewAPIServerCommand() *cobra.Command {
s := options.NewServerRunOptions()
// Load configuration from file
conf, err := apiserverconfig.TryLoadFromDisk()
if err == nil {
s = &options.ServerRunOptions{
KubernetesOptions: conf.KubernetesOptions,
DevopsOptions: conf.DevopsOptions,
SonarQubeOptions: conf.SonarQubeOptions,
ServiceMeshOptions: conf.ServiceMeshOptions,
MySQLOptions: conf.MySQLOptions,
MonitoringOptions: conf.MonitoringOptions,
S3Options: conf.S3Options,
OpenPitrixOptions: conf.OpenPitrixOptions,
LoggingOptions: conf.LoggingOptions,
AuthenticateOptions: conf.AuthenticateOptions,
}
}
cmd := &cobra.Command{
Use: "ks-apiserver",
Long: `The KubeSphere API server validates and configures data for the api objects.
@@ -60,11 +64,8 @@ cluster's shared state through which all other components interact.`,
},
}
configOptions := load()
fs := cmd.Flags()
namedFlagSets := s.Flags(configOptions)
namedFlagSets := s.Flags()
for _, f := range namedFlagSets.FlagSets {
fs.AddFlagSet(f)
}
@@ -80,24 +81,19 @@ cluster's shared state through which all other components interact.`,
func Run(s *options.ServerRunOptions, stopCh <-chan struct{}) error {
err := CreateClientSet(apiserverconfig.Get(), stopCh)
if err != nil {
return err
}
err = WaitForResourceSync(stopCh)
if err != nil {
return err
}
initializeServicemeshConfig(s)
err = CreateAPIServer(s)
apiserver, err := s.NewAPIServer(stopCh)
if err != nil {
return err
}
return nil
err = apiserver.PrepareRun()
if err != nil {
return nil
}
return apiserver.Run(stopCh)
}
func initializeServicemeshConfig(s *options.ServerRunOptions) {
@@ -119,234 +115,3 @@ func initializeServicemeshConfig(s *options.ServerRunOptions) {
kconfig.Set(config)
}
//
func CreateAPIServer(s *options.ServerRunOptions, stopCh <-chan struct{}) error {
var err error
deps := createDeps(s, stopCh)
apiserver := apiserver.New(deps)
container := runtime.Container
container.DoNotRecover(false)
container.Filter(filter.Logging)
container.RecoverHandler(server.LogStackOnRecover)
kapis.InstallAPIs(container)
// install config api
apiserverconfig.InstallAPI(container)
if s.GenericServerRunOptions.InsecurePort != 0 {
err = http.ListenAndServe(fmt.Sprintf("%s:%d", s.GenericServerRunOptions.BindAddress, s.GenericServerRunOptions.InsecurePort), container)
if err == nil {
klog.V(0).Infof("Server listening on insecure port %d.", s.GenericServerRunOptions.InsecurePort)
}
}
if s.GenericServerRunOptions.SecurePort != 0 && len(s.GenericServerRunOptions.TlsCertFile) > 0 && len(s.GenericServerRunOptions.TlsPrivateKey) > 0 {
err = http.ListenAndServeTLS(fmt.Sprintf("%s:%d", s.GenericServerRunOptions.BindAddress, s.GenericServerRunOptions.SecurePort), s.GenericServerRunOptions.TlsCertFile, s.GenericServerRunOptions.TlsPrivateKey, container)
if err == nil {
klog.V(0).Infof("Server listening on secure port %d.", s.GenericServerRunOptions.SecurePort)
}
}
return err
}
func createDeps(s *options.ServerRunOptions, stopCh <-chan struct{}) *apiserver.Dependencies {
deps := &apiserver.Dependencies{}
if s.KubernetesOptions == nil || s.KubernetesOptions.KubeConfig == "" {
klog.Warning("kubeconfig not provided, will use in-cluster config")
}
var err error
deps.KubeClient, err = k8s.NewKubernetesClient(s.KubernetesOptions)
if err != nil {
klog.Fatalf("error happened when initializing kubernetes client, %v", err)
}
if s.S3Options != nil && s.S3Options.Endpoint != "" {
deps.S3, err = s3.NewS3Client(s.S3Options)
if err != nil {
klog.Fatalf("error initializing s3 client, %v", err)
}
}
if s.OpenPitrixOptions != nil && !s.OpenPitrixOptions.IsEmpty() {
deps.OpenPitrix, err = openpitrix.NewClient(s.OpenPitrixOptions)
if err != nil {
klog.Fatalf("error happened when initializing openpitrix client, %v", err)
}
}
return deps
}
func WaitForResourceSync(stopCh <-chan struct{}) error {
klog.V(0).Info("Start cache objects")
discoveryClient := client.ClientSets().K8s().Discovery()
apiResourcesList, err := discoveryClient.ServerResources()
if err != nil {
return err
}
isResourceExists := func(resource schema.GroupVersionResource) bool {
for _, apiResource := range apiResourcesList {
if apiResource.GroupVersion == resource.GroupVersion().String() {
for _, rsc := range apiResource.APIResources {
if rsc.Name == resource.Resource {
return true
}
}
}
}
return false
}
informerFactory := kinformers.NewInformerFactories(client.ClientSets().K8s().Kubernetes(), client.ClientSets().K8s().KubeSphere(), client.ClientSets().K8s().S2i(),
client.ClientSets().K8s().Application())
// resources we have to create informer first
k8sGVRs := []schema.GroupVersionResource{
{Group: "", Version: "v1", Resource: "namespaces"},
{Group: "", Version: "v1", Resource: "nodes"},
{Group: "", Version: "v1", Resource: "resourcequotas"},
{Group: "", Version: "v1", Resource: "pods"},
{Group: "", Version: "v1", Resource: "services"},
{Group: "", Version: "v1", Resource: "persistentvolumeclaims"},
{Group: "", Version: "v1", Resource: "secrets"},
{Group: "", Version: "v1", Resource: "configmaps"},
{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "roles"},
{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "rolebindings"},
{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "clusterroles"},
{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "clusterrolebindings"},
{Group: "apps", Version: "v1", Resource: "deployments"},
{Group: "apps", Version: "v1", Resource: "daemonsets"},
{Group: "apps", Version: "v1", Resource: "replicasets"},
{Group: "apps", Version: "v1", Resource: "statefulsets"},
{Group: "apps", Version: "v1", Resource: "controllerrevisions"},
{Group: "storage.k8s.io", Version: "v1", Resource: "storageclasses"},
{Group: "batch", Version: "v1", Resource: "jobs"},
{Group: "batch", Version: "v1beta1", Resource: "cronjobs"},
{Group: "extensions", Version: "v1beta1", Resource: "ingresses"},
{Group: "autoscaling", Version: "v2beta2", Resource: "horizontalpodautoscalers"},
}
for _, gvr := range k8sGVRs {
if !isResourceExists(gvr) {
klog.Warningf("resource %s not exists in the cluster", gvr)
} else {
_, err := informerFactory.KubernetesSharedInformerFactory().ForResource(gvr)
if err != nil {
klog.Errorf("cannot create informer for %s", gvr)
return err
}
}
}
informerFactory.KubernetesSharedInformerFactory().Start(stopCh)
informerFactory.KubernetesSharedInformerFactory().WaitForCacheSync(stopCh)
s2iInformerFactory := informerFactory.S2iSharedInformerFactory()
s2iGVRs := []schema.GroupVersionResource{
{Group: "devops.kubesphere.io", Version: "v1alpha1", Resource: "s2ibuildertemplates"},
{Group: "devops.kubesphere.io", Version: "v1alpha1", Resource: "s2iruns"},
{Group: "devops.kubesphere.io", Version: "v1alpha1", Resource: "s2ibuilders"},
}
for _, gvr := range s2iGVRs {
if !isResourceExists(gvr) {
klog.Warningf("resource %s not exists in the cluster", gvr)
} else {
_, err := s2iInformerFactory.ForResource(gvr)
if err != nil {
return err
}
}
}
s2iInformerFactory.Start(stopCh)
s2iInformerFactory.WaitForCacheSync(stopCh)
ksInformerFactory := informerFactory.KubeSphereSharedInformerFactory()
ksGVRs := []schema.GroupVersionResource{
{Group: "tenant.kubesphere.io", Version: "v1alpha1", Resource: "workspaces"},
{Group: "devops.kubesphere.io", Version: "v1alpha1", Resource: "s2ibinaries"},
{Group: "servicemesh.kubesphere.io", Version: "v1alpha2", Resource: "strategies"},
{Group: "servicemesh.kubesphere.io", Version: "v1alpha2", Resource: "servicepolicies"},
}
for _, gvr := range ksGVRs {
if !isResourceExists(gvr) {
klog.Warningf("resource %s not exists in the cluster", gvr)
} else {
_, err := ksInformerFactory.ForResource(gvr)
if err != nil {
return err
}
}
}
ksInformerFactory.Start(stopCh)
ksInformerFactory.WaitForCacheSync(stopCh)
appInformerFactory := informerFactory.ApplicationSharedInformerFactory()
appGVRs := []schema.GroupVersionResource{
{Group: "app.k8s.io", Version: "v1beta1", Resource: "applications"},
}
for _, gvr := range appGVRs {
if !isResourceExists(gvr) {
klog.Warningf("resource %s not exists in the cluster", gvr)
} else {
_, err := appInformerFactory.ForResource(gvr)
if err != nil {
return err
}
}
}
appInformerFactory.Start(stopCh)
appInformerFactory.WaitForCacheSync(stopCh)
klog.V(0).Info("Finished caching objects")
return nil
}
// load options from config file
func load() *options.ServerRunOptions {
conf := apiserverconfig.Get()
return &options.ServerRunOptions{
KubernetesOptions: conf.KubernetesOptions,
DevopsOptions: conf.DevopsOptions,
SonarQubeOptions: conf.SonarQubeOptions,
ServiceMeshOptions: conf.ServiceMeshOptions,
MySQLOptions: conf.MySQLOptions,
MonitoringOptions: conf.MonitoringOptions,
S3Options: conf.S3Options,
OpenPitrixOptions: conf.OpenPitrixOptions,
LoggingOptions: conf.LoggingOptions,
}
}
func initConfigz() error {
return nil
}

View File

@@ -1,32 +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 main
import (
"kubesphere.io/kubesphere/cmd/ks-iam/app"
"log"
)
func main() {
cmd := app.NewAPIServerCommand()
if err := cmd.Execute(); err != nil {
log.Fatalln(err)
}
}

View File

@@ -1,86 +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 options
import (
"flag"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/klog"
genericoptions "kubesphere.io/kubesphere/pkg/server/options"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
"strings"
"time"
)
type ServerRunOptions struct {
GenericServerRunOptions *genericoptions.ServerRunOptions
KubernetesOptions *k8s.KubernetesOptions
LdapOptions *ldap.Options
RedisOptions *cache.Options
MySQLOptions *mysql.Options
AdminEmail string
AdminPassword string
TokenIdleTimeout time.Duration
JWTSecret string
AuthRateLimit string
EnableMultiLogin bool
GenerateKubeConfig bool
}
func NewServerRunOptions() *ServerRunOptions {
s := &ServerRunOptions{
GenericServerRunOptions: genericoptions.NewServerRunOptions(),
KubernetesOptions: k8s.NewKubernetesOptions(),
LdapOptions: ldap.NewOptions(),
MySQLOptions: mysql.NewMySQLOptions(),
RedisOptions: cache.NewRedisOptions(),
}
return s
}
func (s *ServerRunOptions) Flags(conf *ServerRunOptions) (fss cliflag.NamedFlagSets) {
fs := fss.FlagSet("generic")
s.GenericServerRunOptions.AddFlags(fs, conf.GenericServerRunOptions)
fs.StringVar(&s.AdminEmail, "admin-email", "admin@kubesphere.io", "default administrator's email")
fs.StringVar(&s.AdminPassword, "admin-password", "passw0rd", "default administrator's password")
fs.DurationVar(&s.TokenIdleTimeout, "token-idle-timeout", 30*time.Minute, "tokens that are idle beyond that time will expire,0s means the token has no expiration time. valid time units are \"ns\",\"us\",\"ms\",\"s\",\"m\",\"h\"")
fs.StringVar(&s.JWTSecret, "jwt-secret", "", "jwt secret")
fs.StringVar(&s.AuthRateLimit, "auth-rate-limit", "5/30m", "specifies the maximum number of authentication attempts permitted and time interval,valid time units are \"s\",\"m\",\"h\"")
fs.BoolVar(&s.EnableMultiLogin, "enable-multi-login", false, "allow one account to have multiple sessions")
fs.BoolVar(&s.GenerateKubeConfig, "generate-kubeconfig", true, "generate kubeconfig for new users, kubeconfig is required in devops pipeline, set to false if you don't need devops.")
s.KubernetesOptions.AddFlags(fss.FlagSet("kubernetes"), conf.KubernetesOptions)
s.LdapOptions.AddFlags(fss.FlagSet("ldap"), conf.LdapOptions)
s.RedisOptions.AddFlags(fss.FlagSet("redis"), conf.RedisOptions)
s.MySQLOptions.AddFlags(fss.FlagSet("mysql"), conf.MySQLOptions)
kfs := fss.FlagSet("klog")
local := flag.NewFlagSet("klog", flag.ExitOnError)
klog.InitFlags(local)
local.VisitAll(func(fl *flag.Flag) {
fl.Name = strings.Replace(fl.Name, "_", "-", -1)
kfs.AddGoFlag(fl)
})
return fss
}

View File

@@ -1,11 +0,0 @@
package options
func (s *ServerRunOptions) Validate() []error {
errs := []error{}
errs = append(errs, s.KubernetesOptions.Validate()...)
errs = append(errs, s.GenericServerRunOptions.Validate()...)
errs = append(errs, s.LdapOptions.Validate()...)
return errs
}

View File

@@ -1,156 +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 app
import (
"fmt"
"github.com/spf13/cobra"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/klog"
"kubesphere.io/kubesphere/cmd/ks-iam/app/options"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/kapis"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/server"
apiserverconfig "kubesphere.io/kubesphere/pkg/server/config"
"kubesphere.io/kubesphere/pkg/server/filter"
"kubesphere.io/kubesphere/pkg/simple/client"
"kubesphere.io/kubesphere/pkg/utils/jwtutil"
"kubesphere.io/kubesphere/pkg/utils/signals"
"kubesphere.io/kubesphere/pkg/utils/term"
"net/http"
)
func NewAPIServerCommand() *cobra.Command {
s := options.NewServerRunOptions()
cmd := &cobra.Command{
Use: "ks-iam",
Long: `The KubeSphere account server validates and configures data
for the api objects. The API Server services REST operations and provides the frontend to the
cluster's shared state through which all other components interact.`,
RunE: func(cmd *cobra.Command, args []string) error {
err := apiserverconfig.Load()
if err != nil {
return err
}
if errs := s.Validate(); len(errs) != 0 {
return utilerrors.NewAggregate(errs)
}
return Run(s, signals.SetupSignalHandler())
},
}
conf := loadFromFile()
fs := cmd.Flags()
namedFlagSets := s.Flags(conf)
for _, f := range namedFlagSets.FlagSets {
fs.AddFlagSet(f)
}
usageFmt := "Usage:\n %s\n"
cols, _, _ := term.TerminalSize(cmd.OutOrStdout())
cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
fmt.Fprintf(cmd.OutOrStdout(), "%s\n\n"+usageFmt, cmd.Long, cmd.UseLine())
cliflag.PrintSections(cmd.OutOrStdout(), namedFlagSets, cols)
})
return cmd
}
func Run(s *options.ServerRunOptions, stopChan <-chan struct{}) error {
csop := client.NewClientSetOptions()
csop.SetKubernetesOptions(s.KubernetesOptions).
SetLdapOptions(s.LdapOptions).
SetRedisOptions(s.RedisOptions).
SetMySQLOptions(s.MySQLOptions)
client.NewClientSetFactory(csop, stopChan)
waitForResourceSync(stopChan)
err := iam.Init(s.AdminEmail, s.AdminPassword, s.AuthRateLimit, s.TokenIdleTimeout, s.EnableMultiLogin, s.GenerateKubeConfig)
jwtutil.Setup(s.JWTSecret)
if err != nil {
return err
}
container := runtime.Container
container.Filter(filter.Logging)
container.DoNotRecover(false)
container.RecoverHandler(server.LogStackOnRecover)
kapis.InstallAuthorizationAPIs(container)
if s.GenericServerRunOptions.InsecurePort != 0 {
klog.Infof("Server listening on %s:%d ", s.GenericServerRunOptions.BindAddress, s.GenericServerRunOptions.InsecurePort)
err = http.ListenAndServe(fmt.Sprintf("%s:%d", s.GenericServerRunOptions.BindAddress, s.GenericServerRunOptions.InsecurePort), container)
}
if s.GenericServerRunOptions.SecurePort != 0 && len(s.GenericServerRunOptions.TlsCertFile) > 0 && len(s.GenericServerRunOptions.TlsPrivateKey) > 0 {
klog.Infof("Server listening on %s:%d", s.GenericServerRunOptions.BindAddress, s.GenericServerRunOptions.SecurePort)
err = http.ListenAndServeTLS(fmt.Sprintf("%s:%d", s.GenericServerRunOptions.BindAddress, s.GenericServerRunOptions.SecurePort), s.GenericServerRunOptions.TlsCertFile, s.GenericServerRunOptions.TlsPrivateKey, container)
}
return err
}
func loadFromFile() *options.ServerRunOptions {
err := apiserverconfig.Load()
if err != nil {
klog.Fatal(err)
}
conf := apiserverconfig.Get()
return &options.ServerRunOptions{
KubernetesOptions: conf.KubernetesOptions,
LdapOptions: conf.LdapOptions,
RedisOptions: conf.RedisOptions,
MySQLOptions: conf.MySQLOptions,
}
}
func waitForResourceSync(stopCh <-chan struct{}) {
informerFactory := informers.SharedInformerFactory()
informerFactory.Rbac().V1().Roles().Lister()
informerFactory.Rbac().V1().RoleBindings().Lister()
informerFactory.Rbac().V1().ClusterRoles().Lister()
informerFactory.Rbac().V1().ClusterRoleBindings().Lister()
informerFactory.Core().V1().Namespaces().Lister()
informerFactory.Start(stopCh)
informerFactory.WaitForCacheSync(stopCh)
ksInformerFactory := informers.KsSharedInformerFactory()
ksInformerFactory.Tenant().V1alpha1().Workspaces().Lister()
ksInformerFactory.Start(stopCh)
ksInformerFactory.WaitForCacheSync(stopCh)
}

View File

@@ -0,0 +1,578 @@
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: (devel)
creationTimestamp: null
name: s2ibuilders.devops.kubesphere.io
spec:
additionalPrinterColumns:
- JSONPath: .status.runCount
name: RunCount
type: integer
- JSONPath: .status.lastRunState
name: LastRunState
type: string
- JSONPath: .status.lastRunName
name: LastRunName
type: string
- JSONPath: .status.lastRunStartTime
name: LastRunStartTime
type: date
group: devops.kubesphere.io
names:
kind: S2iBuilder
listKind: S2iBuilderList
plural: s2ibuilders
shortNames:
- s2ib
singular: s2ibuilder
scope: Namespaced
subresources:
status: {}
validation:
openAPIV3Schema:
description: S2iBuilder is the Schema for the s2ibuilders API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: S2iBuilderSpec defines the desired state of S2iBuilder
properties:
config:
description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
Important: Run "make" to regenerate code after modifying this file'
properties:
addHost:
description: AddHost Add a line to /etc/hosts for test purpose or
private use in LAN. Its format is host:IP,muliple hosts can be
added by using multiple --add-host
items:
type: string
type: array
asDockerfile:
description: AsDockerfile indicates the path where the Dockerfile
should be written instead of building a new image.
type: string
assembleUser:
description: AssembleUser specifies the user to run the assemble
script in container
type: string
blockOnBuild:
description: BlockOnBuild prevents s2i from performing a docker
build operation if one is necessary to execute ONBUILD commands,
or to layer source code into the container for images that don't
have a tar binary available, if the image contains ONBUILD commands
that would be executed.
type: boolean
branchExpression:
description: Regular expressions, ignoring names that do not match
the provided regular expression
type: string
buildVolumes:
description: BuildVolumes specifies a list of volumes to mount to
container running the build.
items:
type: string
type: array
builderBaseImageVersion:
description: BuilderBaseImageVersion provides optional version information
about the builder base image.
type: string
builderImage:
description: BuilderImage describes which image is used for building
the result images.
type: string
builderImageVersion:
description: BuilderImageVersion provides optional version information
about the builder image.
type: string
builderPullPolicy:
description: BuilderPullPolicy specifies when to pull the builder
image
type: string
callbackUrl:
description: CallbackURL is a URL which is called upon successful
build to inform about that fact.
type: string
cgroupLimits:
description: CGroupLimits describes the cgroups limits that will
be applied to any containers run by s2i.
properties:
cpuPeriod:
format: int64
type: integer
cpuQuota:
format: int64
type: integer
cpuShares:
format: int64
type: integer
memoryLimitBytes:
format: int64
type: integer
memorySwap:
format: int64
type: integer
parent:
type: string
required:
- cpuPeriod
- cpuQuota
- cpuShares
- memoryLimitBytes
- memorySwap
- parent
type: object
contextDir:
description: Specify a relative directory inside the application
repository that should be used as a root directory for the application.
type: string
description:
description: Description is a result image description label. The
default is no description.
type: string
destination:
description: Destination specifies a location where the untar operation
will place its artifacts.
type: string
displayName:
description: DisplayName is a result image display-name label. This
defaults to the output image name.
type: string
dockerConfig:
description: DockerConfig describes how to access host docker daemon.
properties:
caFile:
description: CAFile is the certificate authority file path for
a TLS connection
type: string
certFile:
description: CertFile is the certificate file path for a TLS
connection
type: string
endPoint:
description: Endpoint is the docker network endpoint or socket
type: string
keyFile:
description: KeyFile is the key file path for a TLS connection
type: string
tlsVerify:
description: TLSVerify indicates if TLS peer must be verified
type: boolean
useTLS:
description: UseTLS indicates if TLS must be used
type: boolean
required:
- caFile
- certFile
- endPoint
- keyFile
- tlsVerify
- useTLS
type: object
dockerNetworkMode:
description: DockerNetworkMode is used to set the docker network
setting to --net=container:<id> when the builder is invoked from
a container.
type: string
dropCapabilities:
description: DropCapabilities contains a list of capabilities to
drop when executing containers
items:
type: string
type: array
environment:
description: Environment is a map of environment variables to be
passed to the image.
items:
description: EnvironmentSpec specifies a single environment variable.
properties:
name:
type: string
value:
type: string
required:
- name
- value
type: object
type: array
excludeRegExp:
description: ExcludeRegExp contains a string representation of the
regular expression desired for deciding which files to exclude
from the tar stream
type: string
export:
description: Export Push the result image to specify image registry
in tag
type: boolean
gitSecretRef:
description: GitSecretRef is the BasicAuth Secret of Git Clone
properties:
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
type: object
hasOnBuild:
description: HasOnBuild will be set to true if the builder image
contains ONBUILD instructions
type: boolean
imageName:
description: ImageName Contains the registry address and reponame,
tag should set by field tag alone
type: string
imageScriptsUrl:
description: ImageScriptsURL is the default location to find the
assemble/run scripts for a builder image. This url can be a reference
within the builder image if the scheme is specified as image://
type: string
imageWorkDir:
description: ImageWorkDir is the default working directory for the
builder image.
type: string
incremental:
description: Incremental describes whether to try to perform incremental
build.
type: boolean
incrementalAuthentication:
description: IncrementalAuthentication holds the authentication
information for pulling the previous image from private repositories
properties:
email:
type: string
password:
type: string
secretRef:
description: LocalObjectReference contains enough information
to let you locate the referenced object inside the same namespace.
properties:
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
type: object
serverAddress:
type: string
username:
type: string
type: object
incrementalFromTag:
description: IncrementalFromTag sets an alternative image tag to
look for existing artifacts. Tag is used by default if this is
not set.
type: string
injections:
description: Injections specifies a list source/destination folders
that are injected to the container that runs assemble. All files
we inject will be truncated after the assemble script finishes.
items:
description: VolumeSpec represents a single volume mount point.
properties:
destination:
description: Destination is the path to mount the volume to
- absolute or relative.
type: string
keep:
description: Keep indicates if the mounted data should be
kept in the final image.
type: boolean
source:
description: Source is a reference to the volume source.
type: string
type: object
type: array
isBinaryURL:
description: IsBinaryURL explain the type of SourceURL. If it is
IsBinaryURL, it will download the file directly without using
git.
type: boolean
keepSymlinks:
description: KeepSymlinks indicates to copy symlinks as symlinks.
Default behavior is to follow symlinks and copy files by content.
type: boolean
labelNamespace:
description: LabelNamespace provides the namespace under which the
labels will be generated.
type: string
labels:
additionalProperties:
type: string
description: Labels specify labels and their values to be applied
to the resulting image. Label keys must have non-zero length.
The labels defined here override generated labels in case they
have the same name.
type: object
layeredBuild:
description: LayeredBuild describes if this is build which layered
scripts and sources on top of BuilderImage.
type: boolean
nodeAffinityKey:
description: The key of Node Affinity.
type: string
nodeAffinityValues:
description: The values of Node Affinity.
items:
type: string
type: array
outputBuildResult:
description: Whether output build result to status.
type: boolean
outputImageName:
description: OutputImageName is a result image name without tag,
default is latest. tag will append to ImageName in the end
type: string
preserveWorkingDir:
description: PreserveWorkingDir describes if working directory should
be left after processing.
type: boolean
previousImagePullPolicy:
description: PreviousImagePullPolicy specifies when to pull the
previously build image when doing incremental build
type: string
pullAuthentication:
description: PullAuthentication holds the authentication information
for pulling the Docker images from private repositories
properties:
email:
type: string
password:
type: string
secretRef:
description: LocalObjectReference contains enough information
to let you locate the referenced object inside the same namespace.
properties:
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
type: object
serverAddress:
type: string
username:
type: string
type: object
pushAuthentication:
description: PullAuthentication holds the authentication information
for pulling the Docker images from private repositories
properties:
email:
type: string
password:
type: string
secretRef:
description: LocalObjectReference contains enough information
to let you locate the referenced object inside the same namespace.
properties:
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
type: object
serverAddress:
type: string
username:
type: string
type: object
removePreviousImage:
description: RemovePreviousImage describes if previous image should
be removed after successful build. This applies only to incremental
builds.
type: boolean
revisionId:
description: The RevisionId is a branch name or a SHA-1 hash of
every important thing about the commit
type: string
runImage:
description: RunImage will trigger a "docker run ..." invocation
of the produced image so the user can see if it operates as he
would expect
type: boolean
runtimeArtifacts:
description: RuntimeArtifacts specifies a list of source/destination
pairs that will be copied from builder to a runtime image. Source
can be a file or directory. Destination must be a directory. Regardless
whether it is an absolute or relative path, it will be placed
into image's WORKDIR. Destination also can be empty or equals
to ".", in this case it just refers to a root of WORKDIR. In case
it's empty, S2I will try to get this list from io.openshift.s2i.assemble-input-files
label on a RuntimeImage.
items:
description: VolumeSpec represents a single volume mount point.
properties:
destination:
description: Destination is the path to mount the volume to
- absolute or relative.
type: string
keep:
description: Keep indicates if the mounted data should be
kept in the final image.
type: boolean
source:
description: Source is a reference to the volume source.
type: string
type: object
type: array
runtimeAuthentication:
description: RuntimeAuthentication holds the authentication information
for pulling the runtime Docker images from private repositories.
properties:
email:
type: string
password:
type: string
secretRef:
description: LocalObjectReference contains enough information
to let you locate the referenced object inside the same namespace.
properties:
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
type: object
serverAddress:
type: string
username:
type: string
type: object
runtimeImage:
description: RuntimeImage specifies the image that will be a base
for resulting image and will be used for running an application.
By default, BuilderImage is used for building and running, but
the latter may be overridden.
type: string
runtimeImagePullPolicy:
description: RuntimeImagePullPolicy specifies when to pull a runtime
image.
type: string
scriptDownloadProxyConfig:
description: ScriptDownloadProxyConfig optionally specifies the
http and https proxy to use when downloading scripts
properties:
httpProxy:
type: string
httpsProxy:
type: string
type: object
scriptsUrl:
description: ScriptsURL is a URL describing where to fetch the S2I
scripts from during build process. This url can be a reference
within the builder image if the scheme is specified as image://
type: string
secretCode:
description: SecretCode
type: string
securityOpt:
description: SecurityOpt are passed as options to the docker containers
launched by s2i.
items:
type: string
type: array
sourceUrl:
description: SourceURL is url of the codes such as https://github.com/a/b.git
type: string
tag:
description: Tag is a result image tag name.
type: string
taintKey:
description: The name of taint.
type: string
usage:
description: Usage allows for properly shortcircuiting s2i logic
when `s2i usage` is invoked
type: boolean
workingDir:
description: WorkingDir describes temporary directory used for downloading
sources, scripts and tar operations.
type: string
workingSourceDir:
description: WorkingSourceDir describes the subdirectory off of
WorkingDir set up during the repo download that is later used
as the root for ignore processing
type: string
required:
- imageName
- sourceUrl
type: object
fromTemplate:
description: FromTemplate define some inputs from user
properties:
builderImage:
description: BaseImage specify which version of this template to
use
type: string
name:
description: Name specify a template to use, so many fields in Config
can left empty
type: string
parameters:
description: Parameters must use with `template`, fill some parameters
which template will use
items:
properties:
defaultValue:
type: string
description:
type: string
key:
type: string
optValues:
items:
type: string
type: array
required:
type: boolean
type:
type: string
value:
type: string
type: object
type: array
type: object
type: object
status:
description: S2iBuilderStatus defines the observed state of S2iBuilder
properties:
lastRunName:
description: LastRunState return the name of the newest run of this
builder
type: string
lastRunStartTime:
description: LastRunStartTime return the startTime of the newest run
of this builder
format: date-time
type: string
lastRunState:
description: LastRunState return the state of the newest run of this
builder
type: string
runCount:
description: RunCount represent the sum of s2irun of this builder
type: integer
required:
- runCount
type: object
type: object
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@@ -0,0 +1,141 @@
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: (devel)
creationTimestamp: null
name: s2ibuildertemplates.devops.kubesphere.io
spec:
additionalPrinterColumns:
- JSONPath: .spec.codeFramework
name: Framework
type: string
- JSONPath: .spec.defaultBaseImage
name: DefaultBaseImage
type: string
- JSONPath: .spec.version
name: Version
type: string
group: devops.kubesphere.io
names:
categories:
- devops
kind: S2iBuilderTemplate
listKind: S2iBuilderTemplateList
plural: s2ibuildertemplates
shortNames:
- s2ibt
singular: s2ibuildertemplate
scope: Cluster
subresources: {}
validation:
openAPIV3Schema:
description: S2iBuilderTemplate is the Schema for the s2ibuildertemplates API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: S2iBuilderTemplateSpec defines the desired state of S2iBuilderTemplate
properties:
codeFramework:
description: CodeFramework means which language this template is designed
for and which framework is using if has framework. Like Java, NodeJS
etc
type: string
containerInfo:
description: Images are the images this template will use.
items:
properties:
buildVolumes:
description: BuildVolumes specifies a list of volumes to mount
to container running the build.
items:
type: string
type: array
builderImage:
description: BaseImage are the images this template will use.
type: string
runtimeArtifacts:
items:
description: VolumeSpec represents a single volume mount point.
properties:
destination:
description: Destination is the path to mount the volume
to - absolute or relative.
type: string
keep:
description: Keep indicates if the mounted data should be
kept in the final image.
type: boolean
source:
description: Source is a reference to the volume source.
type: string
type: object
type: array
runtimeImage:
type: string
type: object
type: array
defaultBaseImage:
description: DefaultBaseImage is the image that will be used by default
type: string
description:
description: Description illustrate the purpose of this template
type: string
environment:
description: Parameters is a set of environment variables to be passed
to the image.
items:
properties:
defaultValue:
type: string
description:
type: string
key:
type: string
optValues:
items:
type: string
type: array
required:
type: boolean
type:
type: string
value:
type: string
type: object
type: array
iconPath:
description: IconPath is used for frontend display
type: string
version:
description: Version of template
type: string
type: object
status:
description: S2iBuilderTemplateStatus defines the observed state of S2iBuilderTemplate
type: object
type: object
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@@ -0,0 +1,181 @@
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: (devel)
creationTimestamp: null
name: s2iruns.devops.kubesphere.io
spec:
additionalPrinterColumns:
- JSONPath: .status.runState
name: State
type: string
- JSONPath: .status.kubernetesJobName
name: K8sJobName
type: string
- JSONPath: .status.startTime
name: StartTime
type: date
- JSONPath: .status.completionTime
name: CompletionTime
type: date
- JSONPath: .status.s2iBuildResult.imageName
name: ImageName
type: string
group: devops.kubesphere.io
names:
kind: S2iRun
listKind: S2iRunList
plural: s2iruns
shortNames:
- s2ir
singular: s2irun
scope: Namespaced
subresources:
status: {}
validation:
openAPIV3Schema:
description: S2iRun is the Schema for the s2iruns API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: S2iRunSpec defines the desired state of S2iRun
properties:
backoffLimit:
description: BackoffLimit limits the restart count of each s2irun. Default
is 0
format: int32
type: integer
builderName:
description: BuilderName specify the name of s2ibuilder, required
type: string
newRevisionId:
description: NewRevisionId override the default NewRevisionId in its
s2ibuilder.
type: string
newSourceURL:
description: NewSourceURL is used to download new binary artifacts
type: string
newTag:
description: NewTag override the default tag in its s2ibuilder, image
name cannot be changed.
type: string
secondsAfterFinished:
description: SecondsAfterFinished if is set and greater than zero, and
the job created by s2irun become successful or failed , the job will
be auto deleted after SecondsAfterFinished
format: int32
type: integer
required:
- builderName
type: object
status:
description: S2iRunStatus defines the observed state of S2iRun
properties:
completionTime:
description: Represents time when the job was completed. It is not guaranteed
to be set in happens-before order across separate operations. It is
represented in RFC3339 form and is in UTC.
format: date-time
type: string
kubernetesJobName:
description: KubernetesJobName is the job name in k8s
type: string
logURL:
description: LogURL is uesd for external log handler to let user know
where is log located in
type: string
runState:
description: RunState indicates whether this job is done or failed
type: string
s2iBuildResult:
description: S2i build result info.
properties:
commandPull:
description: Command for pull image.
type: string
imageCreated:
description: Image created time.
type: string
imageID:
description: Image ID.
type: string
imageName:
description: ImageName is the name of artifact
type: string
imageRepoTags:
description: image tags.
items:
type: string
type: array
imageSize:
description: The size in bytes of the image
format: int64
type: integer
type: object
s2iBuildSource:
description: S2i build source info.
properties:
binaryName:
description: Binary file Name
type: string
binarySize:
description: Binary file Size
format: int64
type: integer
builderImage:
description: // BuilderImage describes which image is used for building
the result images.
type: string
commitID:
description: CommitID represents an arbitrary extended object reference
in Git as SHA-1
type: string
committerEmail:
description: CommitterEmail contains the e-mail of the committer
type: string
committerName:
description: CommitterName contains the name of the committer
type: string
description:
description: Description is a result image description label. The
default is no description.
type: string
revisionId:
description: The RevisionId is a branch name or a SHA-1 hash of
every important thing about the commit
type: string
sourceUrl:
description: SourceURL is url of the codes such as https://github.com/a/b.git
type: string
type: object
startTime:
description: StartTime represent when this run began
format: date-time
type: string
type: object
type: object
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

6
go.mod
View File

@@ -32,6 +32,8 @@ require (
github.com/fatih/structs v1.1.0
github.com/go-ldap/ldap v3.0.3+incompatible
github.com/go-logr/logr v0.1.0
github.com/go-logr/zapr v0.1.1 // indirect
github.com/go-openapi/jsonreference v0.19.3 // indirect
github.com/go-openapi/spec v0.19.3
github.com/go-openapi/strfmt v0.19.0
github.com/go-playground/universal-translator v0.16.0 // indirect
@@ -55,11 +57,11 @@ require (
github.com/klauspost/cpuid v1.2.1 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/kubernetes-sigs/application v0.0.0-20191210100950-18cc93526ab4
github.com/kubesphere/s2ioperator v0.0.14
github.com/kubesphere/sonargo v0.0.2
github.com/leodido/go-urn v1.1.0 // indirect
github.com/lib/pq v1.2.0 // indirect
github.com/lucas-clemente/quic-go v0.11.1 // indirect
github.com/mailru/easyjson v0.7.0 // indirect
github.com/mattn/go-sqlite3 v1.11.0 // indirect
github.com/mholt/caddy v1.0.0
github.com/mholt/certmagic v0.5.1 // indirect
@@ -82,6 +84,7 @@ require (
github.com/xanzy/ssh-agent v0.2.1 // indirect
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72 // indirect
google.golang.org/grpc v1.23.1
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
gopkg.in/go-playground/validator.v9 v9.29.1 // indirect
@@ -98,6 +101,7 @@ require (
k8s.io/client-go v0.0.0-20191114101535-6c5935290e33
k8s.io/code-generator v0.0.0-20191004115455-8e001e5d1894
k8s.io/component-base v0.0.0-20191114102325-35a9586014f7
k8s.io/gengo v0.0.0-20191120174120-e74f70b9b27e // indirect
k8s.io/klog v1.0.0
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f // indirect

2
go.sum
View File

@@ -276,8 +276,6 @@ github.com/kubesphere/application v0.0.0-20191210100950-18cc93526ab4 h1:pugSGmj8
github.com/kubesphere/application v0.0.0-20191210100950-18cc93526ab4/go.mod h1:sILRE7W0CquRyC51JNRj4U7OP7CJl3o62TcX5E6IcWs=
github.com/kubesphere/kiali v0.15.1-0.20191210080139-edbbad1ef779 h1:52StEbBn6dRFF2DE9DBmVt26JQu9j4DOwagLUq6gZWg=
github.com/kubesphere/kiali v0.15.1-0.20191210080139-edbbad1ef779/go.mod h1:Y1EqeixoXkKkU8I+yvOfhdh21+8+etFE6wYOVT2XFdI=
github.com/kubesphere/s2ioperator v0.0.14 h1:oShV/MSn8bwwnRzXU8bY3RH/V4k0TmCcKZ50B0Q9gEk=
github.com/kubesphere/s2ioperator v0.0.14/go.mod h1:6stEM/ocFZxYhLYl2d5LRYE5WdggHMIX5ngJwloWR4g=
github.com/kubesphere/sonargo v0.0.2 h1:hsSRE3sv3mkPcUAeSABdp7rtfcNW2zzeHXzFa01CTkU=
github.com/kubesphere/sonargo v0.0.2/go.mod h1:ww8n9ANlDXhX5PBZ18iaRnCgEkXN0GMml3/KZXOZ11w=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=

View File

@@ -16,7 +16,6 @@ fi
docker build -f build/ks-apigateway/Dockerfile -t $REPO/ks-apigateway:$TAG .
docker build -f build/ks-apiserver/Dockerfile -t $REPO/ks-apiserver:$TAG .
docker build -f build/ks-iam/Dockerfile -t $REPO/ks-account:$TAG .
docker build -f build/ks-controller-manager/Dockerfile -t $REPO/ks-controller-manager:$TAG .
docker build -f build/hypersphere/Dockerfile -t $REPO/hypersphere:$TAG .
docker build -f ./pkg/db/Dockerfile -t $REPO/ks-devops:flyway-$TAG ./pkg/db/
@@ -26,7 +25,6 @@ docker build -f ./pkg/db/Dockerfile -t $REPO/ks-devops:flyway-$TAG ./pkg/db/
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
docker push $REPO/ks-apigateway:$TAG
docker push $REPO/ks-apiserver:$TAG
docker push $REPO/ks-account:$TAG
docker push $REPO/ks-controller-manager:$TAG
docker push $REPO/hypersphere:$TAG
docker push $REPO/ks-devops:flyway-$TAG

View File

@@ -0,0 +1,44 @@
package iam
import (
"github.com/spf13/pflag"
"time"
)
type AuthenticationOptions struct {
// authenticate rate limit will
AuthenticateRateLimiterMaxTries int
AuthenticateRateLimiterDuration time.Duration
// maximum retries when authenticate failed
MaxAuthenticateRetries int
// token validation duration, will refresh token expiration for each user request
TokenExpiration time.Duration
// allow multiple users login at the same time
MultipleLogin bool
}
func NewAuthenticateOptions() *AuthenticationOptions {
return &AuthenticationOptions{
AuthenticateRateLimiterMaxTries: 5,
AuthenticateRateLimiterDuration: time.Minute * 30,
MaxAuthenticateRetries: 0,
TokenExpiration: 0,
MultipleLogin: false,
}
}
func (options *AuthenticationOptions) Validate() []error {
var errs []error
return errs
}
func (options *AuthenticationOptions) AddFlags(fs *pflag.FlagSet, s *AuthenticationOptions) {
fs.IntVar(&options.AuthenticateRateLimiterMaxTries, "authenticate-rate-limiter-max-retries", s.AuthenticateRateLimiterMaxTries, "")
fs.DurationVar(&options.AuthenticateRateLimiterDuration, "authenticate-rate-limiter-duration", s.AuthenticateRateLimiterDuration, "")
fs.IntVar(&options.MaxAuthenticateRetries, "authenticate-max-retries", s.MaxAuthenticateRetries, "")
fs.DurationVar(&options.TokenExpiration, "token-expiration", s.TokenExpiration, "")
fs.BoolVar(&options.MultipleLogin, "multiple-login", s.MultipleLogin, "")
}

40
pkg/api/iam/user.go Normal file
View File

@@ -0,0 +1,40 @@
package iam
import (
"kubesphere.io/kubesphere/pkg/server/errors"
"time"
)
type User struct {
Username string `json:"username"`
Email string `json:"email"`
Lang string `json:"lang,omitempty"`
Description string `json:"description"`
CreateTime time.Time `json:"create_time"`
Groups []string `json:"groups,omitempty"`
Password string `json:"password,omitempty"`
}
func NewUser() *User {
return &User{
Username: "",
Email: "",
Lang: "",
Description: "",
CreateTime: time.Time{},
Groups: nil,
Password: "",
}
}
func (u *User) Validate() error {
if u.Username == "" {
return errors.New("username can not be empty")
}
if u.Password == "" {
return errors.New("password can not be empty")
}
return nil
}

View File

@@ -20,7 +20,7 @@ package v1alpha2
import (
"fmt"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/api/iam"
"net/mail"
)

File diff suppressed because it is too large Load Diff

View File

@@ -21,9 +21,9 @@ import (
)
const (
ResourceKindS2iBinary = "S2iBinary"
ResourceSingularServicePolicy = "s2ibinary"
ResourcePluralServicePolicy = "s2ibinaries"
ResourceKindS2iBinary = "S2iBinary"
ResourceSingularS2iBinary = "s2ibinary"
ResourcePluralS2iBinary = "s2ibinaries"
)
const (

View File

@@ -422,6 +422,12 @@ type S2iConfig struct {
// Whether output build result to status.
OutputBuildResult bool `json:"outputBuildResult,omitempty"`
// Regular expressions, ignoring names that do not match the provided regular expression
BranchExpression string `json:"branchExpression,omitempty"`
// SecretCode
SecretCode string `json:"secretCode,omitempty"`
}
type UserDefineTemplate struct {

View File

@@ -0,0 +1,58 @@
/*
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 v1alpha1
import (
"testing"
"github.com/onsi/gomega"
"golang.org/x/net/context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
func TestStorageS2iBuilder(t *testing.T) {
key := types.NamespacedName{
Name: "foo",
Namespace: "default",
}
created := &S2iBuilder{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: "default",
}}
g := gomega.NewGomegaWithT(t)
// Test Create
fetched := &S2iBuilder{}
g.Expect(c.Create(context.TODO(), created)).NotTo(gomega.HaveOccurred())
g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred())
g.Expect(fetched).To(gomega.Equal(created))
// Test Updating the Labels
updated := fetched.DeepCopy()
updated.Labels = map[string]string{"hello": "world"}
g.Expect(c.Update(context.TODO(), updated)).NotTo(gomega.HaveOccurred())
g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred())
g.Expect(fetched).To(gomega.Equal(updated))
// Test Delete
g.Expect(c.Delete(context.TODO(), fetched)).NotTo(gomega.HaveOccurred())
g.Expect(c.Get(context.TODO(), key, fetched)).To(gomega.HaveOccurred())
}

View File

@@ -36,6 +36,17 @@ type Parameter struct {
Value string `json:"value,omitempty"`
}
type CodeFramework string
const (
Ruby CodeFramework = "ruby"
Go CodeFramework = "go"
Java CodeFramework = "Java"
JavaTomcat CodeFramework = "JavaTomcat"
Nodejs CodeFramework = "Nodejs"
Python CodeFramework = "python"
)
func (p *Parameter) ToEnvonment() *EnvironmentSpec {
var v string
if p.Value == "" && p.DefaultValue != "" {

View File

@@ -0,0 +1,56 @@
/*
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 v1alpha1
import (
"testing"
"github.com/onsi/gomega"
"golang.org/x/net/context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
func TestStorageS2iBuilderTemplate(t *testing.T) {
key := types.NamespacedName{
Name: "foo",
}
created := &S2iBuilderTemplate{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
}}
g := gomega.NewGomegaWithT(t)
// Test Create
fetched := &S2iBuilderTemplate{}
g.Expect(c.Create(context.TODO(), created)).NotTo(gomega.HaveOccurred())
g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred())
g.Expect(fetched).To(gomega.Equal(created))
// Test Updating the Labels
updated := fetched.DeepCopy()
updated.Labels = map[string]string{"hello": "world"}
g.Expect(c.Update(context.TODO(), updated)).NotTo(gomega.HaveOccurred())
g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred())
g.Expect(fetched).To(gomega.Equal(updated))
// Test Delete
g.Expect(c.Delete(context.TODO(), fetched)).NotTo(gomega.HaveOccurred())
g.Expect(c.Get(context.TODO(), key, fetched)).To(gomega.HaveOccurred())
}

View File

@@ -0,0 +1,58 @@
/*
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 v1alpha1
import (
"testing"
"github.com/onsi/gomega"
"golang.org/x/net/context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
func TestStorageS2iRun(t *testing.T) {
key := types.NamespacedName{
Name: "foo",
Namespace: "default",
}
created := &S2iRun{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: "default",
}}
g := gomega.NewGomegaWithT(t)
// Test Create
fetched := &S2iRun{}
g.Expect(c.Create(context.TODO(), created)).NotTo(gomega.HaveOccurred())
g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred())
g.Expect(fetched).To(gomega.Equal(created))
// Test Updating the Labels
updated := fetched.DeepCopy()
updated.Labels = map[string]string{"hello": "world"}
g.Expect(c.Update(context.TODO(), updated)).NotTo(gomega.HaveOccurred())
g.Expect(c.Get(context.TODO(), key, fetched)).NotTo(gomega.HaveOccurred())
g.Expect(fetched).To(gomega.Equal(updated))
// Test Delete
g.Expect(c.Delete(context.TODO(), fetched)).NotTo(gomega.HaveOccurred())
g.Expect(c.Get(context.TODO(), key, fetched)).To(gomega.HaveOccurred())
}

View File

@@ -21,9 +21,257 @@ limitations under the License.
package v1alpha1
import (
v1 "k8s.io/api/core/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AuthConfig) DeepCopyInto(out *AuthConfig) {
*out = *in
if in.SecretRef != nil {
in, out := &in.SecretRef, &out.SecretRef
*out = new(v1.LocalObjectReference)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthConfig.
func (in *AuthConfig) DeepCopy() *AuthConfig {
if in == nil {
return nil
}
out := new(AuthConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CGroupLimits) DeepCopyInto(out *CGroupLimits) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CGroupLimits.
func (in *CGroupLimits) DeepCopy() *CGroupLimits {
if in == nil {
return nil
}
out := new(CGroupLimits)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ContainerConfig) DeepCopyInto(out *ContainerConfig) {
*out = *in
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Env != nil {
in, out := &in.Env, &out.Env
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerConfig.
func (in *ContainerConfig) DeepCopy() *ContainerConfig {
if in == nil {
return nil
}
out := new(ContainerConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ContainerInfo) DeepCopyInto(out *ContainerInfo) {
*out = *in
if in.RuntimeArtifacts != nil {
in, out := &in.RuntimeArtifacts, &out.RuntimeArtifacts
*out = make([]VolumeSpec, len(*in))
copy(*out, *in)
}
if in.BuildVolumes != nil {
in, out := &in.BuildVolumes, &out.BuildVolumes
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerInfo.
func (in *ContainerInfo) DeepCopy() *ContainerInfo {
if in == nil {
return nil
}
out := new(ContainerInfo)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DockerConfig) DeepCopyInto(out *DockerConfig) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DockerConfig.
func (in *DockerConfig) DeepCopy() *DockerConfig {
if in == nil {
return nil
}
out := new(DockerConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DockerConfigEntry) DeepCopyInto(out *DockerConfigEntry) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DockerConfigEntry.
func (in *DockerConfigEntry) DeepCopy() *DockerConfigEntry {
if in == nil {
return nil
}
out := new(DockerConfigEntry)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DockerConfigJson) DeepCopyInto(out *DockerConfigJson) {
*out = *in
if in.Auths != nil {
in, out := &in.Auths, &out.Auths
*out = make(DockerConfigMap, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DockerConfigJson.
func (in *DockerConfigJson) DeepCopy() *DockerConfigJson {
if in == nil {
return nil
}
out := new(DockerConfigJson)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in DockerConfigMap) DeepCopyInto(out *DockerConfigMap) {
{
in := &in
*out = make(DockerConfigMap, len(*in))
for key, val := range *in {
(*out)[key] = val
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DockerConfigMap.
func (in DockerConfigMap) DeepCopy() DockerConfigMap {
if in == nil {
return nil
}
out := new(DockerConfigMap)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *EnvironmentSpec) DeepCopyInto(out *EnvironmentSpec) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvironmentSpec.
func (in *EnvironmentSpec) DeepCopy() *EnvironmentSpec {
if in == nil {
return nil
}
out := new(EnvironmentSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Parameter) DeepCopyInto(out *Parameter) {
*out = *in
if in.OptValues != nil {
in, out := &in.OptValues, &out.OptValues
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Parameter.
func (in *Parameter) DeepCopy() *Parameter {
if in == nil {
return nil
}
out := new(Parameter)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProxyConfig) DeepCopyInto(out *ProxyConfig) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyConfig.
func (in *ProxyConfig) DeepCopy() *ProxyConfig {
if in == nil {
return nil
}
out := new(ProxyConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iAutoScale) DeepCopyInto(out *S2iAutoScale) {
*out = *in
if in.InitReplicas != nil {
in, out := &in.InitReplicas, &out.InitReplicas
*out = new(int32)
**out = **in
}
if in.Containers != nil {
in, out := &in.Containers, &out.Containers
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iAutoScale.
func (in *S2iAutoScale) DeepCopy() *S2iAutoScale {
if in == nil {
return nil
}
out := new(S2iAutoScale)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iBinary) DeepCopyInto(out *S2iBinary) {
*out = *in
@@ -120,3 +368,512 @@ func (in *S2iBinaryStatus) DeepCopy() *S2iBinaryStatus {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iBuildResult) DeepCopyInto(out *S2iBuildResult) {
*out = *in
if in.ImageRepoTags != nil {
in, out := &in.ImageRepoTags, &out.ImageRepoTags
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuildResult.
func (in *S2iBuildResult) DeepCopy() *S2iBuildResult {
if in == nil {
return nil
}
out := new(S2iBuildResult)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iBuildSource) DeepCopyInto(out *S2iBuildSource) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuildSource.
func (in *S2iBuildSource) DeepCopy() *S2iBuildSource {
if in == nil {
return nil
}
out := new(S2iBuildSource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iBuilder) DeepCopyInto(out *S2iBuilder) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilder.
func (in *S2iBuilder) DeepCopy() *S2iBuilder {
if in == nil {
return nil
}
out := new(S2iBuilder)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *S2iBuilder) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iBuilderList) DeepCopyInto(out *S2iBuilderList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]S2iBuilder, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderList.
func (in *S2iBuilderList) DeepCopy() *S2iBuilderList {
if in == nil {
return nil
}
out := new(S2iBuilderList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *S2iBuilderList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iBuilderSpec) DeepCopyInto(out *S2iBuilderSpec) {
*out = *in
if in.Config != nil {
in, out := &in.Config, &out.Config
*out = new(S2iConfig)
(*in).DeepCopyInto(*out)
}
if in.FromTemplate != nil {
in, out := &in.FromTemplate, &out.FromTemplate
*out = new(UserDefineTemplate)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderSpec.
func (in *S2iBuilderSpec) DeepCopy() *S2iBuilderSpec {
if in == nil {
return nil
}
out := new(S2iBuilderSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iBuilderStatus) DeepCopyInto(out *S2iBuilderStatus) {
*out = *in
if in.LastRunName != nil {
in, out := &in.LastRunName, &out.LastRunName
*out = new(string)
**out = **in
}
if in.LastRunStartTime != nil {
in, out := &in.LastRunStartTime, &out.LastRunStartTime
*out = (*in).DeepCopy()
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderStatus.
func (in *S2iBuilderStatus) DeepCopy() *S2iBuilderStatus {
if in == nil {
return nil
}
out := new(S2iBuilderStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iBuilderTemplate) DeepCopyInto(out *S2iBuilderTemplate) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
out.Status = in.Status
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderTemplate.
func (in *S2iBuilderTemplate) DeepCopy() *S2iBuilderTemplate {
if in == nil {
return nil
}
out := new(S2iBuilderTemplate)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *S2iBuilderTemplate) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iBuilderTemplateList) DeepCopyInto(out *S2iBuilderTemplateList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]S2iBuilderTemplate, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderTemplateList.
func (in *S2iBuilderTemplateList) DeepCopy() *S2iBuilderTemplateList {
if in == nil {
return nil
}
out := new(S2iBuilderTemplateList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *S2iBuilderTemplateList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iBuilderTemplateSpec) DeepCopyInto(out *S2iBuilderTemplateSpec) {
*out = *in
if in.ContainerInfo != nil {
in, out := &in.ContainerInfo, &out.ContainerInfo
*out = make([]ContainerInfo, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Parameters != nil {
in, out := &in.Parameters, &out.Parameters
*out = make([]Parameter, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderTemplateSpec.
func (in *S2iBuilderTemplateSpec) DeepCopy() *S2iBuilderTemplateSpec {
if in == nil {
return nil
}
out := new(S2iBuilderTemplateSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iBuilderTemplateStatus) DeepCopyInto(out *S2iBuilderTemplateStatus) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderTemplateStatus.
func (in *S2iBuilderTemplateStatus) DeepCopy() *S2iBuilderTemplateStatus {
if in == nil {
return nil
}
out := new(S2iBuilderTemplateStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iConfig) DeepCopyInto(out *S2iConfig) {
*out = *in
if in.RuntimeAuthentication != nil {
in, out := &in.RuntimeAuthentication, &out.RuntimeAuthentication
*out = new(AuthConfig)
(*in).DeepCopyInto(*out)
}
if in.RuntimeArtifacts != nil {
in, out := &in.RuntimeArtifacts, &out.RuntimeArtifacts
*out = make([]VolumeSpec, len(*in))
copy(*out, *in)
}
if in.DockerConfig != nil {
in, out := &in.DockerConfig, &out.DockerConfig
*out = new(DockerConfig)
**out = **in
}
if in.PullAuthentication != nil {
in, out := &in.PullAuthentication, &out.PullAuthentication
*out = new(AuthConfig)
(*in).DeepCopyInto(*out)
}
if in.PushAuthentication != nil {
in, out := &in.PushAuthentication, &out.PushAuthentication
*out = new(AuthConfig)
(*in).DeepCopyInto(*out)
}
if in.IncrementalAuthentication != nil {
in, out := &in.IncrementalAuthentication, &out.IncrementalAuthentication
*out = new(AuthConfig)
(*in).DeepCopyInto(*out)
}
if in.Environment != nil {
in, out := &in.Environment, &out.Environment
*out = make([]EnvironmentSpec, len(*in))
copy(*out, *in)
}
if in.Injections != nil {
in, out := &in.Injections, &out.Injections
*out = make([]VolumeSpec, len(*in))
copy(*out, *in)
}
if in.CGroupLimits != nil {
in, out := &in.CGroupLimits, &out.CGroupLimits
*out = new(CGroupLimits)
**out = **in
}
if in.DropCapabilities != nil {
in, out := &in.DropCapabilities, &out.DropCapabilities
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.ScriptDownloadProxyConfig != nil {
in, out := &in.ScriptDownloadProxyConfig, &out.ScriptDownloadProxyConfig
*out = new(ProxyConfig)
**out = **in
}
if in.BuildVolumes != nil {
in, out := &in.BuildVolumes, &out.BuildVolumes
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.SecurityOpt != nil {
in, out := &in.SecurityOpt, &out.SecurityOpt
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.AddHost != nil {
in, out := &in.AddHost, &out.AddHost
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.GitSecretRef != nil {
in, out := &in.GitSecretRef, &out.GitSecretRef
*out = new(v1.LocalObjectReference)
**out = **in
}
if in.NodeAffinityValues != nil {
in, out := &in.NodeAffinityValues, &out.NodeAffinityValues
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iConfig.
func (in *S2iConfig) DeepCopy() *S2iConfig {
if in == nil {
return nil
}
out := new(S2iConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iRun) DeepCopyInto(out *S2iRun) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iRun.
func (in *S2iRun) DeepCopy() *S2iRun {
if in == nil {
return nil
}
out := new(S2iRun)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *S2iRun) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iRunList) DeepCopyInto(out *S2iRunList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]S2iRun, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iRunList.
func (in *S2iRunList) DeepCopy() *S2iRunList {
if in == nil {
return nil
}
out := new(S2iRunList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *S2iRunList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iRunSpec) DeepCopyInto(out *S2iRunSpec) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iRunSpec.
func (in *S2iRunSpec) DeepCopy() *S2iRunSpec {
if in == nil {
return nil
}
out := new(S2iRunSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *S2iRunStatus) DeepCopyInto(out *S2iRunStatus) {
*out = *in
if in.StartTime != nil {
in, out := &in.StartTime, &out.StartTime
*out = (*in).DeepCopy()
}
if in.CompletionTime != nil {
in, out := &in.CompletionTime, &out.CompletionTime
*out = (*in).DeepCopy()
}
if in.S2iBuildResult != nil {
in, out := &in.S2iBuildResult, &out.S2iBuildResult
*out = new(S2iBuildResult)
(*in).DeepCopyInto(*out)
}
if in.S2iBuildSource != nil {
in, out := &in.S2iBuildSource, &out.S2iBuildSource
*out = new(S2iBuildSource)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iRunStatus.
func (in *S2iRunStatus) DeepCopy() *S2iRunStatus {
if in == nil {
return nil
}
out := new(S2iRunStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *UserDefineTemplate) DeepCopyInto(out *UserDefineTemplate) {
*out = *in
if in.Parameters != nil {
in, out := &in.Parameters, &out.Parameters
*out = make([]Parameter, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserDefineTemplate.
func (in *UserDefineTemplate) DeepCopy() *UserDefineTemplate {
if in == nil {
return nil
}
out := new(UserDefineTemplate)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VolumeSpec) DeepCopyInto(out *VolumeSpec) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSpec.
func (in *VolumeSpec) DeepCopy() *VolumeSpec {
if in == nil {
return nil
}
out := new(VolumeSpec)
in.DeepCopyInto(out)
return out
}

View File

@@ -1,18 +1,38 @@
package apiserver
import (
"bytes"
"context"
"fmt"
"github.com/emicklei/go-restful"
"k8s.io/apimachinery/pkg/runtime/schema"
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api/iam"
"kubesphere.io/kubesphere/pkg/informers"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/iam/v1alpha2"
loggingv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/logging/v1alpha2"
monitoringv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha2"
openpitrixv1 "kubesphere.io/kubesphere/pkg/kapis/openpitrix/v1"
operationsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/operations/v1alpha2"
resourcesv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha2"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha3"
"kubesphere.io/kubesphere/pkg/server/options"
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/servicemesh/metrics/v1alpha2"
terminalv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/terminal/v1alpha2"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
"kubesphere.io/kubesphere/pkg/simple/client/db"
"kubesphere.io/kubesphere/pkg/simple/client/devops"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
"kubesphere.io/kubesphere/pkg/simple/client/logging"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"kubesphere.io/kubesphere/pkg/simple/client/s3"
"net"
"net/http"
rt "runtime"
"strings"
"time"
)
const (
@@ -26,56 +46,295 @@ const (
MimeJsonPatchJson = "application/json-patch+json"
)
// Dependencies is objects constructed at runtime that are necessary for running apiserver.
type Dependencies struct {
// Injected Dependencies
KubeClient k8s.Client
S3 s3.Interface
OpenPitrix openpitrix.Client
Monitoring monitoring.Interface
Logging logging.Interface
Devops devops.Interface
DB db.Interface
}
type APIServer struct {
// number of kubesphere apiserver
apiserverCount int
ServerCount int
//
genericServerOptions *options.ServerRunOptions
Server *http.Server
AuthenticateOptions *iam.AuthenticationOptions
// webservice container, where all webservice defines
container *restful.Container
// kubeClient is a collection of all kubernetes(include CRDs) objects clientset
kubeClient k8s.Client
KubernetesClient k8s.Client
// informerFactory is a collection of all kubernetes(include CRDs) objects informers,
// mainly for fast query
informerFactory informers.InformerFactory
InformerFactory informers.InformerFactory
// cache is used for short lived objects, like session
cache cache.Interface
CacheClient cache.Interface
// monitoring client set
MonitoringClient monitoring.Interface
//
OpenpitrixClient openpitrix.Client
//
LoggingClient logging.Interface
//
DevopsClient devops.Interface
//
S3Client s3.Interface
//
DBClient db.Interface
//
LdapClient ldap.Interface
//
}
func (s *APIServer) PrepareRun() error {
s.container = restful.NewContainer()
s.container.Filter(logRequestAndResponse)
s.container.Router(restful.CurlyRouter{})
s.container.RecoverHandler(func(panicReason interface{}, httpWriter http.ResponseWriter) {
logStackOnRecover(panicReason, httpWriter)
})
s.installKubeSphereAPIs()
return nil
}
func (s *APIServer) installKubeSphereAPIs() {
urlruntime.Must(resourcev1alpha3.AddToContainer(s.container, s.InformerFactory))
urlruntime.Must(servicemeshv1alpha2.AddToContainer(s.container))
// Need to refactor devops api registration, too much dependencies
//urlruntime.Must(devopsv1alpha2.AddToContainer(s.container, s.DevopsClient))
urlruntime.Must(loggingv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.LoggingClient))
urlruntime.Must(monitoringv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.MonitoringClient))
urlruntime.Must(openpitrixv1.AddToContainer(s.container, s.InformerFactory, s.OpenpitrixClient))
urlruntime.Must(operationsv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes()))
urlruntime.Must(resourcesv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.InformerFactory))
//urlruntime.Must(tenantv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.InformerFactory, s.DBClient))
urlruntime.Must(terminalv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.KubernetesClient.Config()))
urlruntime.Must(iamv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.InformerFactory, s.LdapClient, s.CacheClient, s.AuthenticateOptions))
}
func New(deps *Dependencies) *APIServer {
func (s *APIServer) Run(stopCh <-chan struct{}) error {
server := &APIServer{}
err := s.waitForResourceSync(stopCh)
if err != nil {
return err
}
return server
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
<-stopCh
_ = s.Server.Shutdown(ctx)
}()
if s.Server.TLSConfig != nil {
return s.Server.ListenAndServeTLS("", "")
} else {
return s.Server.ListenAndServe()
}
}
func (s *APIServer) InstallKubeSphereAPIs() {
func (s *APIServer) waitForResourceSync(stopCh <-chan struct{}) error {
klog.V(0).Info("Start cache objects")
discoveryClient := s.KubernetesClient.Kubernetes().Discovery()
apiResourcesList, err := discoveryClient.ServerResources()
if err != nil {
return err
}
isResourceExists := func(resource schema.GroupVersionResource) bool {
for _, apiResource := range apiResourcesList {
if apiResource.GroupVersion == resource.GroupVersion().String() {
for _, rsc := range apiResource.APIResources {
if rsc.Name == resource.Resource {
return true
}
}
}
}
return false
}
// resources we have to create informer first
k8sGVRs := []schema.GroupVersionResource{
{Group: "", Version: "v1", Resource: "namespaces"},
{Group: "", Version: "v1", Resource: "nodes"},
{Group: "", Version: "v1", Resource: "resourcequotas"},
{Group: "", Version: "v1", Resource: "pods"},
{Group: "", Version: "v1", Resource: "services"},
{Group: "", Version: "v1", Resource: "persistentvolumeclaims"},
{Group: "", Version: "v1", Resource: "secrets"},
{Group: "", Version: "v1", Resource: "configmaps"},
{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "roles"},
{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "rolebindings"},
{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "clusterroles"},
{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "clusterrolebindings"},
{Group: "apps", Version: "v1", Resource: "deployments"},
{Group: "apps", Version: "v1", Resource: "daemonsets"},
{Group: "apps", Version: "v1", Resource: "replicasets"},
{Group: "apps", Version: "v1", Resource: "statefulsets"},
{Group: "apps", Version: "v1", Resource: "controllerrevisions"},
{Group: "storage.k8s.io", Version: "v1", Resource: "storageclasses"},
{Group: "batch", Version: "v1", Resource: "jobs"},
{Group: "batch", Version: "v1beta1", Resource: "cronjobs"},
{Group: "extensions", Version: "v1beta1", Resource: "ingresses"},
{Group: "autoscaling", Version: "v2beta2", Resource: "horizontalpodautoscalers"},
}
for _, gvr := range k8sGVRs {
if !isResourceExists(gvr) {
klog.Warningf("resource %s not exists in the cluster", gvr)
} else {
_, err := s.InformerFactory.KubernetesSharedInformerFactory().ForResource(gvr)
if err != nil {
klog.Errorf("cannot create informer for %s", gvr)
return err
}
}
}
s.InformerFactory.KubernetesSharedInformerFactory().Start(stopCh)
s.InformerFactory.KubernetesSharedInformerFactory().WaitForCacheSync(stopCh)
ksInformerFactory := s.InformerFactory.KubeSphereSharedInformerFactory()
ksGVRs := []schema.GroupVersionResource{
{Group: "tenant.kubesphere.io", Version: "v1alpha1", Resource: "workspaces"},
}
devopsGVRs := []schema.GroupVersionResource{
{Group: "devops.kubesphere.io", Version: "v1alpha1", Resource: "s2ibinaries"},
{Group: "devops.kubesphere.io", Version: "v1alpha1", Resource: "s2ibuildertemplates"},
{Group: "devops.kubesphere.io", Version: "v1alpha1", Resource: "s2iruns"},
{Group: "devops.kubesphere.io", Version: "v1alpha1", Resource: "s2ibuilders"},
}
servicemeshGVRs := []schema.GroupVersionResource{
{Group: "servicemesh.kubesphere.io", Version: "v1alpha2", Resource: "strategies"},
{Group: "servicemesh.kubesphere.io", Version: "v1alpha2", Resource: "servicepolicies"},
}
// skip caching devops resources if devops not enabled
if s.DevopsClient != nil {
ksGVRs = append(ksGVRs, devopsGVRs...)
}
// skip caching servicemesh resources if servicemesh not enabled
if s.KubernetesClient.Istio() != nil {
ksGVRs = append(ksGVRs, servicemeshGVRs...)
}
for _, gvr := range ksGVRs {
if !isResourceExists(gvr) {
klog.Warningf("resource %s not exists in the cluster", gvr)
} else {
_, err := ksInformerFactory.ForResource(gvr)
if err != nil {
return err
}
}
}
ksInformerFactory.Start(stopCh)
ksInformerFactory.WaitForCacheSync(stopCh)
appInformerFactory := s.InformerFactory.ApplicationSharedInformerFactory()
appGVRs := []schema.GroupVersionResource{
{Group: "app.k8s.io", Version: "v1beta1", Resource: "applications"},
}
for _, gvr := range appGVRs {
if !isResourceExists(gvr) {
klog.Warningf("resource %s not exists in the cluster", gvr)
} else {
_, err := appInformerFactory.ForResource(gvr)
if err != nil {
return err
}
}
}
appInformerFactory.Start(stopCh)
appInformerFactory.WaitForCacheSync(stopCh)
klog.V(0).Info("Finished caching objects")
return nil
resourcev1alpha3.AddWebService(s.container, s.kubeClient)
}
func (s *APIServer) Serve() error {
panic("implement me")
func logStackOnRecover(panicReason interface{}, w http.ResponseWriter) {
var buffer bytes.Buffer
buffer.WriteString(fmt.Sprintf("recover from panic situation: - %v\r\n", panicReason))
for i := 2; ; i += 1 {
_, file, line, ok := rt.Caller(i)
if !ok {
break
}
buffer.WriteString(fmt.Sprintf(" %s:%d\r\n", file, line))
}
klog.Errorln(buffer.String())
headers := http.Header{}
if ct := w.Header().Get("Content-Type"); len(ct) > 0 {
headers.Set("Accept", ct)
}
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal server error"))
}
func logRequestAndResponse(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
start := time.Now()
chain.ProcessFilter(req, resp)
klog.V(4).Infof("%s - \"%s %s %s\" %d %d %dms",
getRequestIP(req),
req.Request.Method,
req.Request.RequestURI,
req.Request.Proto,
resp.StatusCode(),
resp.ContentLength(),
time.Since(start)/time.Millisecond,
)
}
func getRequestIP(req *restful.Request) string {
address := strings.Trim(req.Request.Header.Get("X-Real-Ip"), " ")
if address != "" {
return address
}
address = strings.Trim(req.Request.Header.Get("X-Forwarded-For"), " ")
if address != "" {
return address
}
address, _, err := net.SplitHostPort(req.Request.RemoteAddr)
if err != nil {
return req.Request.RemoteAddr
}
return address
}

View File

@@ -5,7 +5,7 @@ import (
"github.com/emicklei/go-restful"
"github.com/spf13/viper"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api/iam"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/simple/client/alerting"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
@@ -49,12 +49,100 @@ import (
//
// --mysql-username root --mysql-password password
//
// we will `root:password@mysql.kubesphere-system.svc` as input, case
// we will `root:password@mysql.kubesphere-system.svc` as input, cause
// mysql-host is missing in command line flags, all other mysql command line flags
// will be ignored.
const (
// DefaultConfigurationName is the default name of configuration
defaultConfigurationName = "kubesphere"
// DefaultConfigurationPath the default location of the configuration file
defaultConfigurationPath = "/etc/kubesphere"
)
// Config defines everything needed for apiserver to deal with external services
type Config struct {
MySQLOptions *mysql.Options `json:"mysql,omitempty" yaml:"mysql,omitempty" mapstructure:"mysql"`
DevopsOptions *jenkins.Options `json:"devops,omitempty" yaml:"devops,omitempty" mapstructure:"devops"`
SonarQubeOptions *sonarqube.Options `json:"sonarqube,omitempty" yaml:"sonarQube,omitempty" mapstructure:"sonarqube"`
KubernetesOptions *k8s.KubernetesOptions `json:"kubernetes,omitempty" yaml:"kubernetes,omitempty" mapstructure:"kubernetes"`
ServiceMeshOptions *servicemesh.Options `json:"servicemesh,omitempty" yaml:"servicemesh,omitempty" mapstructure:"servicemesh"`
LdapOptions *ldap.Options `json:"ldap,omitempty" yaml:"ldap,omitempty" mapstructure:"ldap"`
RedisOptions *cache.Options `json:"redis,omitempty" yaml:"redis,omitempty" mapstructure:"redis"`
S3Options *s3.Options `json:"s3,omitempty" yaml:"s3,omitempty" mapstructure:"s3"`
OpenPitrixOptions *openpitrix.Options `json:"openpitrix,omitempty" yaml:"openpitrix,omitempty" mapstructure:"openpitrix"`
MonitoringOptions *prometheus.Options `json:"monitoring,omitempty" yaml:"monitoring,omitempty" mapstructure:"monitoring"`
LoggingOptions *elasticsearch.Options `json:"logging,omitempty" yaml:"logging,omitempty" mapstructure:"logging"`
// Options below are only loaded from configuration file, no command line flags for these options now.
KubeSphereOptions *kubesphere.Options `json:"-" yaml:"kubesphere,omitempty" mapstructure:"kubesphere"`
AuthenticateOptions *iam.AuthenticationOptions `json:"authenticate,omitempty" yaml:"authenticate,omitempty" mapstructure:"authenticate"`
// Options used for enabling components, not actually used now. Once we switch Alerting/Notification API to kubesphere,
// we can add these options to kubesphere command lines
AlertingOptions *alerting.Options `json:"alerting,omitempty" yaml:"alerting,omitempty" mapstructure:"alerting"`
NotificationOptions *notification.Options `json:"notification,omitempty" yaml:"notification,omitempty" mapstructure:"notification"`
}
// newConfig creates a default non-empty Config
func New() *Config {
return &Config{
MySQLOptions: mysql.NewMySQLOptions(),
DevopsOptions: jenkins.NewDevopsOptions(),
SonarQubeOptions: sonarqube.NewSonarQubeOptions(),
KubernetesOptions: k8s.NewKubernetesOptions(),
ServiceMeshOptions: servicemesh.NewServiceMeshOptions(),
LdapOptions: ldap.NewOptions(),
RedisOptions: cache.NewRedisOptions(),
S3Options: s3.NewS3Options(),
OpenPitrixOptions: openpitrix.NewOptions(),
MonitoringOptions: prometheus.NewPrometheusOptions(),
KubeSphereOptions: kubesphere.NewKubeSphereOptions(),
AlertingOptions: alerting.NewAlertingOptions(),
NotificationOptions: notification.NewNotificationOptions(),
LoggingOptions: elasticsearch.NewElasticSearchOptions(),
AuthenticateOptions: iam.NewAuthenticateOptions(),
}
}
// TryLoadFromDisk loads configuration from default location after server startup
// return nil error if configuration file not exists
func TryLoadFromDisk() (*Config, error) {
viper.SetConfigName(defaultConfigurationName)
viper.AddConfigPath(defaultConfigurationPath)
// Load from current working directory, only used for debugging
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
return nil, err
} else {
return nil, fmt.Errorf("error parsing configuration file %s", err)
}
}
conf := New()
if err := viper.Unmarshal(conf); err != nil {
return nil, err
} else {
// make sure kubesphere options always exists
if conf.KubeSphereOptions == nil {
conf.KubeSphereOptions = kubesphere.NewKubeSphereOptions()
} else {
ksOptions := kubesphere.NewKubeSphereOptions()
conf.KubeSphereOptions.ApplyTo(ksOptions)
conf.KubeSphereOptions = ksOptions
}
}
return conf, nil
}
// InstallAPI installs api for config
func InstallAPI(c *restful.Container) {
func (conf *Config) InstallAPI(c *restful.Container) {
ws := runtime.NewWebService(schema.GroupVersion{
Group: "",
Version: "v1alpha1",
@@ -62,11 +150,8 @@ func InstallAPI(c *restful.Container) {
ws.Route(ws.GET("/configz").
To(func(request *restful.Request, response *restful.Response) {
var conf = *sharedConfig
conf.stripEmptyOptions()
response.WriteAsJson(convertToMap(&conf))
response.WriteAsJson(conf.toMap())
}).
Doc("Get system components configuration").
Produces(restful.MIME_JSON).
@@ -78,7 +163,7 @@ func InstallAPI(c *restful.Container) {
// convertToMap simply converts config to map[string]bool
// to hide sensitive information
func convertToMap(conf *Config) map[string]bool {
func (conf *Config) toMap() map[string]bool {
result := make(map[string]bool, 0)
if conf == nil {
@@ -103,206 +188,56 @@ func convertToMap(conf *Config) map[string]bool {
return result
}
// Load loads configuration after setup
func Load() error {
sharedConfig = newConfig()
viper.SetConfigName(DefaultConfigurationName)
viper.AddConfigPath(DefaultConfigurationPath)
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
klog.Warning("configuration file not found")
return nil
} else {
panic(fmt.Errorf("error parsing configuration file %s", err))
}
func (conf *Config) stripEmptyOptions() {
if conf.MySQLOptions != nil && conf.MySQLOptions.Host == "" {
conf.MySQLOptions = nil
}
conf := newConfig()
if err := viper.Unmarshal(conf); err != nil {
klog.Error(fmt.Errorf("error unmarshal configuration %v", err))
return err
} else {
// make sure kubesphere options always exists
if conf.KubeSphereOptions == nil {
conf.KubeSphereOptions = kubesphere.NewKubeSphereOptions()
} else {
ksOptions := kubesphere.NewKubeSphereOptions()
conf.KubeSphereOptions.ApplyTo(ksOptions)
conf.KubeSphereOptions = ksOptions
}
conf.Apply(shadowConfig)
sharedConfig = conf
if conf.RedisOptions != nil && conf.RedisOptions.RedisURL == "" {
conf.RedisOptions = nil
}
return nil
}
const (
// DefaultConfigurationName is the default name of configuration
DefaultConfigurationName = "kubesphere"
// DefaultConfigurationPath the default location of the configuration file
DefaultConfigurationPath = "/etc/kubesphere"
)
var (
// sharedConfig holds configuration across kubesphere
sharedConfig *Config
// shadowConfig contains options from commandline options
shadowConfig = &Config{}
)
type Config struct {
MySQLOptions *mysql.Options `json:"mysql,omitempty" yaml:"mysql,omitempty" mapstructure:"mysql"`
DevopsOptions *jenkins.Options `json:"devops,omitempty" yaml:"devops,omitempty" mapstructure:"devops"`
SonarQubeOptions *sonarqube.Options `json:"sonarqube,omitempty" yaml:"sonarQube,omitempty" mapstructure:"sonarqube"`
KubernetesOptions *k8s.KubernetesOptions `json:"kubernetes,omitempty" yaml:"kubernetes,omitempty" mapstructure:"kubernetes"`
ServiceMeshOptions *servicemesh.Options `json:"servicemesh,omitempty" yaml:"servicemesh,omitempty" mapstructure:"servicemesh"`
LdapOptions *ldap.Options `json:"ldap,omitempty" yaml:"ldap,omitempty" mapstructure:"ldap"`
RedisOptions *cache.Options `json:"redis,omitempty" yaml:"redis,omitempty" mapstructure:"redis"`
S3Options *s3.Options `json:"s3,omitempty" yaml:"s3,omitempty" mapstructure:"s3"`
OpenPitrixOptions *openpitrix.Options `json:"openpitrix,omitempty" yaml:"openpitrix,omitempty" mapstructure:"openpitrix"`
MonitoringOptions *prometheus.Options `json:"monitoring,omitempty" yaml:"monitoring,omitempty" mapstructure:"monitoring"`
LoggingOptions *elasticsearch.Options `json:"logging,omitempty" yaml:"logging,omitempty" mapstructure:"logging"`
// Options below are only loaded from configuration file, no command line flags for these options now.
KubeSphereOptions *kubesphere.Options `json:"-" yaml:"kubesphere,omitempty" mapstructure:"kubesphere"`
// Options used for enabling components, not actually used now. Once we switch Alerting/Notification API to kubesphere,
// we can add these options to kubesphere command lines
AlertingOptions *alerting.Options `json:"alerting,omitempty" yaml:"alerting,omitempty" mapstructure:"alerting"`
NotificationOptions *notification.Options `json:"notification,omitempty" yaml:"notification,omitempty" mapstructure:"notification"`
}
func newConfig() *Config {
return &Config{
MySQLOptions: mysql.NewMySQLOptions(),
DevopsOptions: jenkins.NewDevopsOptions(),
SonarQubeOptions: sonarqube.NewSonarQubeOptions(),
KubernetesOptions: k8s.NewKubernetesOptions(),
ServiceMeshOptions: servicemesh.NewServiceMeshOptions(),
LdapOptions: ldap.NewOptions(),
RedisOptions: cache.NewRedisOptions(),
S3Options: s3.NewS3Options(),
OpenPitrixOptions: openpitrix.NewOptions(),
MonitoringOptions: prometheus.NewPrometheusOptions(),
KubeSphereOptions: kubesphere.NewKubeSphereOptions(),
AlertingOptions: alerting.NewAlertingOptions(),
NotificationOptions: notification.NewNotificationOptions(),
LoggingOptions: elasticsearch.NewElasticSearchOptions(),
}
}
func Get() *Config {
return sharedConfig
}
func (c *Config) Apply(conf *Config) {
shadowConfig = conf
if conf.LoggingOptions != nil {
conf.LoggingOptions.ApplyTo(c.LoggingOptions)
if conf.DevopsOptions != nil && conf.DevopsOptions.Host == "" {
conf.DevopsOptions = nil
}
if conf.KubeSphereOptions != nil {
conf.KubeSphereOptions.ApplyTo(c.KubeSphereOptions)
if conf.MonitoringOptions != nil && conf.MonitoringOptions.Endpoint == "" &&
conf.MonitoringOptions.SecondaryEndpoint == "" {
conf.MonitoringOptions = nil
}
if conf.MonitoringOptions != nil {
conf.MonitoringOptions.ApplyTo(c.MonitoringOptions)
}
if conf.OpenPitrixOptions != nil {
conf.OpenPitrixOptions.ApplyTo(c.OpenPitrixOptions)
if conf.SonarQubeOptions != nil && conf.SonarQubeOptions.Host == "" {
conf.SonarQubeOptions = nil
}
if conf.S3Options != nil {
conf.S3Options.ApplyTo(c.S3Options)
if conf.LdapOptions != nil && conf.LdapOptions.Host == "" {
conf.LdapOptions = nil
}
if conf.RedisOptions != nil {
conf.RedisOptions.ApplyTo(c.RedisOptions)
if conf.OpenPitrixOptions != nil && conf.OpenPitrixOptions.IsEmpty() {
conf.OpenPitrixOptions = nil
}
if conf.LdapOptions != nil {
conf.LdapOptions.ApplyTo(c.LdapOptions)
if conf.ServiceMeshOptions != nil && conf.ServiceMeshOptions.IstioPilotHost == "" &&
conf.ServiceMeshOptions.ServicemeshPrometheusHost == "" &&
conf.ServiceMeshOptions.JaegerQueryHost == "" {
conf.ServiceMeshOptions = nil
}
if conf.ServiceMeshOptions != nil {
conf.ServiceMeshOptions.ApplyTo(c.ServiceMeshOptions)
if conf.S3Options != nil && conf.S3Options.Endpoint == "" {
conf.S3Options = nil
}
if conf.KubernetesOptions != nil {
conf.KubernetesOptions.ApplyTo(c.KubernetesOptions)
if conf.AlertingOptions != nil && conf.AlertingOptions.Endpoint == "" {
conf.AlertingOptions = nil
}
if conf.SonarQubeOptions != nil {
conf.SonarQubeOptions.ApplyTo(c.SonarQubeOptions)
if conf.LoggingOptions != nil && conf.LoggingOptions.Host == "" {
conf.LoggingOptions = nil
}
if conf.DevopsOptions != nil {
conf.DevopsOptions.ApplyTo(c.DevopsOptions)
}
if conf.MySQLOptions != nil {
conf.MySQLOptions.ApplyTo(c.MySQLOptions)
}
}
func (c *Config) stripEmptyOptions() {
if c.MySQLOptions != nil && c.MySQLOptions.Host == "" {
c.MySQLOptions = nil
}
if c.RedisOptions != nil && c.RedisOptions.RedisURL == "" {
c.RedisOptions = nil
}
if c.DevopsOptions != nil && c.DevopsOptions.Host == "" {
c.DevopsOptions = nil
}
if c.MonitoringOptions != nil && c.MonitoringOptions.Endpoint == "" &&
c.MonitoringOptions.SecondaryEndpoint == "" {
c.MonitoringOptions = nil
}
if c.SonarQubeOptions != nil && c.SonarQubeOptions.Host == "" {
c.SonarQubeOptions = nil
}
if c.LdapOptions != nil && c.LdapOptions.Host == "" {
c.LdapOptions = nil
}
if c.OpenPitrixOptions != nil && c.OpenPitrixOptions.IsEmpty() {
c.OpenPitrixOptions = nil
}
if c.ServiceMeshOptions != nil && c.ServiceMeshOptions.IstioPilotHost == "" &&
c.ServiceMeshOptions.ServicemeshPrometheusHost == "" &&
c.ServiceMeshOptions.JaegerQueryHost == "" {
c.ServiceMeshOptions = nil
}
if c.S3Options != nil && c.S3Options.Endpoint == "" {
c.S3Options = nil
}
if c.AlertingOptions != nil && c.AlertingOptions.Endpoint == "" {
c.AlertingOptions = nil
}
if c.LoggingOptions != nil && c.LoggingOptions.Host == "" {
c.LoggingOptions = nil
}
if c.NotificationOptions != nil && c.NotificationOptions.Endpoint == "" {
c.NotificationOptions = nil
if conf.NotificationOptions != nil && conf.NotificationOptions.Endpoint == "" {
conf.NotificationOptions = nil
}
}

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"gopkg.in/yaml.v2"
"io/ioutil"
iamapi "kubesphere.io/kubesphere/pkg/api/iam"
"kubesphere.io/kubesphere/pkg/simple/client/alerting"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
"kubesphere.io/kubesphere/pkg/simple/client/devops/jenkins"
@@ -102,6 +103,13 @@ func newTestConfig() *Config {
NotificationOptions: &notification.Options{
Endpoint: "http://notification.kubesphere-alerting-system.svc:9200",
},
AuthenticateOptions: &iamapi.AuthenticationOptions{
AuthenticateRateLimiterMaxTries: 5,
AuthenticateRateLimiterDuration: 30 * time.Minute,
MaxAuthenticateRetries: 6,
TokenExpiration: 30 * time.Minute,
MultipleLogin: false,
},
}
return conf
}
@@ -112,14 +120,14 @@ func saveTestConfig(t *testing.T, conf *Config) {
t.Fatalf("error marshal config. %v", err)
}
err = ioutil.WriteFile(fmt.Sprintf("%s.yaml", DefaultConfigurationName), content, 0640)
err = ioutil.WriteFile(fmt.Sprintf("%s.yaml", defaultConfigurationName), content, 0640)
if err != nil {
t.Fatalf("error write configuration file, %v", err)
}
}
func cleanTestConfig(t *testing.T) {
file := fmt.Sprintf("%s.yaml", DefaultConfigurationName)
file := fmt.Sprintf("%s.yaml", defaultConfigurationName)
if _, err := os.Stat(file); os.IsNotExist(err) {
t.Log("file not exists, skipping")
return
@@ -137,11 +145,10 @@ func TestGet(t *testing.T) {
saveTestConfig(t, conf)
defer cleanTestConfig(t)
err := Load()
conf2, err := TryLoadFromDisk()
if err != nil {
t.Fatal(err)
}
conf2 := Get()
if diff := reflectutils.Equal(conf, conf2); diff != nil {
t.Fatal(diff)
@@ -157,11 +164,10 @@ func TestKubeSphereOptions(t *testing.T) {
saveTestConfig(t, &savedConf)
defer cleanTestConfig(t)
err := Load()
loadedConf, err := TryLoadFromDisk()
if err != nil {
t.Fatal(err)
}
loadedConf := Get()
if diff := reflectutils.Equal(conf, loadedConf); diff != nil {
t.Fatal(diff)
@@ -176,11 +182,10 @@ func TestKubeSphereOptions(t *testing.T) {
saveTestConfig(t, &savedConf)
defer cleanTestConfig(t)
err := Load()
loadedConf, err := TryLoadFromDisk()
if err != nil {
t.Fatal(err)
}
loadedConf := Get()
savedConf.KubeSphereOptions.AccountServer = "http://ks-account.kubesphere-system.svc"

View File

@@ -6,6 +6,7 @@ const (
FieldName = "name"
FieldCreationTimeStamp = "creationTimestamp"
FieldLastUpdateTimestamp = "lastUpdateTimestamp"
FieldLabel = "label"
FieldNamespace = "namespace"
FieldStatus = "status"
FieldApplication = "application"

View File

@@ -27,6 +27,9 @@ import (
type DevopsV1alpha1Interface interface {
RESTClient() rest.Interface
S2iBinariesGetter
S2iBuildersGetter
S2iBuilderTemplatesGetter
S2iRunsGetter
}
// DevopsV1alpha1Client is used to interact with features provided by the devops.kubesphere.io group.
@@ -38,6 +41,18 @@ func (c *DevopsV1alpha1Client) S2iBinaries(namespace string) S2iBinaryInterface
return newS2iBinaries(c, namespace)
}
func (c *DevopsV1alpha1Client) S2iBuilders(namespace string) S2iBuilderInterface {
return newS2iBuilders(c, namespace)
}
func (c *DevopsV1alpha1Client) S2iBuilderTemplates() S2iBuilderTemplateInterface {
return newS2iBuilderTemplates(c)
}
func (c *DevopsV1alpha1Client) S2iRuns(namespace string) S2iRunInterface {
return newS2iRuns(c, namespace)
}
// NewForConfig creates a new DevopsV1alpha1Client for the given config.
func NewForConfig(c *rest.Config) (*DevopsV1alpha1Client, error) {
config := *c

View File

@@ -32,6 +32,18 @@ func (c *FakeDevopsV1alpha1) S2iBinaries(namespace string) v1alpha1.S2iBinaryInt
return &FakeS2iBinaries{c, namespace}
}
func (c *FakeDevopsV1alpha1) S2iBuilders(namespace string) v1alpha1.S2iBuilderInterface {
return &FakeS2iBuilders{c, namespace}
}
func (c *FakeDevopsV1alpha1) S2iBuilderTemplates() v1alpha1.S2iBuilderTemplateInterface {
return &FakeS2iBuilderTemplates{c}
}
func (c *FakeDevopsV1alpha1) S2iRuns(namespace string) v1alpha1.S2iRunInterface {
return &FakeS2iRuns{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeDevopsV1alpha1) RESTClient() rest.Interface {

View File

@@ -0,0 +1,140 @@
/*
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
v1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
)
// FakeS2iBuilders implements S2iBuilderInterface
type FakeS2iBuilders struct {
Fake *FakeDevopsV1alpha1
ns string
}
var s2ibuildersResource = schema.GroupVersionResource{Group: "devops.kubesphere.io", Version: "v1alpha1", Resource: "s2ibuilders"}
var s2ibuildersKind = schema.GroupVersionKind{Group: "devops.kubesphere.io", Version: "v1alpha1", Kind: "S2iBuilder"}
// Get takes name of the s2iBuilder, and returns the corresponding s2iBuilder object, and an error if there is any.
func (c *FakeS2iBuilders) Get(name string, options v1.GetOptions) (result *v1alpha1.S2iBuilder, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(s2ibuildersResource, c.ns, name), &v1alpha1.S2iBuilder{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iBuilder), err
}
// List takes label and field selectors, and returns the list of S2iBuilders that match those selectors.
func (c *FakeS2iBuilders) List(opts v1.ListOptions) (result *v1alpha1.S2iBuilderList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(s2ibuildersResource, s2ibuildersKind, c.ns, opts), &v1alpha1.S2iBuilderList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha1.S2iBuilderList{ListMeta: obj.(*v1alpha1.S2iBuilderList).ListMeta}
for _, item := range obj.(*v1alpha1.S2iBuilderList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested s2iBuilders.
func (c *FakeS2iBuilders) Watch(opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(s2ibuildersResource, c.ns, opts))
}
// Create takes the representation of a s2iBuilder and creates it. Returns the server's representation of the s2iBuilder, and an error, if there is any.
func (c *FakeS2iBuilders) Create(s2iBuilder *v1alpha1.S2iBuilder) (result *v1alpha1.S2iBuilder, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(s2ibuildersResource, c.ns, s2iBuilder), &v1alpha1.S2iBuilder{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iBuilder), err
}
// Update takes the representation of a s2iBuilder and updates it. Returns the server's representation of the s2iBuilder, and an error, if there is any.
func (c *FakeS2iBuilders) Update(s2iBuilder *v1alpha1.S2iBuilder) (result *v1alpha1.S2iBuilder, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(s2ibuildersResource, c.ns, s2iBuilder), &v1alpha1.S2iBuilder{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iBuilder), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeS2iBuilders) UpdateStatus(s2iBuilder *v1alpha1.S2iBuilder) (*v1alpha1.S2iBuilder, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(s2ibuildersResource, "status", c.ns, s2iBuilder), &v1alpha1.S2iBuilder{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iBuilder), err
}
// Delete takes name of the s2iBuilder and deletes it. Returns an error if one occurs.
func (c *FakeS2iBuilders) Delete(name string, options *v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(s2ibuildersResource, c.ns, name), &v1alpha1.S2iBuilder{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeS2iBuilders) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(s2ibuildersResource, c.ns, listOptions)
_, err := c.Fake.Invokes(action, &v1alpha1.S2iBuilderList{})
return err
}
// Patch applies the patch and returns the patched s2iBuilder.
func (c *FakeS2iBuilders) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.S2iBuilder, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(s2ibuildersResource, c.ns, name, pt, data, subresources...), &v1alpha1.S2iBuilder{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iBuilder), err
}

View File

@@ -0,0 +1,131 @@
/*
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
v1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
)
// FakeS2iBuilderTemplates implements S2iBuilderTemplateInterface
type FakeS2iBuilderTemplates struct {
Fake *FakeDevopsV1alpha1
}
var s2ibuildertemplatesResource = schema.GroupVersionResource{Group: "devops.kubesphere.io", Version: "v1alpha1", Resource: "s2ibuildertemplates"}
var s2ibuildertemplatesKind = schema.GroupVersionKind{Group: "devops.kubesphere.io", Version: "v1alpha1", Kind: "S2iBuilderTemplate"}
// Get takes name of the s2iBuilderTemplate, and returns the corresponding s2iBuilderTemplate object, and an error if there is any.
func (c *FakeS2iBuilderTemplates) Get(name string, options v1.GetOptions) (result *v1alpha1.S2iBuilderTemplate, err error) {
obj, err := c.Fake.
Invokes(testing.NewRootGetAction(s2ibuildertemplatesResource, name), &v1alpha1.S2iBuilderTemplate{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iBuilderTemplate), err
}
// List takes label and field selectors, and returns the list of S2iBuilderTemplates that match those selectors.
func (c *FakeS2iBuilderTemplates) List(opts v1.ListOptions) (result *v1alpha1.S2iBuilderTemplateList, err error) {
obj, err := c.Fake.
Invokes(testing.NewRootListAction(s2ibuildertemplatesResource, s2ibuildertemplatesKind, opts), &v1alpha1.S2iBuilderTemplateList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha1.S2iBuilderTemplateList{ListMeta: obj.(*v1alpha1.S2iBuilderTemplateList).ListMeta}
for _, item := range obj.(*v1alpha1.S2iBuilderTemplateList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested s2iBuilderTemplates.
func (c *FakeS2iBuilderTemplates) Watch(opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewRootWatchAction(s2ibuildertemplatesResource, opts))
}
// Create takes the representation of a s2iBuilderTemplate and creates it. Returns the server's representation of the s2iBuilderTemplate, and an error, if there is any.
func (c *FakeS2iBuilderTemplates) Create(s2iBuilderTemplate *v1alpha1.S2iBuilderTemplate) (result *v1alpha1.S2iBuilderTemplate, err error) {
obj, err := c.Fake.
Invokes(testing.NewRootCreateAction(s2ibuildertemplatesResource, s2iBuilderTemplate), &v1alpha1.S2iBuilderTemplate{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iBuilderTemplate), err
}
// Update takes the representation of a s2iBuilderTemplate and updates it. Returns the server's representation of the s2iBuilderTemplate, and an error, if there is any.
func (c *FakeS2iBuilderTemplates) Update(s2iBuilderTemplate *v1alpha1.S2iBuilderTemplate) (result *v1alpha1.S2iBuilderTemplate, err error) {
obj, err := c.Fake.
Invokes(testing.NewRootUpdateAction(s2ibuildertemplatesResource, s2iBuilderTemplate), &v1alpha1.S2iBuilderTemplate{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iBuilderTemplate), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeS2iBuilderTemplates) UpdateStatus(s2iBuilderTemplate *v1alpha1.S2iBuilderTemplate) (*v1alpha1.S2iBuilderTemplate, error) {
obj, err := c.Fake.
Invokes(testing.NewRootUpdateSubresourceAction(s2ibuildertemplatesResource, "status", s2iBuilderTemplate), &v1alpha1.S2iBuilderTemplate{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iBuilderTemplate), err
}
// Delete takes name of the s2iBuilderTemplate and deletes it. Returns an error if one occurs.
func (c *FakeS2iBuilderTemplates) Delete(name string, options *v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewRootDeleteAction(s2ibuildertemplatesResource, name), &v1alpha1.S2iBuilderTemplate{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeS2iBuilderTemplates) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
action := testing.NewRootDeleteCollectionAction(s2ibuildertemplatesResource, listOptions)
_, err := c.Fake.Invokes(action, &v1alpha1.S2iBuilderTemplateList{})
return err
}
// Patch applies the patch and returns the patched s2iBuilderTemplate.
func (c *FakeS2iBuilderTemplates) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.S2iBuilderTemplate, err error) {
obj, err := c.Fake.
Invokes(testing.NewRootPatchSubresourceAction(s2ibuildertemplatesResource, name, pt, data, subresources...), &v1alpha1.S2iBuilderTemplate{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iBuilderTemplate), err
}

View File

@@ -0,0 +1,140 @@
/*
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
v1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
)
// FakeS2iRuns implements S2iRunInterface
type FakeS2iRuns struct {
Fake *FakeDevopsV1alpha1
ns string
}
var s2irunsResource = schema.GroupVersionResource{Group: "devops.kubesphere.io", Version: "v1alpha1", Resource: "s2iruns"}
var s2irunsKind = schema.GroupVersionKind{Group: "devops.kubesphere.io", Version: "v1alpha1", Kind: "S2iRun"}
// Get takes name of the s2iRun, and returns the corresponding s2iRun object, and an error if there is any.
func (c *FakeS2iRuns) Get(name string, options v1.GetOptions) (result *v1alpha1.S2iRun, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(s2irunsResource, c.ns, name), &v1alpha1.S2iRun{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iRun), err
}
// List takes label and field selectors, and returns the list of S2iRuns that match those selectors.
func (c *FakeS2iRuns) List(opts v1.ListOptions) (result *v1alpha1.S2iRunList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(s2irunsResource, s2irunsKind, c.ns, opts), &v1alpha1.S2iRunList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha1.S2iRunList{ListMeta: obj.(*v1alpha1.S2iRunList).ListMeta}
for _, item := range obj.(*v1alpha1.S2iRunList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested s2iRuns.
func (c *FakeS2iRuns) Watch(opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(s2irunsResource, c.ns, opts))
}
// Create takes the representation of a s2iRun and creates it. Returns the server's representation of the s2iRun, and an error, if there is any.
func (c *FakeS2iRuns) Create(s2iRun *v1alpha1.S2iRun) (result *v1alpha1.S2iRun, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(s2irunsResource, c.ns, s2iRun), &v1alpha1.S2iRun{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iRun), err
}
// Update takes the representation of a s2iRun and updates it. Returns the server's representation of the s2iRun, and an error, if there is any.
func (c *FakeS2iRuns) Update(s2iRun *v1alpha1.S2iRun) (result *v1alpha1.S2iRun, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(s2irunsResource, c.ns, s2iRun), &v1alpha1.S2iRun{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iRun), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeS2iRuns) UpdateStatus(s2iRun *v1alpha1.S2iRun) (*v1alpha1.S2iRun, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(s2irunsResource, "status", c.ns, s2iRun), &v1alpha1.S2iRun{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iRun), err
}
// Delete takes name of the s2iRun and deletes it. Returns an error if one occurs.
func (c *FakeS2iRuns) Delete(name string, options *v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(s2irunsResource, c.ns, name), &v1alpha1.S2iRun{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeS2iRuns) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(s2irunsResource, c.ns, listOptions)
_, err := c.Fake.Invokes(action, &v1alpha1.S2iRunList{})
return err
}
// Patch applies the patch and returns the patched s2iRun.
func (c *FakeS2iRuns) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.S2iRun, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(s2irunsResource, c.ns, name, pt, data, subresources...), &v1alpha1.S2iRun{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.S2iRun), err
}

View File

@@ -19,3 +19,9 @@ limitations under the License.
package v1alpha1
type S2iBinaryExpansion interface{}
type S2iBuilderExpansion interface{}
type S2iBuilderTemplateExpansion interface{}
type S2iRunExpansion interface{}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubesphere Authors.
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.
@@ -13,6 +13,7 @@ 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
@@ -20,12 +21,12 @@ package v1alpha1
import (
"time"
v1alpha1 "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
scheme "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
v1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme"
)
// S2iBuildersGetter has a method to return a S2iBuilderInterface.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubesphere Authors.
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.
@@ -13,6 +13,7 @@ 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
@@ -20,12 +21,12 @@ package v1alpha1
import (
"time"
v1alpha1 "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
scheme "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
v1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme"
)
// S2iBuilderTemplatesGetter has a method to return a S2iBuilderTemplateInterface.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubesphere Authors.
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.
@@ -13,6 +13,7 @@ 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
@@ -20,12 +21,12 @@ package v1alpha1
import (
"time"
v1alpha1 "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
scheme "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
v1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme"
)
// S2iRunsGetter has a method to return a S2iRunInterface.

View File

@@ -26,6 +26,12 @@ import (
type Interface interface {
// S2iBinaries returns a S2iBinaryInformer.
S2iBinaries() S2iBinaryInformer
// S2iBuilders returns a S2iBuilderInformer.
S2iBuilders() S2iBuilderInformer
// S2iBuilderTemplates returns a S2iBuilderTemplateInformer.
S2iBuilderTemplates() S2iBuilderTemplateInformer
// S2iRuns returns a S2iRunInformer.
S2iRuns() S2iRunInformer
}
type version struct {
@@ -43,3 +49,18 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
func (v *version) S2iBinaries() S2iBinaryInformer {
return &s2iBinaryInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// S2iBuilders returns a S2iBuilderInformer.
func (v *version) S2iBuilders() S2iBuilderInformer {
return &s2iBuilderInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// S2iBuilderTemplates returns a S2iBuilderTemplateInformer.
func (v *version) S2iBuilderTemplates() S2iBuilderTemplateInformer {
return &s2iBuilderTemplateInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
}
// S2iRuns returns a S2iRunInformer.
func (v *version) S2iRuns() S2iRunInformer {
return &s2iRunInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubesphere Authors.
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.
@@ -13,6 +13,7 @@ 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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
@@ -20,14 +21,14 @@ package v1alpha1
import (
time "time"
devopsv1alpha1 "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
versioned "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned"
internalinterfaces "github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions/internalinterfaces"
v1alpha1 "github.com/kubesphere/s2ioperator/pkg/client/listers/devops/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces"
v1alpha1 "kubesphere.io/kubesphere/pkg/client/listers/devops/v1alpha1"
)
// S2iBuilderInformer provides access to a shared informer and lister for

View File

@@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubesphere Authors.
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.
@@ -13,6 +13,7 @@ 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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
@@ -20,14 +21,14 @@ package v1alpha1
import (
time "time"
devopsv1alpha1 "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
versioned "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned"
internalinterfaces "github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions/internalinterfaces"
v1alpha1 "github.com/kubesphere/s2ioperator/pkg/client/listers/devops/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces"
v1alpha1 "kubesphere.io/kubesphere/pkg/client/listers/devops/v1alpha1"
)
// S2iBuilderTemplateInformer provides access to a shared informer and lister for

View File

@@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubesphere Authors.
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.
@@ -13,6 +13,7 @@ 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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
@@ -20,14 +21,14 @@ package v1alpha1
import (
time "time"
devopsv1alpha1 "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
versioned "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned"
internalinterfaces "github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions/internalinterfaces"
v1alpha1 "github.com/kubesphere/s2ioperator/pkg/client/listers/devops/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces"
v1alpha1 "kubesphere.io/kubesphere/pkg/client/listers/devops/v1alpha1"
)
// S2iRunInformer provides access to a shared informer and lister for

View File

@@ -58,6 +58,12 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
// Group=devops.kubesphere.io, Version=v1alpha1
case v1alpha1.SchemeGroupVersion.WithResource("s2ibinaries"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Devops().V1alpha1().S2iBinaries().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("s2ibuilders"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Devops().V1alpha1().S2iBuilders().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("s2ibuildertemplates"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Devops().V1alpha1().S2iBuilderTemplates().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("s2iruns"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Devops().V1alpha1().S2iRuns().Informer()}, nil
// Group=network.kubesphere.io, Version=v1alpha1
case networkv1alpha1.SchemeGroupVersion.WithResource("namespacenetworkpolicies"):

View File

@@ -25,3 +25,23 @@ type S2iBinaryListerExpansion interface{}
// S2iBinaryNamespaceListerExpansion allows custom methods to be added to
// S2iBinaryNamespaceLister.
type S2iBinaryNamespaceListerExpansion interface{}
// S2iBuilderListerExpansion allows custom methods to be added to
// S2iBuilderLister.
type S2iBuilderListerExpansion interface{}
// S2iBuilderNamespaceListerExpansion allows custom methods to be added to
// S2iBuilderNamespaceLister.
type S2iBuilderNamespaceListerExpansion interface{}
// S2iBuilderTemplateListerExpansion allows custom methods to be added to
// S2iBuilderTemplateLister.
type S2iBuilderTemplateListerExpansion interface{}
// S2iRunListerExpansion allows custom methods to be added to
// S2iRunLister.
type S2iRunListerExpansion interface{}
// S2iRunNamespaceListerExpansion allows custom methods to be added to
// S2iRunNamespaceLister.
type S2iRunNamespaceListerExpansion interface{}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubesphere Authors.
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.
@@ -13,15 +13,16 @@ 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.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
import (
v1alpha1 "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
v1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
)
// S2iBuilderLister helps list S2iBuilders.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubesphere Authors.
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.
@@ -13,15 +13,16 @@ 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.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
import (
v1alpha1 "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
v1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
)
// S2iBuilderTemplateLister helps list S2iBuilderTemplates.

View File

@@ -1,5 +1,5 @@
/*
Copyright 2019 The Kubesphere Authors.
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.
@@ -13,15 +13,16 @@ 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.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
import (
v1alpha1 "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
v1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
)
// S2iRunLister helps list S2iRuns.

View File

@@ -1,26 +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 controller
import "kubesphere.io/kubesphere/pkg/controller/clusterrolebinding"
func init() {
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
AddToManagerFuncs = append(AddToManagerFuncs, clusterrolebinding.Add)
}

View File

@@ -1,26 +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 controller
import "kubesphere.io/kubesphere/pkg/controller/namespace"
func init() {
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
AddToManagerFuncs = append(AddToManagerFuncs, namespace.Add)
}

View File

@@ -1,27 +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 controller
import (
"github.com/kubernetes-sigs/application/pkg/controller/application"
)
func init() {
// Add application to manager functions
AddToManagerFuncs = append(AddToManagerFuncs, application.Add)
}

View File

@@ -1,26 +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 controller
import "kubesphere.io/kubesphere/pkg/controller/workspace"
func init() {
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
AddToManagerFuncs = append(AddToManagerFuncs, workspace.Add)
}

View File

@@ -1,34 +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 controller
import (
"sigs.k8s.io/controller-runtime/pkg/manager"
)
// AddToManagerFuncs is a list of functions to add all Controllers to the Manager
var AddToManagerFuncs []func(manager.Manager) error
// AddToManager adds all Controllers to the Manager
func AddToManager(m manager.Manager) error {
for _, f := range AddToManagerFuncs {
if err := f(m); err != nil {
return err
}
}
return nil
}

View File

@@ -69,13 +69,17 @@ var (
// Add creates a new Namespace Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
// and Start it when the Manager is Started.
func Add(mgr manager.Manager) error {
return add(mgr, newReconciler(mgr))
func Add(mgr manager.Manager, openpitrixClient openpitrix.Client) error {
return add(mgr, newReconciler(mgr, openpitrixClient))
}
// newReconciler returns a new reconcile.Reconciler
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
return &ReconcileNamespace{Client: mgr.GetClient(), scheme: mgr.GetScheme()}
func newReconciler(mgr manager.Manager, openpitrixClient openpitrix.Client) reconcile.Reconciler {
return &ReconcileNamespace{
Client: mgr.GetClient(),
scheme: mgr.GetScheme(),
openpitrixClient: openpitrixClient,
}
}
// add adds a new Controller to mgr with r as the reconcile.Reconciler

View File

@@ -18,26 +18,21 @@ import (
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"time"
s2iv1alpha1 "github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
s2iclient "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned"
s2iinformers "github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions/devops/v1alpha1"
s2ilisters "github.com/kubesphere/s2ioperator/pkg/client/listers/devops/v1alpha1"
devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
devopsclient "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
devopsinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions/devops/v1alpha1"
devopslisters "kubesphere.io/kubesphere/pkg/client/listers/devops/v1alpha1"
)
type S2iRunController struct {
client clientset.Interface
s2iClient s2iclient.Interface
type Controller struct {
client clientset.Interface
devopsClient devopsclient.Interface
eventBroadcaster record.EventBroadcaster
eventRecorder record.EventRecorder
s2iRunLister s2ilisters.S2iRunLister
s2iRunLister devopslisters.S2iRunLister
s2iRunSynced cache.InformerSynced
s2iBinaryLister devopslisters.S2iBinaryLister
@@ -48,9 +43,10 @@ type S2iRunController struct {
workerLoopPeriod time.Duration
}
func NewController(devopsclientset devopsclient.Interface, s2iclientset s2iclient.Interface,
func NewS2iRunController(devopsClientSet devopsclient.Interface,
client clientset.Interface,
s2ibinInformer devopsinformers.S2iBinaryInformer, s2iRunInformer s2iinformers.S2iRunInformer) *S2iRunController {
s2iBinInformer devopsinformers.S2iBinaryInformer,
s2iRunInformer devopsinformers.S2iRunInformer) *Controller {
broadcaster := record.NewBroadcaster()
broadcaster.StartLogging(func(format string, args ...interface{}) {
@@ -59,13 +55,12 @@ func NewController(devopsclientset devopsclient.Interface, s2iclientset s2iclien
broadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: client.CoreV1().Events("")})
recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "s2irun-controller"})
v := &S2iRunController{
v := &Controller{
client: client,
devopsClient: devopsclientset,
s2iClient: s2iclientset,
devopsClient: devopsClientSet,
workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "s2irun"),
s2iBinaryLister: s2ibinInformer.Lister(),
s2iBinarySynced: s2ibinInformer.Informer().HasSynced,
s2iBinaryLister: s2iBinInformer.Lister(),
s2iBinarySynced: s2iBinInformer.Informer().HasSynced,
s2iRunLister: s2iRunInformer.Lister(),
s2iRunSynced: s2iRunInformer.Informer().HasSynced,
workerLoopPeriod: time.Second,
@@ -77,8 +72,8 @@ func NewController(devopsclientset devopsclient.Interface, s2iclientset s2iclien
s2iRunInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: v.enqueueS2iRun,
UpdateFunc: func(oldObj, newObj interface{}) {
old := oldObj.(*s2iv1alpha1.S2iRun)
new := newObj.(*s2iv1alpha1.S2iRun)
old := oldObj.(*devopsv1alpha1.S2iRun)
new := newObj.(*devopsv1alpha1.S2iRun)
if old.ResourceVersion == new.ResourceVersion {
return
}
@@ -92,7 +87,7 @@ func NewController(devopsclientset devopsclient.Interface, s2iclientset s2iclien
// enqueueFoo 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 Foo.
func (c *S2iRunController) enqueueS2iRun(obj interface{}) {
func (c Controller) enqueueS2iRun(obj interface{}) {
var key string
var err error
if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
@@ -102,7 +97,7 @@ func (c *S2iRunController) enqueueS2iRun(obj interface{}) {
c.workqueue.Add(key)
}
func (c *S2iRunController) processNextWorkItem() bool {
func (c Controller) processNextWorkItem() bool {
obj, shutdown := c.workqueue.Get()
if shutdown {
@@ -136,17 +131,17 @@ func (c *S2iRunController) processNextWorkItem() bool {
return true
}
func (c *S2iRunController) worker() {
func (c Controller) worker() {
for c.processNextWorkItem() {
}
}
func (c *S2iRunController) Start(stopCh <-chan struct{}) error {
func (c Controller) Start(stopCh <-chan struct{}) error {
return c.Run(1, stopCh)
}
func (c *S2iRunController) Run(workers int, stopCh <-chan struct{}) error {
func (c Controller) Run(workers int, stopCh <-chan struct{}) error {
defer utilruntime.HandleCrash()
defer c.workqueue.ShutDown()
@@ -168,7 +163,7 @@ func (c *S2iRunController) Run(workers int, stopCh <-chan struct{}) error {
// syncHandler compares the actual state with the desired, and attempts to
// converge the two. It then updates the Status block of the Foo resource
// with the current status of the resource.
func (c *S2iRunController) syncHandler(key string) error {
func (c Controller) syncHandler(key string) error {
namespace, name, err := cache.SplitMetaNamespaceKey(key)
if err != nil {
klog.Error(err, fmt.Sprintf("could not split s2irun meta %s ", key))
@@ -189,7 +184,7 @@ func (c *S2iRunController) syncHandler(key string) error {
if s2irun.ObjectMeta.DeletionTimestamp.IsZero() {
if !sliceutil.HasString(s2irun.ObjectMeta.Finalizers, devopsv1alpha1.S2iBinaryFinalizerName) {
s2irun.ObjectMeta.Finalizers = append(s2irun.ObjectMeta.Finalizers, devopsv1alpha1.S2iBinaryFinalizerName)
_, err := c.s2iClient.DevopsV1alpha1().S2iRuns(namespace).Update(s2irun)
_, err = c.devopsClient.DevopsV1alpha1().S2iRuns(namespace).Update(s2irun)
if err != nil {
klog.Error(err, fmt.Sprintf("failed to update s2irun %s", key))
return err
@@ -205,7 +200,7 @@ func (c *S2iRunController) syncHandler(key string) error {
s2irun.ObjectMeta.Finalizers = sliceutil.RemoveString(s2irun.ObjectMeta.Finalizers, func(item string) bool {
return item == devopsv1alpha1.S2iBinaryFinalizerName
})
_, err := c.s2iClient.DevopsV1alpha1().S2iRuns(namespace).Update(s2irun)
_, err = c.devopsClient.DevopsV1alpha1().S2iRuns(namespace).Update(s2irun)
if err != nil {
klog.Error(err, fmt.Sprintf("failed to update s2irun %s ", key))
return err
@@ -218,7 +213,7 @@ func (c *S2iRunController) syncHandler(key string) error {
return nil
}
func (c *S2iRunController) DeleteS2iBinary(s2irun *s2iv1alpha1.S2iRun) error {
func (c Controller) DeleteS2iBinary(s2irun *devopsv1alpha1.S2iRun) error {
s2iBinName := s2irun.Labels[devopsv1alpha1.S2iBinaryLabelKey]
s2iBin, err := c.s2iBinaryLister.S2iBinaries(s2irun.Namespace).Get(s2iBinName)
if err != nil {
@@ -246,7 +241,7 @@ func (c *S2iRunController) DeleteS2iBinary(s2irun *s2iv1alpha1.S2iRun) error {
}
// cleanOtherS2iBinary clean up s2ibinary created for more than 24 hours without associated s2irun
func (c *S2iRunController) cleanOtherS2iBinary(namespace string) error {
func (c Controller) cleanOtherS2iBinary(namespace string) error {
s2iBins, err := c.s2iBinaryLister.S2iBinaries(namespace).List(nil)
if err != nil {
klog.Error(err, fmt.Sprintf("failed to list s2ibin in %s ", namespace))

View File

@@ -29,10 +29,10 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/record"
log "k8s.io/klog"
tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
cs "kubesphere.io/kubesphere/pkg/simple/client"
"kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"reflect"
@@ -42,7 +42,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
"sigs.k8s.io/controller-runtime/pkg/source"
"sync"
)
@@ -53,23 +52,16 @@ const (
workspaceViewerDescription = "Allows viewer access to view all resources in the workspace."
)
var log = logf.Log.WithName("workspace-controller")
/**
* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller
* business logic. Delete these comments after modifying this file.*
*/
// Add creates a new Workspace Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
// and Start it when the Manager is Started.
func Add(mgr manager.Manager) error {
return add(mgr, newReconciler(mgr))
func Add(mgr manager.Manager, kubesphereClient kubesphere.Interface) error {
return add(mgr, newReconciler(mgr, kubesphereClient))
}
// newReconciler returns a new reconcile.Reconciler
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
func newReconciler(mgr manager.Manager, kubesphereClient kubesphere.Interface) reconcile.Reconciler {
return &ReconcileWorkspace{Client: mgr.GetClient(), scheme: mgr.GetScheme(),
recorder: mgr.GetEventRecorderFor("workspace-controller"), ksclient: cs.ClientSets().KubeSphere()}
recorder: mgr.GetEventRecorderFor("workspace-controller"), ksclient: kubesphereClient}
}
// add adds a new Controller to mgr with r as the reconcile.Reconciler
@@ -328,7 +320,6 @@ func (r *ReconcileWorkspace) deleteDevOpsProjects(instance *tenantv1alpha1.Works
log.Info("Delete DevOps Projects")
for {
errChan := make(chan error, 10)
projects, err := r.ksclient.ListWorkspaceDevOpsProjects(instance.Name)
if err != nil {
log.Error(err, "Failed to Get Workspace's DevOps Projects", "ws", instance.Name)
@@ -337,10 +328,11 @@ func (r *ReconcileWorkspace) deleteDevOpsProjects(instance *tenantv1alpha1.Works
if projects.TotalCount == 0 {
return nil
}
errChan := make(chan error, len(projects.Items))
for _, project := range projects.Items {
wg.Add(1)
go func(workspace, devops string) {
err := r.ksclient.DeleteWorkspaceDevOpsProjects(workspace, devops)
err = r.ksclient.DeleteWorkspaceDevOpsProjects(workspace, devops)
errChan <- err
wg.Done()
}(instance.Name, project.ProjectId)

View File

@@ -20,8 +20,8 @@ package informers
import (
applicationclient "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned"
applicationinformers "github.com/kubernetes-sigs/application/pkg/client/informers/externalversions"
s2i "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned"
s2iinformers "github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions"
istioclient "istio.io/client-go/pkg/clientset/versioned"
istioinformers "istio.io/client-go/pkg/informers/externalversions"
k8sinformers "k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/client/clientset/versioned"
@@ -33,19 +33,22 @@ const defaultResync = 600 * time.Second
type InformerFactory interface {
KubernetesSharedInformerFactory() k8sinformers.SharedInformerFactory
S2iSharedInformerFactory() s2iinformers.SharedInformerFactory
KubeSphereSharedInformerFactory() ksinformers.SharedInformerFactory
IstioSharedInformerFactory() istioinformers.SharedInformerFactory
ApplicationSharedInformerFactory() applicationinformers.SharedInformerFactory
// Start all the informer factories if not nil
Start(stopCh <-chan struct{})
}
type informerFactories struct {
informerFactory k8sinformers.SharedInformerFactory
s2iInformerFactory s2iinformers.SharedInformerFactory
ksInformerFactory ksinformers.SharedInformerFactory
appInformerFactory applicationinformers.SharedInformerFactory
informerFactory k8sinformers.SharedInformerFactory
ksInformerFactory ksinformers.SharedInformerFactory
istioInformerFactory istioinformers.SharedInformerFactory
appInformerFactory applicationinformers.SharedInformerFactory
}
func NewInformerFactories(client kubernetes.Interface, ksClient versioned.Interface, s2iClient s2i.Interface, appClient applicationclient.Interface) InformerFactory {
func NewInformerFactories(client kubernetes.Interface, ksClient versioned.Interface, istioClient istioclient.Interface, appClient applicationclient.Interface) InformerFactory {
factory := &informerFactories{}
if client != nil {
@@ -56,14 +59,14 @@ func NewInformerFactories(client kubernetes.Interface, ksClient versioned.Interf
factory.ksInformerFactory = ksinformers.NewSharedInformerFactory(ksClient, defaultResync)
}
if s2iClient != nil {
factory.s2iInformerFactory = s2iinformers.NewSharedInformerFactory(s2iClient, defaultResync)
}
if appClient != nil {
factory.appInformerFactory = applicationinformers.NewSharedInformerFactory(appClient, defaultResync)
}
if istioClient != nil {
factory.istioInformerFactory = istioinformers.NewSharedInformerFactory(istioClient, defaultResync)
}
return factory
}
@@ -71,10 +74,6 @@ func (f *informerFactories) KubernetesSharedInformerFactory() k8sinformers.Share
return f.informerFactory
}
func (f *informerFactories) S2iSharedInformerFactory() s2iinformers.SharedInformerFactory {
return f.s2iInformerFactory
}
func (f *informerFactories) KubeSphereSharedInformerFactory() ksinformers.SharedInformerFactory {
return f.ksInformerFactory
}
@@ -82,3 +81,25 @@ func (f *informerFactories) KubeSphereSharedInformerFactory() ksinformers.Shared
func (f *informerFactories) ApplicationSharedInformerFactory() applicationinformers.SharedInformerFactory {
return f.appInformerFactory
}
func (f *informerFactories) IstioSharedInformerFactory() istioinformers.SharedInformerFactory {
return f.istioInformerFactory
}
func (f *informerFactories) Start(stopCh <-chan struct{}) {
if f.informerFactory != nil {
f.informerFactory.Start(stopCh)
}
if f.ksInformerFactory != nil {
f.ksInformerFactory.Start(stopCh)
}
if f.informerFactory != nil {
f.istioInformerFactory.Start(stopCh)
}
if f.appInformerFactory != nil {
f.appInformerFactory.Start(stopCh)
}
}

View File

@@ -46,7 +46,7 @@ const (
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
func addWebService(c *restful.Container, devopsClient devops.Interface,
func AddToContainer(c *restful.Container, devopsClient devops.Interface,
dbClient *mysql.Database, sonarClient sonarqube.SonarInterface, ksClient versioned.Interface,
ksInformer externalversions.SharedInformerFactory, s3Client s3.Interface) error {

View File

@@ -17,11 +17,18 @@ import (
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
apierr "kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap"
"kubesphere.io/kubesphere/pkg/utils/iputil"
"kubesphere.io/kubesphere/pkg/utils/jwtutil"
"net/http"
iamapi "kubesphere.io/kubesphere/pkg/api/iam"
)
const (
kindTokenReview = "TokenReview"
)
type iamHandler struct {
@@ -29,11 +36,10 @@ type iamHandler struct {
imOperator iam.IdentityManagementInterface
}
func newIAMHandler(k8sClient k8s.Client, ldapClient ldappool.Client, options iam.Config) *iamHandler {
factory := informers.NewInformerFactories(k8sClient.Kubernetes(), k8sClient.KubeSphere(), k8sClient.S2i(), k8sClient.Application())
func newIAMHandler(k8sClient k8s.Client, factory informers.InformerFactory, ldapClient ldappool.Interface, cacheClient cache.Interface, options *iamapi.AuthenticationOptions) *iamHandler {
return &iamHandler{
amOperator: iam.NewAMOperator(factory.KubernetesSharedInformerFactory()),
imOperator: iam.NewIMOperator(ldapClient, options),
amOperator: iam.NewAMOperator(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory()),
imOperator: iam.NewIMOperator(ldapClient, cacheClient, options),
}
}
@@ -60,7 +66,7 @@ func (h *iamHandler) TokenReviewHandler(req *restful.Request, resp *restful.Resp
if err != nil {
failed := iamv1alpha2.TokenReview{APIVersion: tokenReview.APIVersion,
Kind: iam.KindTokenReview,
Kind: kindTokenReview,
Status: &iamv1alpha2.Status{
Authenticated: false,
},
@@ -92,7 +98,7 @@ func (h *iamHandler) TokenReviewHandler(req *restful.Request, resp *restful.Resp
}
success := iamv1alpha2.TokenReview{APIVersion: tokenReview.APIVersion,
Kind: iam.KindTokenReview,
Kind: kindTokenReview,
Status: &iamv1alpha2.Status{
Authenticated: true,
User: map[string]interface{}{"username": user.Username, "uid": user.Username, "groups": user.Groups},
@@ -378,7 +384,7 @@ func (h *iamHandler) ListRoleUsers(req *restful.Request, resp *restful.Response)
api.HandleInternalError(resp, err)
return
}
result := make([]*iam.User, 0)
result := make([]*iamapi.User, 0)
for _, roleBinding := range roleBindings {
for _, subject := range roleBinding.Subjects {
if subject.Kind == rbacv1.UserKind {
@@ -413,7 +419,7 @@ func (h *iamHandler) ListNamespaceUsers(req *restful.Request, resp *restful.Resp
return
}
result := make([]*iam.User, 0)
result := make([]*iamapi.User, 0)
for _, roleBinding := range roleBindings {
for _, subject := range roleBinding.Subjects {
if subject.Kind == rbacv1.UserKind {
@@ -445,7 +451,7 @@ func (h *iamHandler) ListClusterRoleUsers(req *restful.Request, resp *restful.Re
return
}
result := make([]*iam.User, 0)
result := make([]*iamapi.User, 0)
for _, roleBinding := range clusterRoleBindings {
for _, subject := range roleBinding.Subjects {
if subject.Kind == rbacv1.UserKind {

View File

@@ -23,26 +23,28 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/api/iam"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/api/iam/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
"kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap"
"net/http"
)
const GroupName = "iam.kubesphere.io"
const groupName = "iam.kubesphere.io"
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
var GroupVersion = schema.GroupVersion{Group: groupName, Version: "v1alpha2"}
func AddToContainer(c *restful.Container, k8sClient k8s.Client, ldapClient ldappool.Client, options iam.Config) error {
func AddToContainer(c *restful.Container, k8sClient k8s.Client, factory informers.InformerFactory, ldapClient ldappool.Interface, cacheClient cache.Interface, options *iam.AuthenticationOptions) error {
ws := runtime.NewWebService(GroupVersion)
handler := newIAMHandler(k8sClient, ldapClient, options)
handler := newIAMHandler(k8sClient, factory, ldapClient, cacheClient, options)
ws.Route(ws.POST("/authenticate").
To(handler.TokenReviewHandler).

View File

@@ -1,39 +0,0 @@
package kapis
import (
"github.com/emicklei/go-restful"
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
devopsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/devops/v1alpha2"
iamv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/iam/v1alpha2"
loggingv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/logging/v1alpha2"
monitoringv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha2"
openpitrixv1 "kubesphere.io/kubesphere/pkg/kapis/openpitrix/v1"
operationsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/operations/v1alpha2"
resourcesv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha2"
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/servicemesh/metrics/v1alpha2"
tenantv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha2"
terminalv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/terminal/v1alpha2"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap"
"kubesphere.io/kubesphere/pkg/simple/client/logging"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
op "kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
)
func InstallAPIs(container *restful.Container, client k8s.Client, op op.Client, db *mysql.Database, logging logging.Interface, monitoring monitoring.Interface) {
urlruntime.Must(servicemeshv1alpha2.AddToContainer(container))
urlruntime.Must(devopsv1alpha2.AddToContainer(container))
urlruntime.Must(loggingv1alpha2.AddToContainer(container, client, logging))
urlruntime.Must(monitoringv1alpha2.AddToContainer(container, client, monitoring))
urlruntime.Must(openpitrixv1.AddToContainer(container, client, op))
urlruntime.Must(operationsv1alpha2.AddToContainer(container, client))
urlruntime.Must(resourcesv1alpha2.AddToContainer(container, client))
urlruntime.Must(tenantv1alpha2.AddToContainer(container, client, db))
urlruntime.Must(terminalv1alpha2.AddToContainer(container, client))
}
func InstallAuthorizationAPIs(container *restful.Container, k8sClient k8s.Client, ldapClient ldappool.Client, imOptions iam.Config) {
urlruntime.Must(iamv1alpha2.AddToContainer(container, k8sClient, ldapClient, imOptions))
}

View File

@@ -14,7 +14,6 @@ import (
"kubesphere.io/kubesphere/pkg/models/openpitrix"
"kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
op "kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"strconv"
"strings"
@@ -25,9 +24,7 @@ type openpitrixHandler struct {
informers k8sinformers.SharedInformerFactory
}
func newOpenpitrixHandler(k8sClient k8s.Client, opClient op.Client) *openpitrixHandler {
factory := informers.NewInformerFactories(k8sClient.Kubernetes(), k8sClient.KubeSphere(), k8sClient.S2i(), k8sClient.Application())
func newOpenpitrixHandler(factory informers.InformerFactory, opClient op.Client) *openpitrixHandler {
return &openpitrixHandler{
openpitrix: openpitrix.NewOpenpitrixOperator(factory.KubernetesSharedInformerFactory(), opClient),

View File

@@ -24,11 +24,11 @@ import (
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models"
openpitrix2 "kubesphere.io/kubesphere/pkg/models/openpitrix"
"kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
op "kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"net/http"
)
@@ -39,11 +39,11 @@ const (
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
func AddToContainer(c *restful.Container, k8s k8s.Client, op op.Client) error {
func AddToContainer(c *restful.Container, factory informers.InformerFactory, op op.Client) error {
mimePatch := []string{restful.MIME_JSON, runtime.MimeMergePatchJson, runtime.MimeJsonPatchJson}
webservice := runtime.NewWebService(GroupVersion)
handler := newOpenpitrixHandler(k8s, op)
handler := newOpenpitrixHandler(factory, op)
webservice.Route(webservice.GET("/applications").
To(handler.ListApplications).

View File

@@ -4,9 +4,9 @@ import (
"fmt"
"github.com/emicklei/go-restful"
k8serr "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/models/workloads"
"kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"net/http"
)
@@ -14,9 +14,9 @@ type operationHandler struct {
jobRunner workloads.JobRunner
}
func newOperationHandler(client k8s.Client) *operationHandler {
func newOperationHandler(client kubernetes.Interface) *operationHandler {
return &operationHandler{
jobRunner: workloads.NewJobRunner(client.Kubernetes()),
jobRunner: workloads.NewJobRunner(client),
}
}

View File

@@ -20,10 +20,10 @@ package v1alpha2
import (
"github.com/emicklei/go-restful"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"net/http"
)
@@ -33,7 +33,7 @@ const (
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
func AddToContainer(c *restful.Container, client k8s.Client) error {
func AddToContainer(c *restful.Container, client kubernetes.Interface) error {
webservice := runtime.NewWebService(GroupVersion)

View File

@@ -5,6 +5,7 @@ import (
"github.com/emicklei/go-restful"
v1 "k8s.io/api/core/v1"
k8serr "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/kubernetes"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/informers"
@@ -20,7 +21,6 @@ import (
"kubesphere.io/kubesphere/pkg/models/routers"
"kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"net/http"
"strconv"
"strings"
@@ -38,20 +38,18 @@ type resourceHandler struct {
kubectlOperator kubectl.Interface
}
func newResourceHandler(client k8s.Client) *resourceHandler {
factory := informers.NewInformerFactories(client.Kubernetes(), client.KubeSphere(), client.S2i(), client.Application())
func newResourceHandler(client kubernetes.Interface, factory informers.InformerFactory) *resourceHandler {
return &resourceHandler{
resourcesGetter: resource.NewResourceGetter(factory),
componentsGetter: components.NewComponentsGetter(factory.KubernetesSharedInformerFactory()),
resourceQuotaGetter: quotas.NewResourceQuotaGetter(factory.KubernetesSharedInformerFactory()),
revisionGetter: revisions.NewRevisionGetter(factory.KubernetesSharedInformerFactory()),
routerOperator: routers.NewRouterOperator(client.Kubernetes(), factory.KubernetesSharedInformerFactory()),
routerOperator: routers.NewRouterOperator(client, factory.KubernetesSharedInformerFactory()),
gitVerifier: git.NewGitVerifier(factory.KubernetesSharedInformerFactory()),
registryGetter: registries.NewRegistryGetter(factory.KubernetesSharedInformerFactory()),
kubeconfigOperator: kubeconfig.NewKubeconfigOperator(),
kubectlOperator: kubectl.NewKubectlOperator(client.Kubernetes(), factory.KubernetesSharedInformerFactory()),
kubectlOperator: kubectl.NewKubectlOperator(client, factory.KubernetesSharedInformerFactory()),
}
}

View File

@@ -23,16 +23,17 @@ import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/api/resource/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models"
gitmodel "kubesphere.io/kubesphere/pkg/models/git"
registriesmodel "kubesphere.io/kubesphere/pkg/models/registries"
"kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"net/http"
)
@@ -42,9 +43,9 @@ const (
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
func AddToContainer(c *restful.Container, client k8s.Client) error {
func AddToContainer(c *restful.Container, client kubernetes.Interface, factory informers.InformerFactory) error {
webservice := runtime.NewWebService(GroupVersion)
handler := newResourceHandler(client)
handler := newResourceHandler(client, factory)
webservice.Route(webservice.GET("/namespaces/{namespace}/{resources}").
To(handler.handleListNamespaceResources).

View File

@@ -7,7 +7,6 @@ import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/components"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"net/http"
)
@@ -16,9 +15,7 @@ type Handler struct {
componentsGetter components.ComponentsGetter
}
func New(client k8s.Client) *Handler {
factory := informers.NewInformerFactories(client.Kubernetes(), client.KubeSphere(), client.S2i(), client.Application())
func New(factory informers.InformerFactory) *Handler {
return &Handler{
namespacedResourceGetter: resource.New(factory),
componentsGetter: components.NewComponentsGetter(factory.KubernetesSharedInformerFactory()),

View File

@@ -25,7 +25,7 @@ import (
"kubesphere.io/kubesphere/pkg/api/resource/v1alpha2"
"kubesphere.io/kubesphere/pkg/apiserver/query"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/informers"
"net/http"
)
@@ -40,10 +40,10 @@ const (
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
func AddWebService(c *restful.Container, client k8s.Client) error {
func AddToContainer(c *restful.Container, informerFactory informers.InformerFactory) error {
webservice := runtime.NewWebService(GroupVersion)
handler := New(client)
handler := New(informerFactory)
webservice.Route(webservice.GET("/namespaces/{namespace}/{resources}").
To(handler.handleGetNamespacedResource).

View File

@@ -28,12 +28,11 @@ type tenantHandler struct {
am iam.AccessManagementInterface
}
func newTenantHandler(k8sClient k8s.Client, db *mysql.Database) *tenantHandler {
factory := informers.NewInformerFactories(k8sClient.Kubernetes(), k8sClient.KubeSphere(), k8sClient.S2i(), k8sClient.Application())
func newTenantHandler(k8sClient k8s.Client, factory informers.InformerFactory, db *mysql.Database) *tenantHandler {
return &tenantHandler{
tenant: tenant.New(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory(), factory.KubeSphereSharedInformerFactory(), db),
am: iam.NewAMOperator(factory.KubernetesSharedInformerFactory()),
am: iam.NewAMOperator(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory()),
}
}

View File

@@ -27,6 +27,7 @@ import (
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
"kubesphere.io/kubesphere/pkg/server/errors"
@@ -43,9 +44,9 @@ const (
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
func AddToContainer(c *restful.Container, k8sClient k8s.Client, db *mysql.Database) error {
func AddToContainer(c *restful.Container, k8sClient k8s.Client, factory informers.InformerFactory, db *mysql.Database) error {
ws := runtime.NewWebService(GroupVersion)
handler := newTenantHandler(k8sClient, db)
handler := newTenantHandler(k8sClient, factory, db)
ws.Route(ws.GET("/workspaces").
To(handler.ListWorkspaces).

View File

@@ -21,10 +21,11 @@ import (
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful-openapi"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
)
const (
@@ -33,11 +34,11 @@ const (
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
func AddToContainer(c *restful.Container, k8sClient k8s.Client) error {
func AddToContainer(c *restful.Container, client kubernetes.Interface, config *rest.Config) error {
webservice := runtime.NewWebService(GroupVersion)
handler := newTerminalHandler(k8sClient.Kubernetes(), k8sClient.Config())
handler := newTerminalHandler(client, config)
webservice.Route(webservice.GET("/namespaces/{namespace}/pods/{pod}").
To(handler.handleTerminalSession).

View File

@@ -24,6 +24,7 @@ import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
@@ -33,7 +34,6 @@ import (
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/resource"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/role"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client"
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
)
@@ -62,8 +62,9 @@ type AccessManagementInterface interface {
}
type amOperator struct {
informers informers.SharedInformerFactory
resources resource.ResourceGetter
informers informers.SharedInformerFactory
resources resource.ResourceGetter
kubeClient kubernetes.Interface
}
func (am *amOperator) ListClusterRoleBindings(clusterRole string) ([]*rbacv1.ClusterRoleBinding, error) {
@@ -90,11 +91,15 @@ func (am *amOperator) UnBindAllRoles(username string) error {
panic("implement me")
}
func NewAMOperator(informers informers.SharedInformerFactory) *amOperator {
func NewAMOperator(kubeClient kubernetes.Interface, informers informers.SharedInformerFactory) *amOperator {
resourceGetter := resource.ResourceGetter{}
resourceGetter.Add(v1alpha2.Role, role.NewRoleSearcher(informers))
resourceGetter.Add(v1alpha2.ClusterRoles, clusterrole.NewClusterRoleSearcher(informers))
return &amOperator{informers: informers, resources: resourceGetter}
return &amOperator{
informers: informers,
resources: resourceGetter,
kubeClient: kubeClient,
}
}
func (am *amOperator) GetDevopsRoleSimpleRules(role string) []policy.SimpleRule {
@@ -560,7 +565,7 @@ func (am *amOperator) CreateClusterRoleBinding(username string, clusterRoleName
found, err := clusterRoleBindingLister.Get(username)
if apierrors.IsNotFound(err) {
_, err = client.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
_, err = am.kubeClient.RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
if err != nil {
klog.Errorln("create cluster role binding", err)
return err
@@ -575,12 +580,12 @@ func (am *amOperator) CreateClusterRoleBinding(username string, clusterRoleName
deletePolicy := metav1.DeletePropagationBackground
gracePeriodSeconds := int64(0)
deleteOption := &metav1.DeleteOptions{PropagationPolicy: &deletePolicy, GracePeriodSeconds: &gracePeriodSeconds}
err = client.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Delete(found.Name, deleteOption)
err = am.kubeClient.RbacV1().ClusterRoleBindings().Delete(found.Name, deleteOption)
if err != nil {
klog.Errorln(err)
return err
}
_, err = client.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
_, err = am.kubeClient.RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
if err != nil {
klog.Errorln(err)
return err
@@ -590,7 +595,7 @@ func (am *amOperator) CreateClusterRoleBinding(username string, clusterRoleName
if !ContainsUser(found.Subjects, username) {
found.Subjects = clusterRoleBinding.Subjects
_, err = client.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Update(found)
_, err = am.kubeClient.RbacV1().ClusterRoleBindings().Update(found)
if err != nil {
klog.Errorln("update cluster role binding", err)
return err

View File

@@ -20,216 +20,96 @@ package iam
import (
"fmt"
"github.com/dgrijalva/jwt-go"
"github.com/go-ldap/ldap"
"github.com/go-redis/redis"
"github.com/pkg/errors"
"golang.org/x/oauth2"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api/iam"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/server/params"
ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
"kubesphere.io/kubesphere/pkg/utils/jwtutil"
"strconv"
"strings"
"time"
)
type IdentityManagementInterface interface {
CreateUser(user *User) (*User, error)
CreateUser(user *iam.User) (*iam.User, error)
DeleteUser(username string) error
DescribeUser(username string) (*User, error)
DescribeUser(username string) (*iam.User, error)
Login(username, password, ip string) (*oauth2.Token, error)
ModifyUser(user *User) (*User, error)
ModifyUser(user *iam.User) (*iam.User, error)
ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
GetUserRoles(username string) ([]*rbacv1.Role, error)
GetUserRole(namespace string, username string) (*rbacv1.Role, error)
}
type Config struct {
authRateLimit string
maxAuthFailed int
authTimeInterval time.Duration
tokenIdleTimeout time.Duration
enableMultiLogin bool
}
type imOperator struct {
config Config
ldap ldappool.Client
redis redis.Client
authenticateOptions *iam.AuthenticationOptions
ldapClient ldap.Interface
cacheClient cache.Interface
}
const (
authRateLimitRegex = `(\d+)/(\d+[s|m|h])`
defaultMaxAuthFailed = 5
defaultAuthTimeInterval = 30 * time.Minute
mailAttribute = "mail"
uidAttribute = "uid"
descriptionAttribute = "description"
preferredLanguageAttribute = "preferredLanguage"
createTimestampAttribute = "createTimestampAttribute"
dateTimeLayout = "20060102150405Z"
)
var (
AuthRateLimitExceeded = errors.New("user auth rate limit exceeded")
UserAlreadyExists = errors.New("user already exists")
UserNotExists = errors.New("user not exists")
)
func NewIMOperator(ldap ldappool.Client, config Config) *imOperator {
imOperator := &imOperator{ldap: ldap, config: config}
return imOperator
func NewIMOperator(ldapClient ldap.Interface, cacheClient cache.Interface, options *iam.AuthenticationOptions) *imOperator {
return &imOperator{ldapClient: ldapClient, cacheClient: cacheClient, authenticateOptions: options}
}
// TODO init in controller
func (im *imOperator) Init() error {
userSearchBase := &ldap.AddRequest{
DN: im.ldap.UserSearchBase(),
Attributes: []ldap.Attribute{{
Type: "objectClass",
Vals: []string{"organizationalUnit", "top"},
}, {
Type: "ou",
Vals: []string{"Users"},
}},
Controls: nil,
}
err := im.createIfNotExists(userSearchBase)
func (im *imOperator) ModifyUser(user *iam.User) (*iam.User, error) {
err := im.ldapClient.Update(user)
if err != nil {
return err
}
groupSearchBase := &ldap.AddRequest{
DN: im.ldap.GroupSearchBase(),
Attributes: []ldap.Attribute{{
Type: "objectClass",
Vals: []string{"organizationalUnit", "top"},
}, {
Type: "ou",
Vals: []string{"Groups"},
}},
Controls: nil,
}
err = im.createIfNotExists(groupSearchBase)
if err != nil {
return err
}
return nil
}
func (im *imOperator) createIfNotExists(createRequest *ldap.AddRequest) error {
conn, err := im.ldap.NewConn()
if err != nil {
return err
}
defer conn.Close()
searchRequest := ldap.NewSearchRequest(
createRequest.DN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
"(objectClass=*)",
nil,
nil,
)
_, err = conn.Search(searchRequest)
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
err = conn.Add(createRequest)
}
if err != nil {
klog.Errorln(err)
return err
}
return nil
}
func (im *imOperator) ModifyUser(user *User) (*User, error) {
conn, err := im.ldap.NewConn()
if err != nil {
klog.Errorln(err)
return nil, err
}
defer conn.Close()
dn := fmt.Sprintf("uid=%s,%s", user.Username, im.ldap.UserSearchBase())
userModifyRequest := ldap.NewModifyRequest(dn, nil)
if user.Description != "" {
userModifyRequest.Replace("description", []string{user.Description})
}
if user.Lang != "" {
userModifyRequest.Replace("preferredLanguage", []string{user.Lang})
}
if user.Password != "" {
userModifyRequest.Replace("userPassword", []string{user.Password})
}
err = conn.Modify(userModifyRequest)
if err != nil {
klog.Error(err)
return nil, err
}
// clear auth failed record
if user.Password != "" {
records, err := im.redis.Keys(fmt.Sprintf("kubesphere:authfailed:%s:*", user.Username)).Result()
records, err := im.cacheClient.Keys(authenticationFailedKeyForUsername(user.Username, "*"))
if err == nil {
im.redis.Del(records...)
im.cacheClient.Del(records...)
}
}
return im.DescribeUser(user.Username)
return im.ldapClient.Get(user.Username)
}
func authenticationFailedKeyForUsername(username, failedTimestamp string) string {
return fmt.Sprintf("kubesphere:authfailed:%s:%s", username, failedTimestamp)
}
func tokenKeyForUsername(username, token string) string {
return fmt.Sprintf("kubesphere:users:%s:token:%s", username, token)
}
func loginKeyForUsername(username, loginTimestamp, ip string) string {
return fmt.Sprintf("kubesphere:users:%s:login-log:%s:%s", username, loginTimestamp, ip)
}
func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error) {
records, err := im.redis.Keys(fmt.Sprintf("kubesphere:authfailed:%s:*", username)).Result()
records, err := im.cacheClient.Keys(authenticationFailedKeyForUsername(username, "*"))
if err != nil {
klog.Error(err)
return nil, err
}
if len(records) >= im.config.maxAuthFailed {
if len(records) >= im.authenticateOptions.MaxAuthenticateRetries {
return nil, AuthRateLimitExceeded
}
user, err := im.DescribeUser(username)
conn, err := im.ldap.NewConn()
user, err := im.ldapClient.Get(username)
if err != nil {
klog.Error(err)
return nil, err
}
defer conn.Close()
dn := fmt.Sprintf("uid=%s,%s", user.Username, im.ldap.UserSearchBase())
// bind as the user to verify their password
err = conn.Bind(dn, password)
err = im.ldapClient.Verify(user.Username, password)
if err != nil {
if ldap.IsErrorWithCode(err, ldap.LDAPResultInvalidCredentials) {
cacheKey := fmt.Sprintf("kubesphere:authfailed:%s:%d", user.Username, time.Now().UnixNano())
im.redis.Set(cacheKey, "", im.config.authTimeInterval)
if err == ldap.ErrInvalidCredentials {
im.cacheClient.Set(authenticationFailedKeyForUsername(username, fmt.Sprintf("%d", time.Now().UnixNano())), "", 30*time.Minute)
}
return nil, err
}
@@ -243,30 +123,25 @@ func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error
}
token := jwtutil.MustSigned(claims)
if !im.config.enableMultiLogin {
tokenKey := tokenKeyForUsername(user.Username, "*")
if !im.authenticateOptions.MultipleLogin {
// multi login not allowed, remove the previous token
cacheKey := fmt.Sprintf("kubesphere:users:%s:token:*", user.Username)
sessions, err := im.redis.Keys(cacheKey).Result()
sessions, err := im.cacheClient.Keys(tokenKey)
if err != nil {
klog.Errorln(err)
return nil, err
}
if len(sessions) > 0 {
klog.V(4).Infoln("revoke token", sessions)
err = im.redis.Del(sessions...).Err()
err = im.cacheClient.Del(sessions...)
if err != nil {
klog.Errorln(err)
return nil, err
}
}
}
// cache token with expiration time
cacheKey := fmt.Sprintf("kubesphere:users:%s:token:%s", user.Username, token)
if err = im.redis.Set(cacheKey, token, im.config.tokenIdleTimeout).Err(); err != nil {
klog.Errorln(err)
if err = im.cacheClient.Set(tokenKey, token, im.authenticateOptions.TokenExpiration); err != nil {
return nil, err
}
@@ -277,153 +152,39 @@ func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error
func (im *imOperator) loginRecord(username, ip string, loginTime time.Time) {
if ip != "" {
im.redis.RPush(fmt.Sprintf("kubesphere:users:%s:login-log", username), fmt.Sprintf("%s,%s", loginTime.UTC().Format("2006-01-02T15:04:05Z"), ip))
im.redis.LTrim(fmt.Sprintf("kubesphere:users:%s:login-log", username), -10, -1)
_ = im.cacheClient.Set(loginKeyForUsername(username, loginTime.UTC().Format("2006-01-02T15:04:05Z"), ip), "", 30*24*time.Hour)
}
}
func (im *imOperator) LoginHistory(username string) ([]string, error) {
data, err := im.redis.LRange(fmt.Sprintf("kubesphere:users:%s:login-log", username), -10, -1).Result()
keys, err := im.cacheClient.Keys(loginKeyForUsername(username, "*", "*"))
if err != nil {
return nil, err
}
return data, nil
return keys, nil
}
func (im *imOperator) ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
panic("implement me")
}
func (im *imOperator) DescribeUser(username string) (*User, error) {
conn, err := im.ldap.NewConn()
if err != nil {
klog.Errorln(err)
return nil, err
}
defer conn.Close()
filter := fmt.Sprintf("(&(objectClass=inetOrgPerson)(|(uid=%s)(mail=%s)))", username, username)
searchRequest := ldap.NewSearchRequest(
im.ldap.UserSearchBase(),
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
filter,
[]string{mailAttribute, descriptionAttribute, preferredLanguageAttribute, createTimestampAttribute},
nil,
)
result, err := conn.Search(searchRequest)
if err != nil {
klog.Errorln(err)
return nil, err
}
if len(result.Entries) != 1 {
return nil, UserNotExists
}
entry := result.Entries[0]
return convertLdapEntryToUser(entry), nil
}
func convertLdapEntryToUser(entry *ldap.Entry) *User {
username := entry.GetAttributeValue(uidAttribute)
email := entry.GetAttributeValue(mailAttribute)
description := entry.GetAttributeValue(descriptionAttribute)
lang := entry.GetAttributeValue(preferredLanguageAttribute)
createTimestamp, err := time.Parse(dateTimeLayout, entry.GetAttributeValue(createTimestampAttribute))
if err != nil {
klog.Errorln(err)
}
return &User{Username: username, Email: email, Description: description, Lang: lang, CreateTime: createTimestamp}
func (im *imOperator) DescribeUser(username string) (*iam.User, error) {
return im.ldapClient.Get(username)
}
func (im *imOperator) getLastLoginTime(username string) string {
cacheKey := fmt.Sprintf("kubesphere:users:%s:login-log", username)
lastLogin, err := im.redis.LRange(cacheKey, -1, -1).Result()
if err != nil {
return ""
}
if len(lastLogin) > 0 {
return strings.Split(lastLogin[0], ",")[0]
}
return ""
}
func (im *imOperator) DeleteUser(username string) error {
conn, err := im.ldap.NewConn()
if err != nil {
klog.Errorln(err)
return err
}
defer conn.Close()
deleteRequest := ldap.NewDelRequest(fmt.Sprintf("uid=%s,%s", username, im.ldap.UserSearchBase()), nil)
if err = conn.Del(deleteRequest); err != nil {
klog.Errorln(err)
return err
}
return nil
return im.ldapClient.Delete(username)
}
func (im *imOperator) CreateUser(user *User) (*User, error) {
user.Username = strings.TrimSpace(user.Username)
user.Email = strings.TrimSpace(user.Email)
user.Password = strings.TrimSpace(user.Password)
user.Description = strings.TrimSpace(user.Description)
existed, err := im.DescribeUser(user.Username)
func (im *imOperator) CreateUser(user *iam.User) (*iam.User, error) {
err := im.ldapClient.Create(user)
if err != nil {
klog.Errorln(err)
return nil, err
}
if existed != nil {
return nil, UserAlreadyExists
}
uidNumber := im.uidNumberNext()
createRequest := ldap.NewAddRequest(fmt.Sprintf("uid=%s,%s", user.Username, im.ldap.UserSearchBase()), nil)
createRequest.Attribute("objectClass", []string{"inetOrgPerson", "posixAccount", "top"})
createRequest.Attribute("cn", []string{user.Username}) // RFC4519: common name(s) for which the entity is known by
createRequest.Attribute("sn", []string{" "}) // RFC2256: last (family) name(s) for which the entity is known by
createRequest.Attribute("gidNumber", []string{"500"}) // RFC2307: An integer uniquely identifying a group in an administrative domain
createRequest.Attribute("homeDirectory", []string{"/home/" + user.Username}) // The absolute path to the home directory
createRequest.Attribute("uid", []string{user.Username}) // RFC4519: user identifier
createRequest.Attribute("uidNumber", []string{strconv.Itoa(uidNumber)}) // RFC2307: An integer uniquely identifying a user in an administrative domain
createRequest.Attribute("mail", []string{user.Email}) // RFC1274: RFC822 Mailbox
createRequest.Attribute("userPassword", []string{user.Password}) // RFC4519/2307: password of user
if user.Lang != "" {
createRequest.Attribute("preferredLanguage", []string{user.Lang})
}
if user.Description != "" {
createRequest.Attribute("description", []string{user.Description}) // RFC4519: descriptive information
}
conn, err := im.ldap.NewConn()
if err != nil {
klog.Errorln(err)
return nil, err
}
err = conn.Add(createRequest)
if err != nil {
klog.Errorln(err)
return nil, err
}

View File

@@ -17,39 +17,3 @@
*/
package iam
import (
"github.com/golang/mock/gomock"
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
"testing"
)
func TestIMOperator(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ldappool, err := ldap.NewMockClient(&ldap.Options{
Host: "192.168.0.7:30389",
ManagerDN: "cn=admin,dc=kubesphere,dc=io",
ManagerPassword: "admin",
UserSearchBase: "ou=Users,dc=kubesphere,dc=io",
GroupSearchBase: "ou=Groups,dc=kubesphere,dc=io",
InitialCap: 8,
MaxCap: 64,
}, ctrl, func(client *ldap.MockClient) {
client.EXPECT().Search(gomock.Any()).AnyTimes()
})
if err != nil {
t.Fatal(err)
}
defer ldappool.Close()
im := NewIMOperator(ldappool, Config{})
err = im.Init()
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1,80 +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 iam
import (
"fmt"
"kubesphere.io/kubesphere/pkg/simple/client"
"regexp"
"strings"
)
func convertDNToPath(dn string) string {
paths := regexp.MustCompile("cn=[a-z0-9]([-a-z0-9]*[a-z0-9])?").FindAllString(dn, -1)
if len(paths) > 1 {
for i := 0; i < len(paths); i++ {
paths[i] = strings.Replace(paths[i], "cn=", "", 1)
}
for i, j := 0, len(paths)-1; i < j; i, j = i+1, j-1 {
paths[i], paths[j] = paths[j], paths[i]
}
return strings.Join(paths, ":")
} else if len(paths) == 1 {
return strings.Replace(paths[0], "cn=", "", -1)
} else {
return ""
}
}
func splitPath(path string) (searchBase string, cn string) {
ldapClient, err := client.ClientSets().Ldap()
if err != nil {
return "", ""
}
paths := strings.Split(path, ":")
length := len(paths)
if length > 2 {
cn = paths[length-1]
basePath := paths[:length-1]
for i := 0; i < len(basePath); i++ {
basePath[i] = fmt.Sprintf("cn=%s", basePath[i])
}
for i, j := 0, length-2; i < j; i, j = i+1, j-1 {
basePath[i], basePath[j] = basePath[j], basePath[i]
}
searchBase = fmt.Sprintf("%s,%s", strings.Join(basePath, ","), ldapClient.GroupSearchBase())
} else if length == 2 {
searchBase = fmt.Sprintf("cn=%s,%s", paths[0], ldapClient.GroupSearchBase())
cn = paths[1]
} else {
searchBase = ldapClient.GroupSearchBase()
if paths[0] == "" {
cn = "*"
} else {
cn = paths[0]
}
}
return
}

View File

@@ -1,37 +0,0 @@
/*
*
* Copyright 2020 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 iam
import (
"time"
)
const (
KindTokenReview = "TokenReview"
)
type User struct {
Username string `json:"username"`
Email string `json:"email"`
Lang string `json:"lang,omitempty"`
Description string `json:"description"`
CreateTime time.Time `json:"create_time"`
Groups []string `json:"groups,omitempty"`
Password string `json:"password,omitempty"`
}

View File

@@ -20,6 +20,7 @@ package iam
import (
rbacv1 "k8s.io/api/rbac/v1"
"kubesphere.io/kubesphere/pkg/api/iam"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
"strings"
)
@@ -194,15 +195,15 @@ func ContainsUser(subjects interface{}, username string) bool {
return true
}
}
case []User:
for _, u := range subjects.([]User) {
case []iam.User:
for _, u := range subjects.([]iam.User) {
if u.Username == username {
return true
}
}
case []*User:
for _, u := range subjects.([]*User) {
case []*iam.User:
for _, u := range subjects.([]*iam.User) {
if u.Username == username {
return true
}

View File

@@ -77,9 +77,9 @@ func NewResourceGetter(factory informers.InformerFactory) *ResourceGetter {
resourceGetters[v1alpha2.StorageClasses] = storageclass.NewStorageClassesSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.HorizontalPodAutoscalers] = hpa.NewHpaSearcher(factory.KubernetesSharedInformerFactory())
resourceGetters[v1alpha2.S2iBuilders] = s2ibuilder.NewS2iBuilderSearcher(factory.S2iSharedInformerFactory())
resourceGetters[v1alpha2.S2iRuns] = s2irun.NewS2iRunSearcher(factory.S2iSharedInformerFactory())
resourceGetters[v1alpha2.S2iBuilderTemplates] = s2buildertemplate.NewS2iBuidlerTemplateSearcher(factory.S2iSharedInformerFactory())
resourceGetters[v1alpha2.S2iBuilders] = s2ibuilder.NewS2iBuilderSearcher(factory.KubeSphereSharedInformerFactory())
resourceGetters[v1alpha2.S2iRuns] = s2irun.NewS2iRunSearcher(factory.KubeSphereSharedInformerFactory())
resourceGetters[v1alpha2.S2iBuilderTemplates] = s2buildertemplate.NewS2iBuidlerTemplateSearcher(factory.KubeSphereSharedInformerFactory())
resourceGetters[v1alpha2.Workspaces] = workspace.NewWorkspaceSearcher(factory.KubeSphereSharedInformerFactory())

View File

@@ -18,8 +18,8 @@
package s2buildertemplate
import (
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
"github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"

View File

@@ -19,9 +19,9 @@
package s2ibuilder
import (
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
"github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"

View File

@@ -19,19 +19,15 @@
package s2irun
import (
"github.com/kubesphere/s2ioperator/pkg/client/informers/externalversions"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1"
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"kubesphere.io/kubesphere/pkg/server/params"
"k8s.io/apimachinery/pkg/labels"
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
)
type s2iRunSearcher struct {

View File

@@ -108,7 +108,7 @@ func TestListDeployments(t *testing.T) {
},
api.ListResult{
Items: []interface{}{
v1.Deployment{
&v1.Deployment{
ObjectMeta: metaV1.ObjectMeta{
Name: "foo-2",
Namespace: "bar",
@@ -141,7 +141,7 @@ func TestListDeployments(t *testing.T) {
t.Fatal(err)
}
if diff := cmp.Diff(got, test.expected); diff != "" {
if diff := cmp.Diff(got.Items, test.expected.Items); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
}
})

View File

@@ -77,7 +77,7 @@ func (t *tenantOperator) DeleteNamespace(workspace, namespace string) error {
}
func New(client kubernetes.Interface, informers k8sinformers.SharedInformerFactory, ksinformers ksinformers.SharedInformerFactory, db *mysql.Database) Interface {
amOperator := iam.NewAMOperator(informers)
amOperator := iam.NewAMOperator(client, informers)
return &tenantOperator{
workspaces: newWorkspaceOperator(client, informers, ksinformers, amOperator, db),
namespaces: newNamespaceOperator(client, informers, amOperator),

View File

@@ -33,7 +33,6 @@ import (
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
clientset "kubesphere.io/kubesphere/pkg/simple/client"
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
@@ -43,10 +42,12 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
iamapi "kubesphere.io/kubesphere/pkg/api/iam"
)
type InWorkspaceUser struct {
*iam.User
*iamapi.User
WorkspaceRole string `json:"workspaceRole"`
}
@@ -203,10 +204,6 @@ func (w *workspaceOperator) deleteWorkspaceRoleBinding(workspace, username strin
}
func (w *workspaceOperator) CountDevopsProjectsInWorkspace(workspaceName string) (int, error) {
if w.db == nil {
return 0, clientset.ErrClientSetNotEnabled
}
query := w.db.Select(devops.DevOpsProjectIdColumn).
From(devops.DevOpsProjectTableName).
Where(db.And(db.Eq(devops.DevOpsProjectWorkSpaceColumn, workspaceName),

View File

@@ -21,6 +21,7 @@ import (
"fmt"
"github.com/spf13/pflag"
"kubesphere.io/kubesphere/pkg/utils/net"
"os"
)
type ServerRunOptions struct {
@@ -63,10 +64,18 @@ func (s *ServerRunOptions) Validate() []error {
if net.IsValidPort(s.SecurePort) {
if s.TlsCertFile == "" {
errs = append(errs, fmt.Errorf("tls cert file is empty while secure serving"))
} else {
if _, err := os.Stat(s.TlsCertFile); err != nil {
errs = append(errs, err)
}
}
if s.TlsPrivateKey == "" {
errs = append(errs, fmt.Errorf("tls private key file is empty while secure serving"))
} else {
if _, err := os.Stat(s.TlsPrivateKey); err != nil {
errs = append(errs, err)
}
}
}

View File

@@ -13,10 +13,10 @@ type Interface interface {
Set(key string, value string, duration time.Duration) error
// Del deletes the given key, no error returned if the key doesn't exists
Del(key string) error
Del(keys ...string) error
// Exists checks the existence of a give key
Exists(key string) (bool, error)
Exists(keys ...string) (bool, error)
// Expires updates object's expiration time, return err if key doesn't exist
Expire(key string, duration time.Duration) error

View File

@@ -63,25 +63,30 @@ func NewRedisClient(option *Options, stopCh <-chan struct{}) (Interface, error)
}
func (r *Client) Get(key string) (string, error) {
return "", nil
return r.client.Get(key).Result()
}
func (r *Client) Keys(pattern string) ([]string, error) {
panic("implement me")
return r.client.Keys(pattern).Result()
}
func (r *Client) Set(key string, value string, duration time.Duration) error {
panic("implement me")
return r.client.Set(key, value, duration).Err()
}
func (r *Client) Del(key string) error {
panic("implement me")
func (r *Client) Del(keys ...string) error {
return r.client.Del(keys...).Err()
}
func (r *Client) Exists(key string) (bool, error) {
panic("implement me")
func (r *Client) Exists(keys ...string) (bool, error) {
existedKeys, err := r.client.Exists(keys...).Result()
if err != nil {
return false, err
}
return len(keys) == int(existedKeys), nil
}
func (r *Client) Expire(key string, duration time.Duration) error {
panic("implement me")
return r.client.Expire(key, duration).Err()
}

View File

@@ -23,7 +23,7 @@ func (s *SimpleCache) Set(key string, value string, duration time.Duration) erro
panic("implement me")
}
func (s *SimpleCache) Del(key string) error {
func (s *SimpleCache) Del(keys ...string) error {
panic("implement me")
}
@@ -31,7 +31,7 @@ func (s *SimpleCache) Get(key string) (string, error) {
return "", nil
}
func (s *SimpleCache) Exists(key string) (bool, error) {
func (s *SimpleCache) Exists(keys ...string) (bool, error) {
panic("implement me")
}

View File

@@ -14,21 +14,11 @@ limitations under the License.
package jenkins
import (
"fmt"
"k8s.io/klog"
"sync"
"kubesphere.io/kubesphere/pkg/simple/client/devops"
)
const (
jenkinsAllUserRoleName = "kubesphere-user"
)
type Client struct {
jenkinsClient *Jenkins
}
func NewDevopsClient(options *Options) (*Client, error) {
var d Client
func NewDevopsClient(options *Options) (devops.Interface, error) {
jenkins := CreateJenkins(nil, options.Host, options.MaxConnections, options.Username, options.Password)
jenkins, err := jenkins.Init()
@@ -37,51 +27,5 @@ func NewDevopsClient(options *Options) (*Client, error) {
return nil, err
}
d.jenkinsClient = jenkins
err = d.initializeJenkins()
if err != nil {
klog.Error(err)
return nil, err
}
return &d, nil
}
func (c *Client) Jenkins() *Jenkins {
return c.jenkinsClient
}
var mutex = sync.Mutex{}
func (c *Client) initializeJenkins() error {
mutex.Lock()
defer mutex.Unlock()
if c.jenkinsClient == nil {
return fmt.Errorf("jenkins intialization failed")
}
globalRole, err := c.jenkinsClient.GetGlobalRole(jenkinsAllUserRoleName)
if err != nil {
klog.Error(err)
return err
}
// Jenkins uninitialized, create global role
if globalRole == nil {
_, err := c.jenkinsClient.AddGlobalRole(jenkinsAllUserRoleName, GlobalPermissionIds{GlobalRead: true}, true)
if err != nil {
klog.Error(err)
return err
}
}
_, err = c.jenkinsClient.AddProjectRole(jenkinsAllUserRoleName, "\\n\\s*\\r", ProjectPermissionIds{SCMTag: true}, true)
if err != nil {
klog.Error(err)
return err
}
return nil
return jenkins, nil
}

View File

@@ -1,368 +0,0 @@
package client
import (
"errors"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
"kubesphere.io/kubesphere/pkg/simple/client/devops"
"kubesphere.io/kubesphere/pkg/simple/client/devops/jenkins"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
"kubesphere.io/kubesphere/pkg/simple/client/logging/elasticsearch"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring/prometheus"
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"kubesphere.io/kubesphere/pkg/simple/client/s3"
"kubesphere.io/kubesphere/pkg/simple/client/sonarqube"
"sync"
)
var ErrClientSetNotEnabled = errors.New("client set not enabled")
type ClientSetOptions struct {
mySQLOptions *mysql.Options
redisOptions *cache.Options
kubernetesOptions *k8s.KubernetesOptions
devopsOptions *jenkins.Options
sonarqubeOptions *sonarqube.Options
ldapOptions *ldap.Options
s3Options *s3.Options
openPitrixOptions *openpitrix.Options
prometheusOptions *prometheus.Options
kubesphereOptions *kubesphere.Options
elasticsearhOptions *elasticsearch.Options
}
func NewClientSetOptions() *ClientSetOptions {
return &ClientSetOptions{
mySQLOptions: mysql.NewMySQLOptions(),
redisOptions: cache.NewRedisOptions(),
kubernetesOptions: k8s.NewKubernetesOptions(),
ldapOptions: ldap.NewOptions(),
devopsOptions: jenkins.NewDevopsOptions(),
sonarqubeOptions: sonarqube.NewSonarQubeOptions(),
s3Options: s3.NewS3Options(),
openPitrixOptions: openpitrix.NewOptions(),
prometheusOptions: prometheus.NewPrometheusOptions(),
kubesphereOptions: kubesphere.NewKubeSphereOptions(),
elasticsearhOptions: elasticsearch.NewElasticSearchOptions(),
}
}
func (c *ClientSetOptions) SetMySQLOptions(options *mysql.Options) *ClientSetOptions {
c.mySQLOptions = options
return c
}
func (c *ClientSetOptions) SetRedisOptions(options *cache.Options) *ClientSetOptions {
c.redisOptions = options
return c
}
func (c *ClientSetOptions) SetKubernetesOptions(options *k8s.KubernetesOptions) *ClientSetOptions {
c.kubernetesOptions = options
return c
}
func (c *ClientSetOptions) SetDevopsOptions(options *jenkins.Options) *ClientSetOptions {
c.devopsOptions = options
return c
}
func (c *ClientSetOptions) SetLdapOptions(options *ldap.Options) *ClientSetOptions {
c.ldapOptions = options
return c
}
func (c *ClientSetOptions) SetS3Options(options *s3.Options) *ClientSetOptions {
c.s3Options = options
return c
}
func (c *ClientSetOptions) SetOpenPitrixOptions(options *openpitrix.Options) *ClientSetOptions {
c.openPitrixOptions = options
return c
}
func (c *ClientSetOptions) SetPrometheusOptions(options *prometheus.Options) *ClientSetOptions {
c.prometheusOptions = options
return c
}
func (c *ClientSetOptions) SetSonarQubeOptions(options *sonarqube.Options) *ClientSetOptions {
c.sonarqubeOptions = options
return c
}
func (c *ClientSetOptions) SetKubeSphereOptions(options *kubesphere.Options) *ClientSetOptions {
c.kubesphereOptions = options
return c
}
func (c *ClientSetOptions) SetElasticSearchOptions(options *elasticsearch.Options) *ClientSetOptions {
c.elasticsearhOptions = options
return c
}
// ClientSet provide best of effort service to initialize clients,
// but there is no guarantee to return a valid client instance,
// so do validity check before use
type ClientSet struct {
csoptions *ClientSetOptions
stopCh <-chan struct{}
mySQLClient *mysql.Client
k8sClient k8s.Client
ldapClient ldap.Client
devopsClient *jenkins.Client
sonarQubeClient *sonarqube.Client
redisClient cache.Interface
s3Client s3.Interface
prometheusClient monitoring.Interface
openpitrixClient openpitrix.Client
kubesphereClient *kubesphere.Client
elasticSearchClient *elasticsearch.Elasticsearch
}
var mutex sync.Mutex
// global clientsets instance
var sharedClientSet *ClientSet
func ClientSets() *ClientSet {
return sharedClientSet
}
func NewClientSetFactory(c *ClientSetOptions, stopCh <-chan struct{}) *ClientSet {
sharedClientSet = &ClientSet{csoptions: c, stopCh: stopCh}
if c.kubernetesOptions != nil {
sharedClientSet.k8sClient = k8s.NewKubernetesClientOrDie(c.kubernetesOptions)
}
if c.kubesphereOptions != nil {
sharedClientSet.kubesphereClient = kubesphere.NewKubeSphereClient(c.kubesphereOptions)
}
return sharedClientSet
}
// lazy creating
func (cs *ClientSet) MySQL() (*mysql.Database, error) {
var err error
if cs.csoptions.mySQLOptions == nil || cs.csoptions.mySQLOptions.Host == "" {
return nil, ErrClientSetNotEnabled
}
if cs.mySQLClient != nil {
return cs.mySQLClient.Database(), nil
} else {
mutex.Lock()
defer mutex.Unlock()
if cs.mySQLClient == nil {
cs.mySQLClient, err = mysql.NewMySQLClient(cs.csoptions.mySQLOptions, cs.stopCh)
if err != nil {
return nil, err
}
}
return cs.mySQLClient.Database(), nil
}
}
func (cs *ClientSet) Cache() (cache.Interface, error) {
var err error
if cs.csoptions.redisOptions == nil || cs.csoptions.redisOptions.RedisURL == "" {
return nil, ErrClientSetNotEnabled
}
if cs.redisClient != nil {
return cs.redisClient, nil
} else {
mutex.Lock()
defer mutex.Unlock()
if cs.redisClient == nil {
cs.redisClient, err = cache.NewRedisClient(cs.csoptions.redisOptions, cs.stopCh)
if err != nil {
return nil, err
}
}
return cs.redisClient, nil
}
}
func (cs *ClientSet) Devops() (devops.Interface, error) {
//var err error
//
//if cs.csoptions.devopsOptions == nil || cs.csoptions.devopsOptions.Host == "" {
// return nil, ErrClientSetNotEnabled
//}
//
//if cs.devopsClient != nil {
// return cs.devopsClient, nil
//} else {
// mutex.Lock()
// defer mutex.Unlock()
//
// if cs.devopsClient == nil {
// cs.devopsClient, err = jenkins.NewDevopsClient(cs.csoptions.devopsOptions)
// if err != nil {
// return nil, err
// }
// }
// return cs.devopsClient, nil
//}
return nil, nil
}
func (cs *ClientSet) SonarQube() (*sonarqube.Client, error) {
var err error
if cs.csoptions.sonarqubeOptions == nil || cs.csoptions.sonarqubeOptions.Host == "" {
return nil, ErrClientSetNotEnabled
}
if cs.sonarQubeClient != nil {
return cs.sonarQubeClient, nil
} else {
mutex.Lock()
defer mutex.Unlock()
if cs.sonarQubeClient == nil {
cs.sonarQubeClient, err = sonarqube.NewSonarQubeClient(cs.csoptions.sonarqubeOptions)
if err != nil {
return nil, err
}
}
return cs.sonarQubeClient, nil
}
}
func (cs *ClientSet) Ldap() (ldap.Client, error) {
var err error
if cs.csoptions.ldapOptions == nil || cs.csoptions.ldapOptions.Host == "" {
return nil, ErrClientSetNotEnabled
}
if cs.ldapClient != nil {
return cs.ldapClient, nil
} else {
mutex.Lock()
defer mutex.Unlock()
if cs.ldapClient == nil {
cs.ldapClient, err = ldap.NewClient(cs.csoptions.ldapOptions, cs.stopCh)
if err != nil {
return nil, err
}
}
return cs.ldapClient, nil
}
}
// since kubernetes client is required, we will
// create it on setup
func (cs *ClientSet) K8s() k8s.Client {
return cs.k8sClient
}
func (cs *ClientSet) S3() (s3.Interface, error) {
var err error
if cs.csoptions.s3Options == nil || cs.csoptions.s3Options.Endpoint == "" {
return nil, ErrClientSetNotEnabled
}
if cs.s3Client != nil {
return cs.s3Client, nil
} else {
mutex.Lock()
defer mutex.Unlock()
if cs.s3Client == nil {
cs.s3Client, err = s3.NewS3Client(cs.csoptions.s3Options)
if err != nil {
return nil, err
}
}
return cs.s3Client, nil
}
}
func (cs *ClientSet) OpenPitrix() (openpitrix.Client, error) {
var err error
if cs.csoptions.openPitrixOptions == nil ||
cs.csoptions.openPitrixOptions.RepoManagerEndpoint == "" ||
cs.csoptions.openPitrixOptions.RuntimeManagerEndpoint == "" ||
cs.csoptions.openPitrixOptions.ClusterManagerEndpoint == "" ||
cs.csoptions.openPitrixOptions.AppManagerEndpoint == "" ||
cs.csoptions.openPitrixOptions.AttachmentManagerEndpoint == "" ||
cs.csoptions.openPitrixOptions.RepoIndexerEndpoint == "" ||
cs.csoptions.openPitrixOptions.CategoryManagerEndpoint == "" {
return nil, ErrClientSetNotEnabled
}
if cs.openpitrixClient != nil {
return cs.openpitrixClient, nil
} else {
cs.openpitrixClient, err = openpitrix.NewClient(cs.csoptions.openPitrixOptions)
if err != nil {
return nil, err
}
return cs.openpitrixClient, nil
}
}
func (cs *ClientSet) MonitoringClient() (monitoring.Interface, error) {
if cs.csoptions.prometheusOptions == nil || cs.csoptions.prometheusOptions.Endpoint == "" {
return nil, ErrClientSetNotEnabled
}
if cs.prometheusClient != nil {
return cs.prometheusClient, nil
} else {
mutex.Lock()
defer mutex.Unlock()
if cs.prometheusClient == nil {
cs.prometheusClient = prometheus.NewPrometheus(cs.csoptions.prometheusOptions)
}
return cs.prometheusClient, nil
}
}
func (cs *ClientSet) KubeSphere() *kubesphere.Client {
return cs.kubesphereClient
}
func (cs *ClientSet) ElasticSearch() (*elasticsearch.Elasticsearch, error) {
var err error
if cs.csoptions.elasticsearhOptions == nil || cs.csoptions.elasticsearhOptions.Host == "" {
return nil, ErrClientSetNotEnabled
}
if cs.elasticSearchClient != nil {
return cs.elasticSearchClient, nil
} else {
mutex.Lock()
defer mutex.Unlock()
if cs.elasticSearchClient == nil {
cs.elasticSearchClient, err = elasticsearch.NewElasticsearch(cs.csoptions.elasticsearhOptions)
if err != nil {
return nil, err
}
}
return cs.elasticSearchClient, nil
}
}

View File

@@ -2,7 +2,7 @@ package k8s
import (
applicationclientset "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned"
s2i "github.com/kubesphere/s2ioperator/pkg/client/clientset/versioned"
istioclient "istio.io/client-go/pkg/clientset/versioned"
"k8s.io/client-go/discovery"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
@@ -14,7 +14,7 @@ import (
type Client interface {
Kubernetes() kubernetes.Interface
KubeSphere() kubesphere.Interface
S2i() s2i.Interface
Istio() istioclient.Interface
Application() applicationclientset.Interface
Discovery() discovery.DiscoveryInterface
Master() string
@@ -23,17 +23,17 @@ type Client interface {
type kubernetesClient struct {
// kubernetes client interface
k8s *kubernetes.Clientset
k8s kubernetes.Interface
// discovery client
discoveryClient *discovery.DiscoveryClient
// generated clientset
ks *kubesphere.Clientset
ks kubesphere.Interface
s2i *s2i.Clientset
application applicationclientset.Interface
application *applicationclientset.Clientset
istio istioclient.Interface
master string
@@ -54,7 +54,7 @@ func NewKubernetesClientOrDie(options *KubernetesOptions) Client {
k8s: kubernetes.NewForConfigOrDie(config),
discoveryClient: discovery.NewDiscoveryClientForConfigOrDie(config),
ks: kubesphere.NewForConfigOrDie(config),
s2i: s2i.NewForConfigOrDie(config),
istio: istioclient.NewForConfigOrDie(config),
application: applicationclientset.NewForConfigOrDie(config),
master: config.Host,
config: config,
@@ -93,11 +93,6 @@ func NewKubernetesClient(options *KubernetesOptions) (Client, error) {
return nil, err
}
k.s2i, err = s2i.NewForConfig(config)
if err != nil {
return nil, err
}
k.application, err = applicationclientset.NewForConfig(config)
if err != nil {
return nil, err
@@ -121,14 +116,14 @@ func (k *kubernetesClient) KubeSphere() kubesphere.Interface {
return k.ks
}
func (k *kubernetesClient) S2i() s2i.Interface {
return k.s2i
}
func (k *kubernetesClient) Application() applicationclientset.Interface {
return k.application
}
func (k *kubernetesClient) Istio() istioclient.Interface {
return k.istio
}
// master address used to generate kubeconfig for downloading
func (k *kubernetesClient) Master() string {
return k.master

View File

@@ -20,103 +20,360 @@ package ldap
import (
"fmt"
"github.com/go-ldap/ldap"
"github.com/golang/mock/gomock"
"k8s.io/klog"
"github.com/google/uuid"
"kubesphere.io/kubesphere/pkg/api/iam"
"kubesphere.io/kubesphere/pkg/server/errors"
"sync"
"time"
)
type Client interface {
NewConn() (ldap.Client, error)
Close()
GroupSearchBase() string
UserSearchBase() string
type Interface interface {
// Create create a new user in ldap
Create(user *iam.User) error
// Update updates a user information, return error if user not exists
Update(user *iam.User) error
// Delete deletes a user from ldap, return nil if user not exists
Delete(name string) error
// Get gets a user by its username from ldap
Get(name string) (*iam.User, error)
//
Verify(name string, password string) error
}
type poolClient struct {
pool Pool
options *Options
const (
ldapAttributeObjectClass = "objectClass"
ldapAttributeCommonName = "cn"
ldapAttributeSerialNumber = "sn"
ldapAttributeGlobalIDNumber = "gidNumber"
ldapAttributeHomeDirectory = "homeDirectory"
ldapAttributeUserID = "uid"
ldapAttributeUserIDNumber = "uidNumber"
ldapAttributeMail = "mail"
ldapAttributeUserPassword = "userPassword"
ldapAttributePreferredLanguage = "preferredLanguage"
ldapAttributeDescription = "description"
ldapAttributeCreateTimestamp = "createTimestamp"
ldapAttributeOrganizationUnit = "ou"
// ldap create timestamp attribute layout
ldapAttributeCreateTimestampLayout = "20060102150405Z"
)
var ErrUserAlreadyExisted = errors.New("user already existed")
var ErrUserNotExists = errors.New("user not exists")
var ErrInvalidCredentials = errors.New("invalid credentials")
type ldapInterfaceImpl struct {
pool Pool
userSearchBase string
groupSearchBase string
managerDN string
managerPassword string
once sync.Once
}
// panic if cannot connect to ldap service
func NewClient(options *Options, stopCh <-chan struct{}) (Client, error) {
pool, err := newChannelPool(options.InitialCap, options.MaxCap, options.PoolName, func(s string) (ldap.Client, error) {
var _ Interface = &ldapInterfaceImpl{}
func NewLdapClient(options *Options, stopCh <-chan struct{}) (Interface, error) {
poolFactory := func(s string) (ldap.Client, error) {
conn, err := ldap.Dial("tcp", options.Host)
if err != nil {
return nil, err
}
return conn, nil
}, []uint16{ldap.LDAPResultAdminLimitExceeded, ldap.ErrorNetwork})
}
pool, err := newChannelPool(options.InitialCap,
options.MaxCap,
options.PoolName,
poolFactory,
[]uint16{ldap.LDAPResultAdminLimitExceeded, ldap.ErrorNetwork})
if err != nil {
klog.Error(err)
return nil, err
}
client := &poolClient{
pool: pool,
options: options,
client := &ldapInterfaceImpl{
pool: pool,
userSearchBase: options.UserSearchBase,
groupSearchBase: options.GroupSearchBase,
managerDN: options.ManagerDN,
managerPassword: options.ManagerPassword,
once: sync.Once{},
}
go func() {
<-stopCh
client.Close()
client.close()
}()
client.once.Do(func() {
_ = client.createSearchBase()
})
return client, nil
}
func (l *poolClient) Close() {
func (l *ldapInterfaceImpl) createSearchBase() error {
conn, err := l.newConn()
if err != nil {
return err
}
createIfNotExistsFunc := func(request *ldap.AddRequest) error {
searchRequest := &ldap.SearchRequest{
BaseDN: request.DN,
Scope: ldap.ScopeWholeSubtree,
DerefAliases: ldap.NeverDerefAliases,
SizeLimit: 0,
TimeLimit: 0,
TypesOnly: false,
Filter: "(objectClass=*)",
}
_, err = conn.Search(searchRequest)
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
return conn.Add(request)
}
return nil
}
userSearchBaseAddRequest := &ldap.AddRequest{
DN: l.userSearchBase,
Attributes: []ldap.Attribute{
{
Type: ldapAttributeObjectClass,
Vals: []string{"organizationalUnit", "top"},
},
{
Type: ldapAttributeOrganizationUnit,
Vals: []string{"Users"},
},
},
}
err = createIfNotExistsFunc(userSearchBaseAddRequest)
if err != nil {
return err
}
groupSearchBaseAddRequest := *userSearchBaseAddRequest
groupSearchBaseAddRequest.DN = l.groupSearchBase
return createIfNotExistsFunc(&groupSearchBaseAddRequest)
}
func (l *ldapInterfaceImpl) close() {
if l.pool != nil {
l.pool.Close()
}
}
func (l *poolClient) NewConn() (ldap.Client, error) {
if l.pool == nil {
err := fmt.Errorf("ldap connection pool is not initialized")
klog.Errorln(err)
func (l *ldapInterfaceImpl) newConn() (ldap.Client, error) {
conn, err := l.pool.Get()
if err != nil {
return nil, err
}
conn, err := l.pool.Get()
// cannot connect to ldap server or pool is closed
if err != nil {
klog.Errorln(err)
return nil, err
}
err = conn.Bind(l.options.ManagerDN, l.options.ManagerPassword)
err = conn.Bind(l.managerDN, l.managerPassword)
if err != nil {
conn.Close()
klog.Errorln(err)
return nil, err
}
return conn, nil
}
func (l *poolClient) GroupSearchBase() string {
return l.options.GroupSearchBase
func (l *ldapInterfaceImpl) dnForUsername(username string) string {
return fmt.Sprintf("uid=%s,%s", username, l.userSearchBase)
}
func (l *poolClient) UserSearchBase() string {
return l.options.UserSearchBase
func (l *ldapInterfaceImpl) filterForUsername(username string) string {
return fmt.Sprintf("(&(objectClass=inetOrgPerson)(|(uid=%s)(mail=%s)))", username, username)
}
func NewMockClient(options *Options, ctrl *gomock.Controller, setup func(client *MockClient)) (Client, error) {
pool, err := newChannelPool(options.InitialCap, options.MaxCap, options.PoolName, func(s string) (ldap.Client, error) {
conn := newMockClient(ctrl)
conn.EXPECT().Bind(gomock.Any(), gomock.Any()).AnyTimes()
conn.EXPECT().Close().AnyTimes()
setup(conn)
return conn, nil
}, []uint16{ldap.LDAPResultAdminLimitExceeded, ldap.ErrorNetwork})
func (l *ldapInterfaceImpl) Get(name string) (*iam.User, error) {
conn, err := l.newConn()
if err != nil {
return nil, err
}
defer conn.Close()
searchRequest := &ldap.SearchRequest{
BaseDN: l.userSearchBase,
Scope: ldap.ScopeWholeSubtree,
DerefAliases: ldap.NeverDerefAliases,
SizeLimit: 0,
TimeLimit: 0,
TypesOnly: false,
Filter: l.filterForUsername(name),
Attributes: []string{
ldapAttributeMail,
ldapAttributeDescription,
ldapAttributePreferredLanguage,
ldapAttributeCreateTimestamp,
},
}
searchResults, err := conn.Search(searchRequest)
if err != nil {
klog.Error(err)
return nil, err
}
client := &poolClient{
pool: pool,
options: options,
if len(searchResults.Entries) != 1 {
return nil, ErrUserNotExists
}
return client, nil
userEntry := searchResults.Entries[0]
user := &iam.User{
Username: userEntry.GetAttributeValue(ldapAttributeUserID),
Email: userEntry.GetAttributeValue(ldapAttributeMail),
Lang: userEntry.GetAttributeValue(ldapAttributePreferredLanguage),
Description: userEntry.GetAttributeValue(ldapAttributeDescription),
}
createTimestamp, _ := time.Parse(ldapAttributeCreateTimestampLayout, userEntry.GetAttributeValue(ldapAttributeCreateTimestamp))
user.CreateTime = createTimestamp
return user, nil
}
func (l *ldapInterfaceImpl) Create(user *iam.User) error {
if _, err := l.Get(user.Username); err != nil {
return ErrUserAlreadyExisted
}
createRequest := &ldap.AddRequest{
DN: l.dnForUsername(user.Username),
Attributes: []ldap.Attribute{
{
Type: ldapAttributeObjectClass,
Vals: []string{"inetOrgPerson", "posixAccount", "top"},
},
{
Type: ldapAttributeCommonName,
Vals: []string{user.Username},
},
{
Type: ldapAttributeSerialNumber,
Vals: []string{" "},
},
{
Type: ldapAttributeGlobalIDNumber,
Vals: []string{"500"},
},
{
Type: ldapAttributeHomeDirectory,
Vals: []string{"/home/" + user.Username},
},
{
Type: ldapAttributeUserID,
Vals: []string{user.Username},
},
{
Type: ldapAttributeUserIDNumber,
Vals: []string{uuid.New().String()},
},
{
Type: ldapAttributeMail,
Vals: []string{user.Email},
},
{
Type: ldapAttributeUserPassword,
Vals: []string{user.Password},
},
{
Type: ldapAttributePreferredLanguage,
Vals: []string{user.Lang},
},
{
Type: ldapAttributeDescription,
Vals: []string{user.Description},
},
},
}
conn, err := l.newConn()
if err != nil {
return err
}
defer conn.Close()
return conn.Add(createRequest)
}
func (l *ldapInterfaceImpl) Delete(name string) error {
conn, err := l.newConn()
if err != nil {
return err
}
defer conn.Close()
_, err = l.Get(name)
if err != nil {
if err == ErrUserNotExists {
return nil
}
return err
}
deleteRequest := &ldap.DelRequest{
DN: l.dnForUsername(name),
}
return conn.Del(deleteRequest)
}
func (l *ldapInterfaceImpl) Update(newUser *iam.User) error {
conn, err := l.newConn()
if err != nil {
return err
}
defer conn.Close()
// check user existed
_, err = l.Get(newUser.Username)
if err != nil {
return err
}
modifyRequest := &ldap.ModifyRequest{
DN: l.dnForUsername(newUser.Username),
}
if newUser.Description != "" {
modifyRequest.Replace(ldapAttributeDescription, []string{newUser.Description})
}
if newUser.Lang != "" {
modifyRequest.Replace(ldapAttributePreferredLanguage, []string{newUser.Lang})
}
if newUser.Password != "" {
modifyRequest.Replace(ldapAttributeUserPassword, []string{newUser.Password})
}
return conn.Modify(modifyRequest)
}
func (l *ldapInterfaceImpl) Verify(username, password string) error {
conn, err := l.newConn()
if err != nil {
return err
}
dn := l.dnForUsername(username)
err = conn.Bind(dn, password)
if ldap.IsErrorWithCode(err, ldap.LDAPResultInvalidCredentials) {
return ErrInvalidCredentials
}
return err
}

Some files were not shown because too many files have changed in this diff Show More