diff --git a/api/api-rules/violation_exceptions.list b/api/api-rules/violation_exceptions.list index 89a22b62a2c..d2fc81b01e9 100644 --- a/api/api-rules/violation_exceptions.list +++ b/api/api-rules/violation_exceptions.list @@ -370,6 +370,7 @@ API rule violation: list_type_missing,k8s.io/apiserver/pkg/apis/audit/v1beta1,Po API rule violation: list_type_missing,k8s.io/apiserver/pkg/apis/audit/v1beta1,PolicyRule,Verbs API rule violation: list_type_missing,k8s.io/kube-controller-manager/config/v1alpha1,GarbageCollectorControllerConfiguration,GCIgnoredResources API rule violation: list_type_missing,k8s.io/kube-controller-manager/config/v1alpha1,GenericControllerManagerConfiguration,Controllers +API rule violation: list_type_missing,k8s.io/kube-controller-manager/config/v1alpha1,PersistentVolumeBinderControllerConfiguration,VolumeHostCIDRDenylist API rule violation: list_type_missing,k8s.io/kube-proxy/config/v1alpha1,KubeProxyConfiguration,NodePortAddresses API rule violation: list_type_missing,k8s.io/kube-proxy/config/v1alpha1,KubeProxyIPVSConfiguration,ExcludeCIDRs API rule violation: list_type_missing,k8s.io/kube-scheduler/config/v1,ExtenderTLSConfig,CAData @@ -569,6 +570,8 @@ API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,N API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,NodeLifecycleControllerConfiguration,UnhealthyZoneThreshold API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,PersistentVolumeBinderControllerConfiguration,PVClaimBinderSyncPeriod API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,PersistentVolumeBinderControllerConfiguration,VolumeConfiguration +API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,PersistentVolumeBinderControllerConfiguration,VolumeHostAllowLocalLoopback +API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,PersistentVolumeBinderControllerConfiguration,VolumeHostCIDRDenylist API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,PersistentVolumeRecyclerConfiguration,IncrementTimeoutHostPath API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,PersistentVolumeRecyclerConfiguration,IncrementTimeoutNFS API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,PersistentVolumeRecyclerConfiguration,MaximumRetry diff --git a/cmd/kube-controller-manager/app/core.go b/cmd/kube-controller-manager/app/core.go index 8d68f00621e..3826ac427a0 100644 --- a/cmd/kube-controller-manager/app/core.go +++ b/cmd/kube-controller-manager/app/core.go @@ -43,6 +43,7 @@ import ( servicecontroller "k8s.io/cloud-provider/controllers/service" "k8s.io/component-base/metrics/prometheus/ratelimiter" csitrans "k8s.io/csi-translation-lib" + "k8s.io/kubernetes/cmd/kube-controller-manager/app/options" "k8s.io/kubernetes/pkg/controller" endpointcontroller "k8s.io/kubernetes/pkg/controller/endpoint" "k8s.io/kubernetes/pkg/controller/garbagecollector" @@ -285,6 +286,12 @@ func startPersistentVolumeBinderController(ctx ControllerContext) (http.Handler, if err != nil { return nil, true, fmt.Errorf("failed to probe volume plugins when starting persistentvolume controller: %v", err) } + filteredDialOptions, err := options.ParseVolumeHostFilters( + ctx.ComponentConfig.PersistentVolumeBinderController.VolumeHostCIDRDenylist, + ctx.ComponentConfig.PersistentVolumeBinderController.VolumeHostAllowLocalLoopback) + if err != nil { + return nil, true, err + } params := persistentvolumecontroller.ControllerParameters{ KubeClient: ctx.ClientBuilder.ClientOrDie("persistent-volume-binder"), SyncPeriod: ctx.ComponentConfig.PersistentVolumeBinderController.PVClaimBinderSyncPeriod.Duration, @@ -297,6 +304,7 @@ func startPersistentVolumeBinderController(ctx ControllerContext) (http.Handler, PodInformer: ctx.InformerFactory.Core().V1().Pods(), NodeInformer: ctx.InformerFactory.Core().V1().Nodes(), EnableDynamicProvisioning: ctx.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration.EnableDynamicProvisioning, + FilteredDialOptions: filteredDialOptions, } volumeController, volumeControllerErr := persistentvolumecontroller.NewController(params) if volumeControllerErr != nil { @@ -324,6 +332,13 @@ func startAttachDetachController(ctx ControllerContext) (http.Handler, bool, err return nil, true, fmt.Errorf("failed to probe volume plugins when starting attach/detach controller: %v", err) } + filteredDialOptions, err := options.ParseVolumeHostFilters( + ctx.ComponentConfig.PersistentVolumeBinderController.VolumeHostCIDRDenylist, + ctx.ComponentConfig.PersistentVolumeBinderController.VolumeHostAllowLocalLoopback) + if err != nil { + return nil, true, err + } + attachDetachController, attachDetachControllerErr := attachdetach.NewAttachDetachController( ctx.ClientBuilder.ClientOrDie("attachdetach-controller"), @@ -340,6 +355,7 @@ func startAttachDetachController(ctx ControllerContext) (http.Handler, bool, err ctx.ComponentConfig.AttachDetachController.DisableAttachDetachReconcilerSync, ctx.ComponentConfig.AttachDetachController.ReconcilerSyncLoopPeriod.Duration, attachdetach.DefaultTimerConfig, + filteredDialOptions, ) if attachDetachControllerErr != nil { return nil, true, fmt.Errorf("failed to start attach/detach controller: %v", attachDetachControllerErr) @@ -355,6 +371,12 @@ func startVolumeExpandController(ctx ControllerContext) (http.Handler, bool, err return nil, true, fmt.Errorf("failed to probe volume plugins when starting volume expand controller: %v", err) } csiTranslator := csitrans.New() + filteredDialOptions, err := options.ParseVolumeHostFilters( + ctx.ComponentConfig.PersistentVolumeBinderController.VolumeHostCIDRDenylist, + ctx.ComponentConfig.PersistentVolumeBinderController.VolumeHostAllowLocalLoopback) + if err != nil { + return nil, true, err + } expandController, expandControllerErr := expand.NewExpandController( ctx.ClientBuilder.ClientOrDie("expand-controller"), ctx.InformerFactory.Core().V1().PersistentVolumeClaims(), @@ -363,7 +385,9 @@ func startVolumeExpandController(ctx ControllerContext) (http.Handler, bool, err ctx.Cloud, plugins, csiTranslator, - csimigration.NewPluginManager(csiTranslator)) + csimigration.NewPluginManager(csiTranslator), + filteredDialOptions, + ) if expandControllerErr != nil { return nil, true, fmt.Errorf("failed to start volume expand controller: %v", expandControllerErr) diff --git a/cmd/kube-controller-manager/app/options/BUILD b/cmd/kube-controller-manager/app/options/BUILD index ba65d77052b..248338c19e9 100644 --- a/cmd/kube-controller-manager/app/options/BUILD +++ b/cmd/kube-controller-manager/app/options/BUILD @@ -63,6 +63,7 @@ go_library( "//pkg/controller/volume/attachdetach/config:go_default_library", "//pkg/controller/volume/persistentvolume/config:go_default_library", "//pkg/features:go_default_library", + "//pkg/proxy/util:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server/options:go_default_library", @@ -78,6 +79,7 @@ go_library( "//staging/src/k8s.io/component-base/metrics:go_default_library", "//staging/src/k8s.io/kube-controller-manager/config/v1alpha1:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library", + "//vendor/k8s.io/utils/net:go_default_library", ], ) diff --git a/cmd/kube-controller-manager/app/options/options_test.go b/cmd/kube-controller-manager/app/options/options_test.go index 59e0d252290..872415def16 100644 --- a/cmd/kube-controller-manager/app/options/options_test.go +++ b/cmd/kube-controller-manager/app/options/options_test.go @@ -100,6 +100,8 @@ var args = []string{ "--enable-taint-manager=false", "--cluster-signing-duration=10h", "--flex-volume-plugin-dir=/flex-volume-plugin", + "--volume-host-cidr-denylist=127.0.0.1/28,feed::/16", + "--volume-host-allow-local-loopback=false", "--horizontal-pod-autoscaler-downscale-delay=2m", "--horizontal-pod-autoscaler-sync-period=45s", "--horizontal-pod-autoscaler-upscale-delay=1m", @@ -350,6 +352,8 @@ func TestAddFlags(t *testing.T) { IncrementTimeoutHostPath: 45, }, }, + VolumeHostCIDRDenylist: []string{"127.0.0.1/28", "feed::/16"}, + VolumeHostAllowLocalLoopback: false, }, }, PodGCController: &PodGCControllerOptions{ @@ -589,6 +593,8 @@ func TestApplyTo(t *testing.T) { IncrementTimeoutHostPath: 45, }, }, + VolumeHostCIDRDenylist: []string{"127.0.0.1/28", "feed::/16"}, + VolumeHostAllowLocalLoopback: false, }, PodGCController: podgcconfig.PodGCControllerConfiguration{ TerminatedPodGCThreshold: 12000, diff --git a/cmd/kube-controller-manager/app/options/persistentvolumebindercontroller.go b/cmd/kube-controller-manager/app/options/persistentvolumebindercontroller.go index a09107706dd..4be5a29a9ca 100644 --- a/cmd/kube-controller-manager/app/options/persistentvolumebindercontroller.go +++ b/cmd/kube-controller-manager/app/options/persistentvolumebindercontroller.go @@ -17,9 +17,13 @@ limitations under the License. package options import ( + "fmt" + "github.com/spf13/pflag" persistentvolumeconfig "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/config" + proxyutil "k8s.io/kubernetes/pkg/proxy/util" + netutils "k8s.io/utils/net" ) // PersistentVolumeBinderControllerOptions holds the PersistentVolumeBinderController options. @@ -43,6 +47,8 @@ func (o *PersistentVolumeBinderControllerOptions) AddFlags(fs *pflag.FlagSet) { fs.BoolVar(&o.VolumeConfiguration.EnableHostPathProvisioning, "enable-hostpath-provisioner", o.VolumeConfiguration.EnableHostPathProvisioning, "Enable HostPath PV provisioning when running without a cloud provider. This allows testing and development of provisioning features. HostPath provisioning is not supported in any way, won't work in a multi-node cluster, and should not be used for anything other than testing or development.") fs.BoolVar(&o.VolumeConfiguration.EnableDynamicProvisioning, "enable-dynamic-provisioning", o.VolumeConfiguration.EnableDynamicProvisioning, "Enable dynamic provisioning for environments that support it.") fs.StringVar(&o.VolumeConfiguration.FlexVolumePluginDir, "flex-volume-plugin-dir", o.VolumeConfiguration.FlexVolumePluginDir, "Full path of the directory in which the flex volume plugin should search for additional third party volume plugins.") + fs.StringSliceVar(&o.VolumeHostCIDRDenylist, "volume-host-cidr-denylist", o.VolumeHostCIDRDenylist, "A comma-separated list of CIDR ranges to avoid from volume plugins.") + fs.BoolVar(&o.VolumeHostAllowLocalLoopback, "volume-host-allow-local-loopback", o.VolumeHostAllowLocalLoopback, "If false, deny local loopback IPs in addition to any CIDR ranges in --volume-host-cidr-denylist") } // ApplyTo fills up PersistentVolumeBinderController config with options. @@ -53,6 +59,8 @@ func (o *PersistentVolumeBinderControllerOptions) ApplyTo(cfg *persistentvolumec cfg.PVClaimBinderSyncPeriod = o.PVClaimBinderSyncPeriod cfg.VolumeConfiguration = o.VolumeConfiguration + cfg.VolumeHostCIDRDenylist = o.VolumeHostCIDRDenylist + cfg.VolumeHostAllowLocalLoopback = o.VolumeHostAllowLocalLoopback return nil } @@ -64,5 +72,17 @@ func (o *PersistentVolumeBinderControllerOptions) Validate() []error { } errs := []error{} + if _, err := ParseVolumeHostFilters(o.VolumeHostCIDRDenylist, o.VolumeHostAllowLocalLoopback); err != nil { + errs = append(errs, fmt.Errorf("Bad --volume-host-ip-denylist/--volume-host-allow-local-loopback %w", err)) + } return errs } + +// ParseVolumeHostFilters process the --volume-host-ip-denylist and --volume-host-allow-local-loopback flags. +func ParseVolumeHostFilters(denylist []string, allowLocalLoopback bool) (*proxyutil.FilteredDialOptions, error) { + denyCIDRs, err := netutils.ParseCIDRs(denylist) + if err != nil { + return nil, err + } + return &proxyutil.FilteredDialOptions{DialHostCIDRDenylist: denyCIDRs, AllowLocalLoopback: allowLocalLoopback}, nil +} diff --git a/go.mod b/go.mod index 4715ecd6bd0..22be70a6c6e 100644 --- a/go.mod +++ b/go.mod @@ -91,7 +91,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.4.0 - github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc + github.com/storageos/go-api v2.2.0+incompatible github.com/stretchr/testify v1.4.0 github.com/thecodeteam/goscaleio v0.1.0 github.com/urfave/negroni v1.0.0 // indirect @@ -397,7 +397,7 @@ replace ( github.com/spf13/jwalterweatherman => github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/pflag => github.com/spf13/pflag v1.0.5 github.com/spf13/viper => github.com/spf13/viper v1.4.0 - github.com/storageos/go-api => github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc + github.com/storageos/go-api => github.com/storageos/go-api v2.2.0+incompatible github.com/stretchr/objx => github.com/stretchr/objx v0.2.0 github.com/stretchr/testify => github.com/stretchr/testify v1.4.0 github.com/syndtr/gocapability => github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 diff --git a/go.sum b/go.sum index 917bb9de442..cc3b95fac32 100644 --- a/go.sum +++ b/go.sum @@ -436,8 +436,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc h1:n+WYaU0kQ6WIiuEyWSgbXqkBx16irO69kYCtwVYoO5s= -github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= +github.com/storageos/go-api v2.2.0+incompatible h1:U0SablXoZIg06gvSlg8BCdzq1C/SkHVygOVX95Z2MU0= +github.com/storageos/go-api v2.2.0+incompatible/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= diff --git a/pkg/controller/apis/config/zz_generated.deepcopy.go b/pkg/controller/apis/config/zz_generated.deepcopy.go index 0f5dd63275e..cba4ff2b8d0 100644 --- a/pkg/controller/apis/config/zz_generated.deepcopy.go +++ b/pkg/controller/apis/config/zz_generated.deepcopy.go @@ -123,7 +123,7 @@ func (in *KubeControllerManagerConfiguration) DeepCopyInto(out *KubeControllerMa out.NamespaceController = in.NamespaceController out.NodeIPAMController = in.NodeIPAMController out.NodeLifecycleController = in.NodeLifecycleController - out.PersistentVolumeBinderController = in.PersistentVolumeBinderController + in.PersistentVolumeBinderController.DeepCopyInto(&out.PersistentVolumeBinderController) out.PodGCController = in.PodGCController out.ReplicaSetController = in.ReplicaSetController out.ReplicationController = in.ReplicationController diff --git a/pkg/controller/volume/attachdetach/BUILD b/pkg/controller/volume/attachdetach/BUILD index cb412ec61f8..9e17ac460be 100644 --- a/pkg/controller/volume/attachdetach/BUILD +++ b/pkg/controller/volume/attachdetach/BUILD @@ -19,6 +19,7 @@ go_library( "//pkg/controller/volume/attachdetach/util:go_default_library", "//pkg/controller/volume/common:go_default_library", "//pkg/features:go_default_library", + "//pkg/proxy/util:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/csimigration:go_default_library", "//pkg/volume/util:go_default_library", diff --git a/pkg/controller/volume/attachdetach/attach_detach_controller.go b/pkg/controller/volume/attachdetach/attach_detach_controller.go index dfcfe7b50d9..e5d703f5114 100644 --- a/pkg/controller/volume/attachdetach/attach_detach_controller.go +++ b/pkg/controller/volume/attachdetach/attach_detach_controller.go @@ -55,6 +55,7 @@ import ( "k8s.io/kubernetes/pkg/controller/volume/attachdetach/util" "k8s.io/kubernetes/pkg/controller/volume/common" "k8s.io/kubernetes/pkg/features" + proxyutil "k8s.io/kubernetes/pkg/proxy/util" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/csimigration" volumeutil "k8s.io/kubernetes/pkg/volume/util" @@ -117,21 +118,23 @@ func NewAttachDetachController( prober volume.DynamicPluginProber, disableReconciliationSync bool, reconcilerSyncDuration time.Duration, - timerConfig TimerConfig) (AttachDetachController, error) { + timerConfig TimerConfig, + filteredDialOptions *proxyutil.FilteredDialOptions) (AttachDetachController, error) { adc := &attachDetachController{ - kubeClient: kubeClient, - pvcLister: pvcInformer.Lister(), - pvcsSynced: pvcInformer.Informer().HasSynced, - pvLister: pvInformer.Lister(), - pvsSynced: pvInformer.Informer().HasSynced, - podLister: podInformer.Lister(), - podsSynced: podInformer.Informer().HasSynced, - podIndexer: podInformer.Informer().GetIndexer(), - nodeLister: nodeInformer.Lister(), - nodesSynced: nodeInformer.Informer().HasSynced, - cloud: cloud, - pvcQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "pvcs"), + kubeClient: kubeClient, + pvcLister: pvcInformer.Lister(), + pvcsSynced: pvcInformer.Informer().HasSynced, + pvLister: pvInformer.Lister(), + pvsSynced: pvInformer.Informer().HasSynced, + podLister: podInformer.Lister(), + podsSynced: podInformer.Informer().HasSynced, + podIndexer: podInformer.Informer().GetIndexer(), + nodeLister: nodeInformer.Lister(), + nodesSynced: nodeInformer.Informer().HasSynced, + cloud: cloud, + pvcQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "pvcs"), + filteredDialOptions: filteredDialOptions, } if utilfeature.DefaultFeatureGate.Enabled(features.CSIMigration) && @@ -313,6 +316,9 @@ type attachDetachController struct { // intreeToCSITranslator translates from in-tree volume specs to CSI intreeToCSITranslator csimigration.InTreeToCSITranslator + + // filteredDialOptions configures any dialing done by the controller. + filteredDialOptions *proxyutil.FilteredDialOptions } func (adc *attachDetachController) Run(stopCh <-chan struct{}) { @@ -813,6 +819,10 @@ func (adc *attachDetachController) GetSubpather() subpath.Interface { return nil } +func (adc *attachDetachController) GetFilteredDialOptions() *proxyutil.FilteredDialOptions { + return adc.filteredDialOptions +} + func (adc *attachDetachController) GetCSIDriverLister() storagelistersv1.CSIDriverLister { return adc.csiDriverLister } diff --git a/pkg/controller/volume/attachdetach/attach_detach_controller_test.go b/pkg/controller/volume/attachdetach/attach_detach_controller_test.go index 16988563438..a321478d9c5 100644 --- a/pkg/controller/volume/attachdetach/attach_detach_controller_test.go +++ b/pkg/controller/volume/attachdetach/attach_detach_controller_test.go @@ -55,6 +55,7 @@ func Test_NewAttachDetachController_Positive(t *testing.T) { false, 5*time.Second, DefaultTimerConfig, + nil, /* filteredDialOptions */ ) // Assert @@ -175,7 +176,9 @@ func attachDetachRecoveryTestCase(t *testing.T, extraPods1 []*v1.Pod, extraPods2 prober, false, 1*time.Second, - DefaultTimerConfig) + DefaultTimerConfig, + nil, /* filteredDialOptions */ + ) if err != nil { t.Fatalf("Run failed with error. Expected: Actual: <%v>", err) diff --git a/pkg/controller/volume/expand/BUILD b/pkg/controller/volume/expand/BUILD index b391fce2246..c4068adee66 100644 --- a/pkg/controller/volume/expand/BUILD +++ b/pkg/controller/volume/expand/BUILD @@ -9,6 +9,7 @@ go_library( deps = [ "//pkg/apis/core/v1/helper:go_default_library", "//pkg/controller/volume/events:go_default_library", + "//pkg/proxy/util:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/csimigration:go_default_library", "//pkg/volume/util:go_default_library", diff --git a/pkg/controller/volume/expand/expand_controller.go b/pkg/controller/volume/expand/expand_controller.go index 7d4e833a558..4fda7e15019 100644 --- a/pkg/controller/volume/expand/expand_controller.go +++ b/pkg/controller/volume/expand/expand_controller.go @@ -47,6 +47,7 @@ import ( cloudprovider "k8s.io/cloud-provider" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" "k8s.io/kubernetes/pkg/controller/volume/events" + proxyutil "k8s.io/kubernetes/pkg/proxy/util" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/csimigration" "k8s.io/kubernetes/pkg/volume/util" @@ -104,6 +105,8 @@ type expandController struct { translator CSINameTranslator csiMigratedPluginManager csimigration.PluginManager + + filteredDialOptions *proxyutil.FilteredDialOptions } // NewExpandController expands the pvs @@ -115,7 +118,8 @@ func NewExpandController( cloud cloudprovider.Interface, plugins []volume.VolumePlugin, translator CSINameTranslator, - csiMigratedPluginManager csimigration.PluginManager) (ExpandController, error) { + csiMigratedPluginManager csimigration.PluginManager, + filteredDialOptions *proxyutil.FilteredDialOptions) (ExpandController, error) { expc := &expandController{ kubeClient: kubeClient, @@ -129,6 +133,7 @@ func NewExpandController( queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "volume_expand"), translator: translator, csiMigratedPluginManager: csiMigratedPluginManager, + filteredDialOptions: filteredDialOptions, } if err := expc.volumePluginMgr.InitPlugins(plugins, nil, expc); err != nil { @@ -449,3 +454,7 @@ func (expc *expandController) GetSubpather() subpath.Interface { // not needed for expand controller return nil } + +func (expc *expandController) GetFilteredDialOptions() *proxyutil.FilteredDialOptions { + return expc.filteredDialOptions +} diff --git a/pkg/controller/volume/expand/expand_controller_test.go b/pkg/controller/volume/expand/expand_controller_test.go index e0d0a52c7c4..df400aa0460 100644 --- a/pkg/controller/volume/expand/expand_controller_test.go +++ b/pkg/controller/volume/expand/expand_controller_test.go @@ -126,7 +126,7 @@ func TestSyncHandler(t *testing.T) { informerFactory.Storage().V1().StorageClasses().Informer().GetIndexer().Add(tc.storageClass) } translator := csitrans.New() - expc, err := NewExpandController(fakeKubeClient, pvcInformer, pvInformer, storageClassInformer, nil, allPlugins, translator, csimigration.NewPluginManager(translator)) + expc, err := NewExpandController(fakeKubeClient, pvcInformer, pvInformer, storageClassInformer, nil, allPlugins, translator, csimigration.NewPluginManager(translator), nil) if err != nil { t.Fatalf("error creating expand controller : %v", err) } diff --git a/pkg/controller/volume/persistentvolume/BUILD b/pkg/controller/volume/persistentvolume/BUILD index 35584cc4406..dfc348bdbed 100644 --- a/pkg/controller/volume/persistentvolume/BUILD +++ b/pkg/controller/volume/persistentvolume/BUILD @@ -23,6 +23,7 @@ go_library( "//pkg/controller/volume/persistentvolume/metrics:go_default_library", "//pkg/controller/volume/persistentvolume/util:go_default_library", "//pkg/features:go_default_library", + "//pkg/proxy/util:go_default_library", "//pkg/util/goroutinemap:go_default_library", "//pkg/util/goroutinemap/exponentialbackoff:go_default_library", "//pkg/volume:go_default_library", diff --git a/pkg/controller/volume/persistentvolume/config/types.go b/pkg/controller/volume/persistentvolume/config/types.go index 11b28b0a53c..c840bd0b293 100644 --- a/pkg/controller/volume/persistentvolume/config/types.go +++ b/pkg/controller/volume/persistentvolume/config/types.go @@ -28,6 +28,12 @@ type PersistentVolumeBinderControllerConfiguration struct { PVClaimBinderSyncPeriod metav1.Duration // volumeConfiguration holds configuration for volume related features. VolumeConfiguration VolumeConfiguration + // VolumeHostCIDRDenylist is a list of CIDRs that should not be reachable by the + // controller from plugins. + VolumeHostCIDRDenylist []string + // VolumeHostAllowLocalLoopback indicates if local loopback hosts (127.0.0.1, etc) + // should be allowed from plugins. + VolumeHostAllowLocalLoopback bool } // VolumeConfiguration contains *all* enumerated flags meant to configure all volume diff --git a/pkg/controller/volume/persistentvolume/config/v1alpha1/defaults.go b/pkg/controller/volume/persistentvolume/config/v1alpha1/defaults.go index ce9481ac0cb..5fb6cbfcda5 100644 --- a/pkg/controller/volume/persistentvolume/config/v1alpha1/defaults.go +++ b/pkg/controller/volume/persistentvolume/config/v1alpha1/defaults.go @@ -39,6 +39,11 @@ func RecommendedDefaultPersistentVolumeBinderControllerConfiguration(obj *kubect obj.PVClaimBinderSyncPeriod = metav1.Duration{Duration: 15 * time.Second} } + if obj.VolumeHostAllowLocalLoopback == nil { + trueValue := true + obj.VolumeHostAllowLocalLoopback = &trueValue + } + // Use the default VolumeConfiguration options. RecommendedDefaultVolumeConfiguration(&obj.VolumeConfiguration) } diff --git a/pkg/controller/volume/persistentvolume/config/v1alpha1/zz_generated.conversion.go b/pkg/controller/volume/persistentvolume/config/v1alpha1/zz_generated.conversion.go index 910b6b0f5ce..e1cf08855b0 100644 --- a/pkg/controller/volume/persistentvolume/config/v1alpha1/zz_generated.conversion.go +++ b/pkg/controller/volume/persistentvolume/config/v1alpha1/zz_generated.conversion.go @@ -21,6 +21,8 @@ limitations under the License. package v1alpha1 import ( + unsafe "unsafe" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" @@ -105,6 +107,10 @@ func autoConvert_v1alpha1_PersistentVolumeBinderControllerConfiguration_To_confi if err := Convert_v1alpha1_VolumeConfiguration_To_config_VolumeConfiguration(&in.VolumeConfiguration, &out.VolumeConfiguration, s); err != nil { return err } + out.VolumeHostCIDRDenylist = *(*[]string)(unsafe.Pointer(&in.VolumeHostCIDRDenylist)) + if err := v1.Convert_Pointer_bool_To_bool(&in.VolumeHostAllowLocalLoopback, &out.VolumeHostAllowLocalLoopback, s); err != nil { + return err + } return nil } @@ -113,6 +119,10 @@ func autoConvert_config_PersistentVolumeBinderControllerConfiguration_To_v1alpha if err := Convert_config_VolumeConfiguration_To_v1alpha1_VolumeConfiguration(&in.VolumeConfiguration, &out.VolumeConfiguration, s); err != nil { return err } + out.VolumeHostCIDRDenylist = *(*[]string)(unsafe.Pointer(&in.VolumeHostCIDRDenylist)) + if err := v1.Convert_bool_To_Pointer_bool(&in.VolumeHostAllowLocalLoopback, &out.VolumeHostAllowLocalLoopback, s); err != nil { + return err + } return nil } diff --git a/pkg/controller/volume/persistentvolume/config/zz_generated.deepcopy.go b/pkg/controller/volume/persistentvolume/config/zz_generated.deepcopy.go index 86c2e99e165..47ce776175b 100644 --- a/pkg/controller/volume/persistentvolume/config/zz_generated.deepcopy.go +++ b/pkg/controller/volume/persistentvolume/config/zz_generated.deepcopy.go @@ -25,6 +25,11 @@ func (in *PersistentVolumeBinderControllerConfiguration) DeepCopyInto(out *Persi *out = *in out.PVClaimBinderSyncPeriod = in.PVClaimBinderSyncPeriod out.VolumeConfiguration = in.VolumeConfiguration + if in.VolumeHostCIDRDenylist != nil { + in, out := &in.VolumeHostCIDRDenylist, &out.VolumeHostCIDRDenylist + *out = make([]string, len(*in)) + copy(*out, *in) + } return } diff --git a/pkg/controller/volume/persistentvolume/pv_controller.go b/pkg/controller/volume/persistentvolume/pv_controller.go index 61b1ed1f3ef..28ee91912d3 100644 --- a/pkg/controller/volume/persistentvolume/pv_controller.go +++ b/pkg/controller/volume/persistentvolume/pv_controller.go @@ -45,6 +45,7 @@ import ( "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/metrics" pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util" "k8s.io/kubernetes/pkg/features" + proxyutil "k8s.io/kubernetes/pkg/proxy/util" "k8s.io/kubernetes/pkg/util/goroutinemap" "k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff" vol "k8s.io/kubernetes/pkg/volume" @@ -235,6 +236,9 @@ type PersistentVolumeController struct { translator CSINameTranslator csiMigratedPluginManager CSIMigratedPluginManager + + // filteredDialOptions configures any dialing done by the controller. + filteredDialOptions *proxyutil.FilteredDialOptions } // syncClaim is the main controller method to decide what to do with a claim. diff --git a/pkg/controller/volume/persistentvolume/pv_controller_base.go b/pkg/controller/volume/persistentvolume/pv_controller_base.go index 5747db35fd4..38e1d36e2bb 100644 --- a/pkg/controller/volume/persistentvolume/pv_controller_base.go +++ b/pkg/controller/volume/persistentvolume/pv_controller_base.go @@ -44,6 +44,7 @@ import ( "k8s.io/kubernetes/pkg/controller/volume/common" "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/metrics" pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util" + proxyutil "k8s.io/kubernetes/pkg/proxy/util" "k8s.io/kubernetes/pkg/util/goroutinemap" vol "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/csimigration" @@ -70,6 +71,7 @@ type ControllerParameters struct { NodeInformer coreinformers.NodeInformer EventRecorder record.EventRecorder EnableDynamicProvisioning bool + FilteredDialOptions *proxyutil.FilteredDialOptions } // NewController creates a new PersistentVolume controller @@ -142,6 +144,8 @@ func NewController(p ControllerParameters) (*PersistentVolumeController, error) controller.translator = csiTranslator controller.csiMigratedPluginManager = csimigration.NewPluginManager(csiTranslator) + controller.filteredDialOptions = p.FilteredDialOptions + return controller, nil } diff --git a/pkg/controller/volume/persistentvolume/volume_host.go b/pkg/controller/volume/persistentvolume/volume_host.go index d75333f63d3..4030a844bcd 100644 --- a/pkg/controller/volume/persistentvolume/volume_host.go +++ b/pkg/controller/volume/persistentvolume/volume_host.go @@ -30,6 +30,7 @@ import ( clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/record" cloudprovider "k8s.io/cloud-provider" + proxyutil "k8s.io/kubernetes/pkg/proxy/util" vol "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util/subpath" ) @@ -138,3 +139,7 @@ func (ctrl *PersistentVolumeController) GetSubpather() subpath.Interface { // No volume plugin needs Subpaths in PV controller. return nil } + +func (ctrl *PersistentVolumeController) GetFilteredDialOptions() *proxyutil.FilteredDialOptions { + return ctrl.filteredDialOptions +} diff --git a/pkg/kubelet/BUILD b/pkg/kubelet/BUILD index 669b074c798..d13a5f03e55 100644 --- a/pkg/kubelet/BUILD +++ b/pkg/kubelet/BUILD @@ -98,6 +98,7 @@ go_library( "//pkg/kubelet/util/queue:go_default_library", "//pkg/kubelet/util/sliceutils:go_default_library", "//pkg/kubelet/volumemanager:go_default_library", + "//pkg/proxy/util:go_default_library", "//pkg/security/apparmor:go_default_library", "//pkg/security/podsecuritypolicy/sysctl:go_default_library", "//pkg/util/iptables:go_default_library", diff --git a/pkg/kubelet/volume_host.go b/pkg/kubelet/volume_host.go index b9b6a0eae7b..c4e0361577d 100644 --- a/pkg/kubelet/volume_host.go +++ b/pkg/kubelet/volume_host.go @@ -38,6 +38,7 @@ import ( "k8s.io/kubernetes/pkg/kubelet/configmap" "k8s.io/kubernetes/pkg/kubelet/secret" "k8s.io/kubernetes/pkg/kubelet/token" + proxyutil "k8s.io/kubernetes/pkg/proxy/util" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util/hostutil" @@ -151,6 +152,11 @@ func (kvh *kubeletVolumeHost) GetSubpather() subpath.Interface { return kvh.kubelet.subpather } +func (kvh *kubeletVolumeHost) GetFilteredDialOptions() *proxyutil.FilteredDialOptions { + // FilteredDial is not needed in the kubelet. + return nil +} + func (kvh *kubeletVolumeHost) GetHostUtil() hostutil.HostUtils { return kvh.kubelet.hostutil } diff --git a/pkg/proxy/util/utils.go b/pkg/proxy/util/utils.go index c2bf2c97d15..4cf4e21eaba 100644 --- a/pkg/proxy/util/utils.go +++ b/pkg/proxy/util/utils.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "net" + "net/http" "strconv" v1 "k8s.io/api/core/v1" @@ -124,6 +125,16 @@ func IsProxyableHostname(ctx context.Context, resolv Resolver, hostname string) return nil } +// IsAllowedHost checks if the given IP host address is in a network in the denied list. +func IsAllowedHost(host net.IP, denied []*net.IPNet) error { + for _, ipNet := range denied { + if ipNet.Contains(host) { + return ErrAddressNotAllowed + } + } + return nil +} + // GetLocalAddrs returns a list of all network addresses on the local system func GetLocalAddrs() ([]net.IP, error) { var localAddrs []net.IP @@ -311,3 +322,57 @@ func EnsureSysctl(sysctl utilsysctl.Interface, name string, newVal int) error { } return nil } + +// DialContext is a dial function matching the signature of net.Dialer.DialContext. +type DialContext = func(context.Context, string, string) (net.Conn, error) + +// FilteredDialOptions configures how a DialContext is wrapped by NewFilteredDialContext. +type FilteredDialOptions struct { + // DialHostIPDenylist restricts hosts from being dialed. + DialHostCIDRDenylist []*net.IPNet + // AllowLocalLoopback controls connections to local loopback hosts (as defined by + // IsProxyableIP). + AllowLocalLoopback bool +} + +// NewFilteredDialContext returns a DialContext function that filters connections based on a FilteredDialOptions. +func NewFilteredDialContext(wrapped DialContext, resolv Resolver, opts *FilteredDialOptions) DialContext { + if wrapped == nil { + wrapped = http.DefaultTransport.(*http.Transport).DialContext + } + if opts == nil { + // Do no filtering + return wrapped + } + if resolv == nil { + resolv = net.DefaultResolver + } + if len(opts.DialHostCIDRDenylist) == 0 && opts.AllowLocalLoopback { + // Do no filtering. + return wrapped + } + return func(ctx context.Context, network, address string) (net.Conn, error) { + resp, err := resolv.LookupIPAddr(ctx, address) + if err != nil { + return nil, err + } + + if len(resp) == 0 { + return nil, ErrNoAddresses + } + + for _, host := range resp { + if !opts.AllowLocalLoopback { + if err := isProxyableIP(host.IP); err != nil { + return nil, err + } + } + if opts.DialHostCIDRDenylist != nil { + if err := IsAllowedHost(host.IP, opts.DialHostCIDRDenylist); err != nil { + return nil, err + } + } + } + return wrapped(ctx, network, address) + } +} diff --git a/pkg/proxy/util/utils_test.go b/pkg/proxy/util/utils_test.go index e563a8da888..e7fa4dcea54 100644 --- a/pkg/proxy/util/utils_test.go +++ b/pkg/proxy/util/utils_test.go @@ -163,6 +163,39 @@ func TestIsProxyableHostname(t *testing.T) { } } +func TestIsAllowedHost(t *testing.T) { + testCases := []struct { + ip string + denied []string + want error + }{ + {"8.8.8.8", []string{}, nil}, + {"169.254.169.254", []string{"169.0.0.0/8"}, ErrAddressNotAllowed}, + {"169.254.169.254", []string{"fce8::/15", "169.254.169.0/24"}, ErrAddressNotAllowed}, + {"fce9:beef::", []string{"fce8::/15", "169.254.169.0/24"}, ErrAddressNotAllowed}, + {"127.0.0.1", []string{"127.0.0.1/32"}, ErrAddressNotAllowed}, + {"34.107.204.206", []string{"fce8::/15"}, nil}, + {"fce9:beef::", []string{"127.0.0.1/32"}, nil}, + {"34.107.204.206", []string{"127.0.0.1/32"}, nil}, + {"127.0.0.1", []string{}, nil}, + } + + for i := range testCases { + var denyList []*net.IPNet + for _, cidrStr := range testCases[i].denied { + _, ipNet, err := net.ParseCIDR(cidrStr) + if err != nil { + t.Fatalf("bad IP for test case: %v: %v", cidrStr, err) + } + denyList = append(denyList, ipNet) + } + got := IsAllowedHost(net.ParseIP(testCases[i].ip), denyList) + if testCases[i].want != got { + t.Errorf("case %d: expected %v, got %v", i, testCases[i].want, got) + } + } +} + func TestShouldSkipService(t *testing.T) { testCases := []struct { service *v1.Service diff --git a/pkg/volume/BUILD b/pkg/volume/BUILD index 61c22c29bdd..c195f857c2a 100644 --- a/pkg/volume/BUILD +++ b/pkg/volume/BUILD @@ -18,6 +18,7 @@ go_library( importpath = "k8s.io/kubernetes/pkg/volume", visibility = ["//visibility:public"], deps = [ + "//pkg/proxy/util:go_default_library", "//pkg/volume/util/fs:go_default_library", "//pkg/volume/util/hostutil:go_default_library", "//pkg/volume/util/recyclerclient:go_default_library", diff --git a/pkg/volume/plugins.go b/pkg/volume/plugins.go index 9feccd04286..20edbb3ef60 100644 --- a/pkg/volume/plugins.go +++ b/pkg/volume/plugins.go @@ -39,6 +39,7 @@ import ( "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" cloudprovider "k8s.io/cloud-provider" + proxyutil "k8s.io/kubernetes/pkg/proxy/util" "k8s.io/kubernetes/pkg/volume/util/hostutil" "k8s.io/kubernetes/pkg/volume/util/recyclerclient" "k8s.io/kubernetes/pkg/volume/util/subpath" @@ -450,6 +451,9 @@ type VolumeHost interface { // Returns an interface that should be used to execute subpath operations GetSubpather() subpath.Interface + + // Returns options to pass for proxyutil filtered dialers. + GetFilteredDialOptions() *proxyutil.FilteredDialOptions } // VolumePluginMgr tracks registered plugins. diff --git a/pkg/volume/scaleio/BUILD b/pkg/volume/scaleio/BUILD index d6aabc7d642..d5dd453e1f1 100644 --- a/pkg/volume/scaleio/BUILD +++ b/pkg/volume/scaleio/BUILD @@ -41,6 +41,7 @@ go_library( ], importpath = "k8s.io/kubernetes/pkg/volume/scaleio", deps = [ + "//pkg/proxy/util:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", diff --git a/pkg/volume/scaleio/sio_client.go b/pkg/volume/scaleio/sio_client.go index cdd6c2db631..a9c83267194 100644 --- a/pkg/volume/scaleio/sio_client.go +++ b/pkg/volume/scaleio/sio_client.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "io/ioutil" + "net/http" "os" "path/filepath" "regexp" @@ -33,6 +34,7 @@ import ( sio "github.com/thecodeteam/goscaleio" siotypes "github.com/thecodeteam/goscaleio/types/v1" "k8s.io/klog/v2" + proxyutil "k8s.io/kubernetes/pkg/proxy/util" ) var ( @@ -56,37 +58,39 @@ type sioInterface interface { } type sioClient struct { - client *sio.Client - gateway string - username string - password string - insecure bool - certsEnabled bool - system *siotypes.System - sysName string - sysClient *sio.System - protectionDomain *siotypes.ProtectionDomain - pdName string - pdClient *sio.ProtectionDomain - storagePool *siotypes.StoragePool - spName string - spClient *sio.StoragePool - provisionMode string - sdcPath string - sdcGUID string - instanceID string - inited bool - diskRegex *regexp.Regexp - mtx sync.Mutex - exec utilexec.Interface + client *sio.Client + gateway string + username string + password string + insecure bool + certsEnabled bool + system *siotypes.System + sysName string + sysClient *sio.System + protectionDomain *siotypes.ProtectionDomain + pdName string + pdClient *sio.ProtectionDomain + storagePool *siotypes.StoragePool + spName string + spClient *sio.StoragePool + provisionMode string + sdcPath string + sdcGUID string + instanceID string + inited bool + diskRegex *regexp.Regexp + mtx sync.Mutex + exec utilexec.Interface + filteredDialOptions *proxyutil.FilteredDialOptions } -func newSioClient(gateway, username, password string, sslEnabled bool, exec utilexec.Interface) (*sioClient, error) { +func newSioClient(gateway, username, password string, sslEnabled bool, exec utilexec.Interface, filteredDialOptions *proxyutil.FilteredDialOptions) (*sioClient, error) { client := new(sioClient) client.gateway = gateway client.username = username client.password = password client.exec = exec + client.filteredDialOptions = filteredDialOptions if sslEnabled { client.insecure = false client.certsEnabled = true @@ -118,6 +122,15 @@ func (c *sioClient) init() error { klog.Error(log("failed to create client: %v", err)) return err } + transport, ok := client.Http.Transport.(*http.Transport) + if !ok { + return errors.New("could not set http.Transport options for scaleio client") + } + //lint:ignore SA1019 DialTLS must be used to support legacy clients. + if transport.DialTLS != nil { + return errors.New("DialTLS will be used instead of DialContext") + } + transport.DialContext = proxyutil.NewFilteredDialContext(transport.DialContext, nil, c.filteredDialOptions) c.client = client if _, err = c.client.Authenticate( &sio.ConfigConnect{ diff --git a/pkg/volume/scaleio/sio_mgr.go b/pkg/volume/scaleio/sio_mgr.go index d353fe58ff3..159f040e23a 100644 --- a/pkg/volume/scaleio/sio_mgr.go +++ b/pkg/volume/scaleio/sio_mgr.go @@ -21,6 +21,7 @@ import ( "strconv" "k8s.io/klog/v2" + "k8s.io/kubernetes/pkg/volume" utilexec "k8s.io/utils/exec" siotypes "github.com/thecodeteam/goscaleio/types/v1" @@ -30,9 +31,10 @@ type sioMgr struct { client sioInterface configData map[string]string exec utilexec.Interface + host volume.VolumeHost } -func newSioMgr(configs map[string]string, exec utilexec.Interface) (*sioMgr, error) { +func newSioMgr(configs map[string]string, host volume.VolumeHost, exec utilexec.Interface) (*sioMgr, error) { if configs == nil { return nil, errors.New("missing configuration data") } @@ -41,7 +43,7 @@ func newSioMgr(configs map[string]string, exec utilexec.Interface) (*sioMgr, err configs[confKey.sdcRootPath] = defaultString(configs[confKey.sdcRootPath], sdcRootPath) configs[confKey.storageMode] = defaultString(configs[confKey.storageMode], "ThinProvisioned") - mgr := &sioMgr{configData: configs, exec: exec} + mgr := &sioMgr{configData: configs, host: host, exec: exec} return mgr, nil } @@ -61,7 +63,7 @@ func (m *sioMgr) getClient() (sioInterface, error) { certsEnabled := b klog.V(4).Info(log("creating new client for gateway %s", gateway)) - client, err := newSioClient(gateway, username, password, certsEnabled, m.exec) + client, err := newSioClient(gateway, username, password, certsEnabled, m.exec, m.host.GetFilteredDialOptions()) if err != nil { klog.Error(log("failed to create scaleio client: %v", err)) return nil, err diff --git a/pkg/volume/scaleio/sio_mgr_test.go b/pkg/volume/scaleio/sio_mgr_test.go index f818d2359b3..403b1300c7a 100644 --- a/pkg/volume/scaleio/sio_mgr_test.go +++ b/pkg/volume/scaleio/sio_mgr_test.go @@ -22,6 +22,7 @@ import ( "time" siotypes "github.com/thecodeteam/goscaleio/types/v1" + volumetesting "k8s.io/kubernetes/pkg/volume/testing" "k8s.io/utils/exec/testing" ) @@ -42,7 +43,8 @@ var ( ) func newTestMgr(t *testing.T) *sioMgr { - mgr, err := newSioMgr(fakeConfig, &testingexec.FakeExec{}) + host := volumetesting.NewFakeVolumeHost(t, "/tmp/fake", nil, nil) + mgr, err := newSioMgr(fakeConfig, host, &testingexec.FakeExec{}) if err != nil { t.Error(err) } @@ -51,7 +53,8 @@ func newTestMgr(t *testing.T) *sioMgr { } func TestMgrNew(t *testing.T) { - mgr, err := newSioMgr(fakeConfig, &testingexec.FakeExec{}) + host := volumetesting.NewFakeVolumeHost(t, "/tmp/fake", nil, nil) + mgr, err := newSioMgr(fakeConfig, host, &testingexec.FakeExec{}) if err != nil { t.Fatal(err) } diff --git a/pkg/volume/scaleio/sio_volume.go b/pkg/volume/scaleio/sio_volume.go index 337dba9cb0d..f6d6da975ac 100644 --- a/pkg/volume/scaleio/sio_volume.go +++ b/pkg/volume/scaleio/sio_volume.go @@ -405,7 +405,7 @@ func (v *sioVolume) setSioMgr() error { klog.Error(log("failed to retrieve sdc guid: %v", err)) return err } - mgr, err := newSioMgr(configData, v.plugin.host.GetExec(v.plugin.GetPluginName())) + mgr, err := newSioMgr(configData, v.plugin.host, v.plugin.host.GetExec(v.plugin.GetPluginName())) if err != nil { klog.Error(log("failed to reset sio manager: %v", err)) @@ -444,8 +444,7 @@ func (v *sioVolume) resetSioMgr() error { klog.Error(log("failed to retrieve sdc guid: %v", err)) return err } - - mgr, err := newSioMgr(configData, v.plugin.host.GetExec(v.plugin.GetPluginName())) + mgr, err := newSioMgr(configData, v.plugin.host, v.plugin.host.GetExec(v.plugin.GetPluginName())) if err != nil { klog.Error(log("failed to reset scaleio mgr: %v", err)) @@ -480,8 +479,7 @@ func (v *sioVolume) setSioMgrFromConfig() error { klog.Error(log("failed to load secret: %v", err)) return err } - - mgr, err := newSioMgr(data, v.plugin.host.GetExec(v.plugin.GetPluginName())) + mgr, err := newSioMgr(data, v.plugin.host, v.plugin.host.GetExec(v.plugin.GetPluginName())) if err != nil { klog.Error(log("failed while setting scaleio mgr from config: %v", err)) @@ -516,8 +514,7 @@ func (v *sioVolume) setSioMgrFromSpec() error { klog.Error(log("failed to load secret: %v", err)) return err } - - mgr, err := newSioMgr(configData, v.plugin.host.GetExec(v.plugin.GetPluginName())) + mgr, err := newSioMgr(configData, v.plugin.host, v.plugin.host.GetExec(v.plugin.GetPluginName())) if err != nil { klog.Error(log("failed to reset sio manager: %v", err)) diff --git a/pkg/volume/storageos/BUILD b/pkg/volume/storageos/BUILD index f66bb22b190..dffd6341a45 100644 --- a/pkg/volume/storageos/BUILD +++ b/pkg/volume/storageos/BUILD @@ -15,6 +15,7 @@ go_library( ], importpath = "k8s.io/kubernetes/pkg/volume/storageos", deps = [ + "//pkg/proxy/util:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", diff --git a/pkg/volume/storageos/storageos.go b/pkg/volume/storageos/storageos.go index 7243eaccc5c..e1ad8b9b8f3 100644 --- a/pkg/volume/storageos/storageos.go +++ b/pkg/volume/storageos/storageos.go @@ -110,7 +110,7 @@ func (plugin *storageosPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volu return nil, err } - return plugin.newMounterInternal(spec, pod, apiCfg, &storageosUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName())) + return plugin.newMounterInternal(spec, pod, apiCfg, &storageosUtil{host: plugin.host}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName())) } func (plugin *storageosPlugin) newMounterInternal(spec *volume.Spec, pod *v1.Pod, apiCfg *storageosAPIConfig, manager storageosManager, mounter mount.Interface, exec utilexec.Interface) (volume.Mounter, error) { @@ -142,7 +142,7 @@ func (plugin *storageosPlugin) newMounterInternal(spec *volume.Spec, pod *v1.Pod } func (plugin *storageosPlugin) NewUnmounter(pvName string, podUID types.UID) (volume.Unmounter, error) { - return plugin.newUnmounterInternal(pvName, podUID, &storageosUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName())) + return plugin.newUnmounterInternal(pvName, podUID, &storageosUtil{host: plugin.host}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName())) } func (plugin *storageosPlugin) newUnmounterInternal(pvName string, podUID types.UID, manager storageosManager, mounter mount.Interface, exec utilexec.Interface) (volume.Unmounter, error) { @@ -194,7 +194,7 @@ func (plugin *storageosPlugin) NewDeleter(spec *volume.Spec) (volume.Deleter, er return nil, fmt.Errorf("failed to get admin secret from [%q/%q]: %v", adminSecretNamespace, adminSecretName, err) } - return plugin.newDeleterInternal(spec, apiCfg, &storageosUtil{}) + return plugin.newDeleterInternal(spec, apiCfg, &storageosUtil{host: plugin.host}) } func (plugin *storageosPlugin) newDeleterInternal(spec *volume.Spec, apiCfg *storageosAPIConfig, manager storageosManager) (volume.Deleter, error) { @@ -215,7 +215,7 @@ func (plugin *storageosPlugin) newDeleterInternal(spec *volume.Spec, apiCfg *sto } func (plugin *storageosPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) { - return plugin.newProvisionerInternal(options, &storageosUtil{}) + return plugin.newProvisionerInternal(options, &storageosUtil{host: plugin.host}) } func (plugin *storageosPlugin) newProvisionerInternal(options volume.VolumeOptions, manager storageosManager) (volume.Provisioner, error) { diff --git a/pkg/volume/storageos/storageos_util.go b/pkg/volume/storageos/storageos_util.go index 00f2e09a684..8f080e39f9a 100644 --- a/pkg/volume/storageos/storageos_util.go +++ b/pkg/volume/storageos/storageos_util.go @@ -26,6 +26,8 @@ import ( storageosapi "github.com/storageos/go-api" storageostypes "github.com/storageos/go-api/types" "k8s.io/klog/v2" + proxyutil "k8s.io/kubernetes/pkg/proxy/util" + "k8s.io/kubernetes/pkg/volume" utilexec "k8s.io/utils/exec" ) @@ -76,13 +78,17 @@ type apiImplementer interface { // storageosUtil is the utility structure to interact with the StorageOS API. type storageosUtil struct { - api apiImplementer + api apiImplementer + host volume.VolumeHost } func (u *storageosUtil) NewAPI(apiCfg *storageosAPIConfig) error { if u.api != nil { return nil } + if u.host == nil { + return errors.New("host must not be nil") + } if apiCfg == nil { apiCfg = &storageosAPIConfig{ apiAddr: defaultAPIAddress, @@ -98,6 +104,9 @@ func (u *storageosUtil) NewAPI(apiCfg *storageosAPIConfig) error { return err } api.SetAuth(apiCfg.apiUser, apiCfg.apiPass) + if err := api.SetDialContext(proxyutil.NewFilteredDialContext(api.GetDialContext(), nil, u.host.GetFilteredDialOptions())); err != nil { + return fmt.Errorf("failed to set DialContext in storageos client: %v", err) + } u.api = api return nil } diff --git a/pkg/volume/storageos/storageos_util_test.go b/pkg/volume/storageos/storageos_util_test.go index 2c00adce646..c658f71b044 100644 --- a/pkg/volume/storageos/storageos_util_test.go +++ b/pkg/volume/storageos/storageos_util_test.go @@ -49,8 +49,12 @@ func GetAPIConfig() *storageosAPIConfig { } func TestClient(t *testing.T) { - util := storageosUtil{} - err := util.NewAPI(GetAPIConfig()) + tmpDir, err := utiltesting.MkTmpdir("storageos_test") + if err != nil { + t.Fatalf("error creating tmpdir: %v", err) + } + util := storageosUtil{host: volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil)} + err = util.NewAPI(GetAPIConfig()) if err != nil { t.Fatalf("error getting api config: %v", err) } diff --git a/pkg/volume/testing/BUILD b/pkg/volume/testing/BUILD index 58007e7f2e6..84e420944be 100644 --- a/pkg/volume/testing/BUILD +++ b/pkg/volume/testing/BUILD @@ -13,6 +13,7 @@ go_library( ], importpath = "k8s.io/kubernetes/pkg/volume/testing", deps = [ + "//pkg/proxy/util:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", "//pkg/volume/util/hostutil:go_default_library", diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index f19f913860b..f6884efaa64 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -46,6 +46,7 @@ import ( "k8s.io/client-go/tools/record" utiltesting "k8s.io/client-go/util/testing" cloudprovider "k8s.io/cloud-provider" + proxyutil "k8s.io/kubernetes/pkg/proxy/util" . "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util/hostutil" @@ -118,6 +119,7 @@ type fakeVolumeHost struct { informerFactory informers.SharedInformerFactory kubeletErr error mux sync.Mutex + filteredDialOptions *proxyutil.FilteredDialOptions } var _ VolumeHost = &fakeVolumeHost{} @@ -207,6 +209,10 @@ func (f *fakeVolumeHost) GetSubpather() subpath.Interface { return f.subpather } +func (f *fakeVolumeHost) GetFilteredDialOptions() *proxyutil.FilteredDialOptions { + return f.filteredDialOptions +} + func (f *fakeVolumeHost) GetPluginMgr() *VolumePluginMgr { return f.pluginMgr } diff --git a/staging/src/k8s.io/kube-controller-manager/config/v1alpha1/types.go b/staging/src/k8s.io/kube-controller-manager/config/v1alpha1/types.go index a92805d8c0f..c693f30d95a 100644 --- a/staging/src/k8s.io/kube-controller-manager/config/v1alpha1/types.go +++ b/staging/src/k8s.io/kube-controller-manager/config/v1alpha1/types.go @@ -471,6 +471,12 @@ type PersistentVolumeBinderControllerConfiguration struct { PVClaimBinderSyncPeriod metav1.Duration // volumeConfiguration holds configuration for volume related features. VolumeConfiguration VolumeConfiguration + // VolumeHostCIDRDenylist is a list of CIDRs that should not be reachable by the + // controller from plugins. + VolumeHostCIDRDenylist []string + // VolumeHostAllowLocalLoopback indicates if local loopback hosts (127.0.0.1, etc) + // should be allowed from plugins. + VolumeHostAllowLocalLoopback *bool } // PodGCControllerConfiguration contains elements describing PodGCController. diff --git a/staging/src/k8s.io/kube-controller-manager/config/v1alpha1/zz_generated.deepcopy.go b/staging/src/k8s.io/kube-controller-manager/config/v1alpha1/zz_generated.deepcopy.go index 5e7fc064d95..453675db207 100644 --- a/staging/src/k8s.io/kube-controller-manager/config/v1alpha1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/kube-controller-manager/config/v1alpha1/zz_generated.deepcopy.go @@ -442,6 +442,16 @@ func (in *PersistentVolumeBinderControllerConfiguration) DeepCopyInto(out *Persi *out = *in out.PVClaimBinderSyncPeriod = in.PVClaimBinderSyncPeriod in.VolumeConfiguration.DeepCopyInto(&out.VolumeConfiguration) + if in.VolumeHostCIDRDenylist != nil { + in, out := &in.VolumeHostCIDRDenylist, &out.VolumeHostCIDRDenylist + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.VolumeHostAllowLocalLoopback != nil { + in, out := &in.VolumeHostAllowLocalLoopback, &out.VolumeHostAllowLocalLoopback + *out = new(bool) + **out = **in + } return } diff --git a/test/integration/volume/attach_detach_test.go b/test/integration/volume/attach_detach_test.go index 4e6d0ffb9f4..116cdfc6b27 100644 --- a/test/integration/volume/attach_detach_test.go +++ b/test/integration/volume/attach_detach_test.go @@ -438,7 +438,9 @@ func createAdClients(ns *v1.Namespace, t *testing.T, server *httptest.Server, sy nil, /* prober */ false, 5*time.Second, - timers) + timers, + nil, /* filteredDialOptions */ + ) if err != nil { t.Fatalf("Error creating AttachDetach : %v", err) diff --git a/vendor/github.com/storageos/go-api/BUILD b/vendor/github.com/storageos/go-api/BUILD index c052c8e3266..b10689ab3fa 100644 --- a/vendor/github.com/storageos/go-api/BUILD +++ b/vendor/github.com/storageos/go-api/BUILD @@ -4,7 +4,9 @@ go_library( name = "go_default_library", srcs = [ "client.go", + "cluster.go", "health.go", + "licence.go", "logger.go", "login.go", "namespace.go", diff --git a/vendor/github.com/storageos/go-api/client.go b/vendor/github.com/storageos/go-api/client.go index 4a95516b14b..1a6dc0dcde4 100644 --- a/vendor/github.com/storageos/go-api/client.go +++ b/vendor/github.com/storageos/go-api/client.go @@ -44,6 +44,9 @@ var ( // ErrProxyNotSupported is returned when a client is unable to set a proxy for http requests. ErrProxyNotSupported = errors.New("client does not support http proxy") + // ErrDialerNotSupported is returned when a client is unable to set a DialContext for http requests. + ErrDialerNotSupported = errors.New("client does not support setting DialContext") + // DefaultPort is the default API port. DefaultPort = "5705" @@ -107,6 +110,8 @@ type Dialer interface { Dial(network, address string) (net.Conn, error) } +type dialContext = func(ctx context.Context, network, address string) (net.Conn, error) + // NewClient returns a Client instance ready for communication with the given // server endpoint. It will use the latest remote API version available in the // server. @@ -203,6 +208,36 @@ func (c *Client) SetTimeout(t time.Duration) { } } +// GetDialContext returns the current DialContext function, or nil if there is none. +func (c *Client) GetDialContext() dialContext { + c.configLock.RLock() + defer c.configLock.RUnlock() + + if c.httpClient == nil { + return nil + } + transport, supported := c.httpClient.Transport.(*http.Transport) + if !supported { + return nil + } + return transport.DialContext +} + +// SetDialContext uses the given dial function to establish TCP connections in the HTTPClient. +func (c *Client) SetDialContext(dial dialContext) error { + c.configLock.Lock() + defer c.configLock.Unlock() + + if client := c.httpClient; client != nil { + transport, supported := client.Transport.(*http.Transport) + if !supported { + return ErrDialerNotSupported + } + transport.DialContext = dial + } + return nil +} + func (c *Client) checkAPIVersion() error { serverAPIVersionString, err := c.getServerAPIVersionString() if err != nil { @@ -259,6 +294,8 @@ type doOptions struct { forceJSON bool force bool unversioned bool + + retryOn []int // http.status codes } func (c *Client) do(method, urlpath string, doOptions doOptions) (*http.Response, error) { @@ -338,6 +375,7 @@ func (c *Client) do(method, urlpath string, doOptions doOptions) (*http.Response resp, err := httpClient.Do(req.WithContext(ctx)) if err != nil { + // If it is a custom error, return it. It probably knows more than us if serror.IsStorageOSError(err) { switch serror.ErrorKind(err) { @@ -366,6 +404,17 @@ func (c *Client) do(method, urlpath string, doOptions doOptions) (*http.Response } } + var shouldretry bool + if doOptions.retryOn != nil { + for _, code := range doOptions.retryOn { + if resp.StatusCode == code { + failedAddresses[address] = struct{}{} + shouldretry = true + } + + } + } + // If we get to the point of response, we should move any failed // addresses to the back. failed := len(failedAddresses) @@ -388,6 +437,10 @@ func (c *Client) do(method, urlpath string, doOptions doOptions) (*http.Response c.addressLock.Unlock() } + if shouldretry { + continue + } + if resp.StatusCode < 200 || resp.StatusCode >= 400 { return nil, newError(resp) // These status codes are likely to be fatal } diff --git a/vendor/github.com/storageos/go-api/cluster.go b/vendor/github.com/storageos/go-api/cluster.go new file mode 100644 index 00000000000..1ba6f86451d --- /dev/null +++ b/vendor/github.com/storageos/go-api/cluster.go @@ -0,0 +1,48 @@ +package storageos + +import ( + "encoding/json" + + "github.com/storageos/go-api/types" +) + +var ( + // ClusterMaintenanceAPIPrefix is a path to the HTTP endpoint for managing + // the cluster maintenance mode. + ClusterMaintenanceAPIPrefix = "cluster/maintenance" +) + +// Maintenance returns the maintenance status of the cluster +func (c *Client) Maintenance() (*types.Maintenance, error) { + resp, err := c.do("GET", ClusterMaintenanceAPIPrefix, doOptions{}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + res := &types.Maintenance{} + if err := json.NewDecoder(resp.Body).Decode(res); err != nil { + return nil, err + } + return res, nil +} + +// EnableMaintenance enables maintenance mode in the cluster +func (c *Client) EnableMaintenance() error { + resp, err := c.do("POST", ClusterMaintenanceAPIPrefix, doOptions{}) + if err != nil { + return err + } + defer resp.Body.Close() + return nil +} + +// DisableMaintenance disables maintenance mode in the cluster +func (c *Client) DisableMaintenance() error { + resp, err := c.do("DELETE", ClusterMaintenanceAPIPrefix, doOptions{}) + if err != nil { + return err + } + defer resp.Body.Close() + return nil +} diff --git a/vendor/github.com/storageos/go-api/health.go b/vendor/github.com/storageos/go-api/health.go index 7b441000749..b1acd5db890 100644 --- a/vendor/github.com/storageos/go-api/health.go +++ b/vendor/github.com/storageos/go-api/health.go @@ -14,6 +14,22 @@ var ( HealthAPIPrefix = "health" ) +func (c *Client) ClusterHealth(ctx context.Context) ([]*types.ClusterHealthNode, error) { + status := []*types.ClusterHealthNode{} + url := fmt.Sprintf("/cluster/%s", HealthAPIPrefix) + + resp, err := c.do("GET", url, doOptions{context: ctx, retryOn: []int{http.StatusNotFound}}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if err := json.NewDecoder(resp.Body).Decode(&status); err != nil { + return nil, err + } + return status, nil +} + // CPHealth returns the health of the control plane server at a given url. func (c *Client) CPHealth(ctx context.Context, hostname string) (*types.CPHealthStatus, error) { diff --git a/vendor/github.com/storageos/go-api/licence.go b/vendor/github.com/storageos/go-api/licence.go new file mode 100644 index 00000000000..425d97462cd --- /dev/null +++ b/vendor/github.com/storageos/go-api/licence.go @@ -0,0 +1,43 @@ +package storageos + +import ( + "encoding/json" + + "github.com/storageos/go-api/types" +) + +const ( + // licenceAPIPrefix is a partial path to the HTTP endpoint. + licenceAPIPrefix = "licencing" +) + +// Licence returns the current licence on the server. +func (c *Client) Licence() (*types.Licence, error) { + resp, err := c.do("GET", licenceAPIPrefix, doOptions{}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + licence := &types.Licence{} + if err := json.NewDecoder(resp.Body).Decode(&licence); err != nil { + return nil, err + } + return licence, nil +} + +// LicenceApply applies a licence on the server. +func (c *Client) LicenceApply(licenceKey string) error { + _, err := c.do("POST", licenceAPIPrefix, doOptions{ + data: &types.LicenceKeyContainer{Key: licenceKey}, + }) + return err +} + +// LicenceDelete removes the current licence. +func (c *Client) LicenceDelete() error { + resp, err := c.do("DELETE", licenceAPIPrefix, doOptions{}) + if err != nil { + return err + } + return resp.Body.Close() +} diff --git a/vendor/github.com/storageos/go-api/netutil/parsers.go b/vendor/github.com/storageos/go-api/netutil/parsers.go index cb297e83488..932c7795b80 100644 --- a/vendor/github.com/storageos/go-api/netutil/parsers.go +++ b/vendor/github.com/storageos/go-api/netutil/parsers.go @@ -55,6 +55,12 @@ func AddressesFromNodes(nodes []string) ([]string, error) { return nil, newInvalidNodeError(errInvalidHostName) } + // Given input like "http://localhost:8080:8383", url.Parse() will + // return host as "localhost:8000", which isn't a vaild DNS name. + if strings.Contains(host, ":") { + return nil, newInvalidNodeError(errInvalidHostName) + } + port := url.Port() if port == "" { port = DefaultDialPort diff --git a/vendor/github.com/storageos/go-api/policy.go b/vendor/github.com/storageos/go-api/policy.go index 9d2f6604fdc..f5c1a050df7 100644 --- a/vendor/github.com/storageos/go-api/policy.go +++ b/vendor/github.com/storageos/go-api/policy.go @@ -29,7 +29,7 @@ func (n *nopMarshaler) MarshalJSON() ([]byte, error) { } // PolicyCreate creates a policy on the server. -func (c *Client) PolicyCreate(jsonl []byte, ctx context.Context) error { +func (c *Client) PolicyCreate(ctx context.Context, jsonl []byte) error { nopm := nopMarshaler(jsonl) _, err := c.do("POST", PolicyAPIPrefix, doOptions{ data: &nopm, diff --git a/vendor/github.com/storageos/go-api/pool.go b/vendor/github.com/storageos/go-api/pool.go index c4629d74f6a..b383e77007c 100644 --- a/vendor/github.com/storageos/go-api/pool.go +++ b/vendor/github.com/storageos/go-api/pool.go @@ -110,7 +110,7 @@ func (c *Client) PoolDelete(opts types.DeleteOptions) error { return ErrPoolInUse } } - return nil + return err } defer resp.Body.Close() return nil diff --git a/vendor/github.com/storageos/go-api/rule.go b/vendor/github.com/storageos/go-api/rule.go index fc92d150229..af1dc196849 100644 --- a/vendor/github.com/storageos/go-api/rule.go +++ b/vendor/github.com/storageos/go-api/rule.go @@ -134,7 +134,7 @@ func (c *Client) RuleDelete(opts types.DeleteOptions) error { return ErrRuleInUse } } - return nil + return err } defer resp.Body.Close() return nil diff --git a/vendor/github.com/storageos/go-api/types/BUILD b/vendor/github.com/storageos/go-api/types/BUILD index 02b1afff3f0..11bcfe84805 100644 --- a/vendor/github.com/storageos/go-api/types/BUILD +++ b/vendor/github.com/storageos/go-api/types/BUILD @@ -5,6 +5,7 @@ go_library( srcs = [ "auth.go", "capacity_stats.go", + "cluster.go", "connectivity.go", "delete_options.go", "deployment.go", @@ -12,6 +13,7 @@ go_library( "error_response.go", "events.go", "health.go", + "licence.go", "list_options.go", "logger.go", "namespace.go", diff --git a/vendor/github.com/storageos/go-api/types/cluster.go b/vendor/github.com/storageos/go-api/types/cluster.go new file mode 100644 index 00000000000..65625d01210 --- /dev/null +++ b/vendor/github.com/storageos/go-api/types/cluster.go @@ -0,0 +1,10 @@ +package types + +import "time" + +// Maintenance is used to place the cluster in maintenance mode. +type Maintenance struct { + Enabled bool `json:"enabled"` + UpdatedBy string `json:"updatedBy"` + UpdatedAt time.Time `json:"updatedAt"` +} diff --git a/vendor/github.com/storageos/go-api/types/health.go b/vendor/github.com/storageos/go-api/types/health.go index d6c6d8eb6ca..6efe0a4079b 100644 --- a/vendor/github.com/storageos/go-api/types/health.go +++ b/vendor/github.com/storageos/go-api/types/health.go @@ -14,6 +14,20 @@ type NamedSubModuleStatus struct { SubModuleStatus } +type ClusterHealthNode struct { + NodeID string `json:"nodeID"` + NodeName string `json:"nodeName"` + Submodules struct { + DirectFSInitiator SubModuleStatus `json:"directfs_initiator"` + Director SubModuleStatus `json:"director"` + KV SubModuleStatus `json:"kv"` + KVWrite SubModuleStatus `json:"kv_write"` + NATS SubModuleStatus `json:"nats"` + Presentation SubModuleStatus `json:"presentation"` + RDB SubModuleStatus `json:"rdb"` + } `json:"submodules"` +} + type CPHealthStatus struct { KV SubModuleStatus KVWrite SubModuleStatus diff --git a/vendor/github.com/storageos/go-api/types/licence.go b/vendor/github.com/storageos/go-api/types/licence.go new file mode 100644 index 00000000000..c486ed2bb7b --- /dev/null +++ b/vendor/github.com/storageos/go-api/types/licence.go @@ -0,0 +1,35 @@ +package types + +import "time" + +// FeatureType store features types +type FeatureType string + +const ( + // HA means High Availability + HA = FeatureType("HA") + // DEV means developer licence + DEV = FeatureType("DEV") + // TRIAL means trial licence + TRIAL = FeatureType("TRIAL") +) + +// Licence holds the information to be encoded in the licence key. It needs to be synced across +// the django server running on portal-API as well as the corresponding decoding package on the +// storageOS control plane +type Licence struct { + ArrayUUID string `json:"arrayUUID,omitempty"` + ClusterID string `json:"clusterID,omitempty"` + CustomerID string `json:"customerID"` + CustomerName string `json:"customerName"` + Storage int `json:"storage"` + ValidUntil time.Time `json:"validUntil"` + LicenceType string `json:"licenceType"` + Features map[FeatureType]bool `json:"features"` + Unregistered bool `json:"unregistered"` +} + +// LicenceKeyContainer - stores a licence key +type LicenceKeyContainer struct { + Key string `json:"key"` +} diff --git a/vendor/github.com/storageos/go-api/user.go b/vendor/github.com/storageos/go-api/user.go index 19688203aa0..bfea90105d2 100644 --- a/vendor/github.com/storageos/go-api/user.go +++ b/vendor/github.com/storageos/go-api/user.go @@ -12,7 +12,6 @@ import ( ) var ( - // UserAPIPrefix is a partial path to the HTTP endpoint. UserAPIPrefix = "users" @@ -77,7 +76,7 @@ func (c *Client) UserCreate(opts types.UserCreateOptions) error { } // UserUpdate updates a user on the server. -func (c *Client) UserUpdate(user *types.User, ctx context.Context) error { +func (c *Client) UserUpdate(ctx context.Context, user *types.User) error { var ref string switch { case user.UUID != "": diff --git a/vendor/modules.txt b/vendor/modules.txt index 9a1c384a327..4a6bd5fe055 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1010,10 +1010,10 @@ github.com/spf13/pflag ## explicit github.com/spf13/viper # github.com/spf13/viper => github.com/spf13/viper v1.4.0 -# github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc => github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc +# github.com/storageos/go-api v2.2.0+incompatible => github.com/storageos/go-api v2.2.0+incompatible ## explicit github.com/storageos/go-api -# github.com/storageos/go-api => github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc +# github.com/storageos/go-api => github.com/storageos/go-api v2.2.0+incompatible github.com/storageos/go-api/netutil github.com/storageos/go-api/serror github.com/storageos/go-api/types