Merge pull request #91785 from mattcary/filtereddial

Specify a DialContext in storage plugin clients
This commit is contained in:
Kubernetes Prow Robot 2020-09-18 15:08:27 -07:00 committed by GitHub
commit b86e725694
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 585 additions and 73 deletions

View File

@ -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

View File

@ -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)

View File

@ -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",
],
)

View File

@ -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,

View File

@ -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
}

4
go.mod
View File

@ -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

4
go.sum
View File

@ -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=

View File

@ -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

View File

@ -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",

View File

@ -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
}

View File

@ -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: <no error> Actual: <%v>", err)

View File

@ -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",

View File

@ -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
}

View File

@ -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)
}

View File

@ -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",

View File

@ -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

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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.

View File

@ -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
}

View File

@ -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
}

View File

@ -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",

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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",

View File

@ -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.

View File

@ -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",

View File

@ -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{

View File

@ -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

View File

@ -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)
}

View File

@ -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))

View File

@ -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",

View File

@ -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) {

View File

@ -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
}

View File

@ -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)
}

View File

@ -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",

View File

@ -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
}

View File

@ -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.

View File

@ -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
}

View File

@ -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)

View File

@ -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",

View File

@ -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
}

48
vendor/github.com/storageos/go-api/cluster.go generated vendored Normal file
View File

@ -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
}

View File

@ -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) {

43
vendor/github.com/storageos/go-api/licence.go generated vendored Normal file
View File

@ -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()
}

View File

@ -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

View File

@ -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,

View File

@ -110,7 +110,7 @@ func (c *Client) PoolDelete(opts types.DeleteOptions) error {
return ErrPoolInUse
}
}
return nil
return err
}
defer resp.Body.Close()
return nil

View File

@ -134,7 +134,7 @@ func (c *Client) RuleDelete(opts types.DeleteOptions) error {
return ErrRuleInUse
}
}
return nil
return err
}
defer resp.Body.Close()
return nil

View File

@ -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",

10
vendor/github.com/storageos/go-api/types/cluster.go generated vendored Normal file
View File

@ -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"`
}

View File

@ -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

35
vendor/github.com/storageos/go-api/types/licence.go generated vendored Normal file
View File

@ -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"`
}

View File

@ -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 != "":

4
vendor/modules.txt vendored
View File

@ -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