diff --git a/.travis.yml b/.travis.yml index 18d12de1d..a36fbe5a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,12 @@ go: - 1.13.x install: - go get -u github.com/vbatts/git-validation + - curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl + - chmod +x kubectl + - mv kubectl ${GOPATH}/bin + - curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-$(uname)-amd64 + - chmod +x ./kind + - mv ./kind ${GOPATH}/bin script: - git-validation -run DCO,short-subject - if [[ $(go version) == *"1.13"* ]]; then @@ -15,11 +21,8 @@ script: - make docker-proto - git diff $(find . -name "*.pb.*go" -o -name "api.swagger.json" | grep -v vendor) | wc -l | grep "^0" - git grep -rw GPL vendor | grep LICENSE | egrep -v "yaml.v2" | wc -l | grep "^0" - - make sdk-check-version - - make install - - make vet + - make install verify - bash hack/docker-integration-test.sh - - make docker-test - if [ "${TRAVIS_PULL_REQUEST}" == "false" ]; then echo "${DOCKER_PASS}" | docker login -u "${DOCKER_USER}" --password-stdin; make push-mock-sdk-server; diff --git a/Makefile b/Makefile index 4e4bd10c2..7fe8adc39 100644 --- a/Makefile +++ b/Makefile @@ -82,6 +82,8 @@ OSDSANITY:=cmd/osd-sanity/osd-sanity clean \ generate \ generate-mockfiles \ + e2e \ + verify \ sdk-check-version @@ -157,7 +159,7 @@ build: packr go build -tags "$(TAGS)" $(BUILDFLAGS) $(PKGS) install: packr $(OSDSANITY)-install - go install -tags "$(TAGS)" $(PKGS) + go install -gcflags="all=-N -l" -tags "$(TAGS)" $(PKGS) go install github.com/libopenstorage/openstorage/cmd/osd-token-generator $(OSDSANITY): @@ -412,3 +414,9 @@ mockgen: mockgen -destination=api/mock/mock_volume.go -package=mock github.com/libopenstorage/openstorage/api OpenStorageVolumeServer,OpenStorageVolumeClient mockgen -destination=api/mock/mock_fstrim.go -package=mock github.com/libopenstorage/openstorage/api OpenStorageFilesystemTrimServer,OpenStorageFilesystemTrimClient mockgen -destination=api/mock/mock_fscheck.go -package=mock github.com/libopenstorage/openstorage/api OpenStorageFilesystemCheckServer,OpenStorageFilesystemCheckClient + mockgen -destination=api/server/mock/mock_schedops_k8s.go -package=mock github.com/portworx/sched-ops/k8s/core Ops + +e2e: docker-build-osd + cd test && ./run.bash + +verify: vet sdk-check-version docker-test e2e \ No newline at end of file diff --git a/api/api.go b/api/api.go index c89b18e4e..5643d716b 100644 --- a/api/api.go +++ b/api/api.go @@ -169,6 +169,19 @@ const ( AutoAggregation = math.MaxUint32 ) +// The main goal of the following label keys is for the Kubernetes intree middleware +// to keep track of the source location of the PVC with labels that cannot be modified +// by the owner of the volume, but only by the storage administrator. +const ( + // KubernetesPvcNameKey is a label on the openstorage volume + // which tracks the source PVC for the volume. + KubernetesPvcNameKey = "openstorage.io/pvc-name" + + // KubernetesPvcNamespaceKey is a label on the openstorage volume + // which tracks the source PVC namespace for the volume + KubernetesPvcNamespaceKey = "openstorage.io/pvc-namespace" +) + // Node describes the state of a node. // It includes the current physical state (CPU, memory, storage, network usage) as // well as the containers running on the system. @@ -1204,4 +1217,6 @@ func (v *Volume) IsAttached() bool { type TokenSecretContext struct { SecretName string SecretNamespace string + PvcName string + PvcNamespace string } diff --git a/api/server/middleware_auth.go b/api/server/middleware_auth.go index f7528b15b..cdd9825b4 100644 --- a/api/server/middleware_auth.go +++ b/api/server/middleware_auth.go @@ -12,14 +12,14 @@ import ( "github.com/gorilla/mux" "github.com/libopenstorage/openstorage/api" "github.com/libopenstorage/openstorage/pkg/auth" + "github.com/libopenstorage/openstorage/pkg/auth/secrets" osecrets "github.com/libopenstorage/openstorage/pkg/auth/secrets" + "github.com/libopenstorage/openstorage/pkg/util" "github.com/libopenstorage/openstorage/volume" volumedrivers "github.com/libopenstorage/openstorage/volume/drivers" lsecrets "github.com/libopenstorage/secrets" "github.com/portworx/sched-ops/k8s/core" "github.com/sirupsen/logrus" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) const ( @@ -29,6 +29,11 @@ const ( PVCNamespaceLabelKey = "namespace" ) +var ( + // OverrideSchedDriverName is set by osd program to override the schedule driver + OverrideSchedDriverName = "" +) + // NewAuthMiddleware returns a negroni implementation of an http middleware // which will intercept the management APIs func NewAuthMiddleware() *authMiddleware { @@ -150,31 +155,42 @@ func (a *authMiddleware) createWithAuth(w http.ResponseWriter, r *http.Request, spec := dcReq.GetSpec() locator := dcReq.GetLocator() - tokenSecretContext, err := a.parseSecret(spec.VolumeLabels, locator.VolumeLabels, true) + tokenSecretContext, err := a.parseSecret(spec.VolumeLabels, locator.VolumeLabels) if err != nil { a.log(locator.Name, fn).WithError(err).Error("failed to parse secret") dcRes.VolumeResponse = &api.VolumeResponse{Error: "failed to parse secret: " + err.Error()} json.NewEncoder(w).Encode(&dcRes) return - } - if tokenSecretContext.SecretName == "" { - errorMessage := "Access denied, no secret found in the annotations of the persistent volume claim" + - " or storage class parameters" - a.log(locator.Name, fn).Error(errorMessage) - dcRes.VolumeResponse = &api.VolumeResponse{Error: errorMessage} - json.NewEncoder(w).Encode(&dcRes) - w.WriteHeader(http.StatusUnauthorized) - return + } else if tokenSecretContext == nil { + tokenSecretContext = &api.TokenSecretContext{} } - token, err := osecrets.GetToken(tokenSecretContext) - if err != nil { - a.log(locator.Name, fn).WithError(err).Error("failed to get token") - dcRes.VolumeResponse = &api.VolumeResponse{Error: "failed to get token: " + err.Error()} - json.NewEncoder(w).Encode(&dcRes) - return + // If no secret is provided, then the caller is accessing publicly + if tokenSecretContext.SecretName != "" { + token, err := osecrets.GetToken(tokenSecretContext) + if err != nil { + a.log(locator.Name, fn).WithError(err).Error("failed to get token") + dcRes.VolumeResponse = &api.VolumeResponse{Error: "failed to get token: " + err.Error()} + json.NewEncoder(w).Encode(&dcRes) + return + } + + // Save a reference to the secret + // These values will be stored in the header for the create() server handler + // to take and place in the labels for the volume since we do not want to adjust + // the body of the request in this middleware. When create() gets these values + // from the headers, it will copy them to the labels of the volume so that + // we can track the secret in the rest of the middleware calls. + r.Header.Set(secrets.SecretNameKey, tokenSecretContext.SecretName) + r.Header.Set(secrets.SecretNamespaceKey, tokenSecretContext.SecretNamespace) + + // If the source PVC was set, save it for the next layer to store on + // the labels of the volume + if len(tokenSecretContext.PvcName) != 0 && len(tokenSecretContext.PvcNamespace) != 0 { + r.Header.Set(api.KubernetesPvcNameKey, tokenSecretContext.PvcName) + r.Header.Set(api.KubernetesPvcNamespaceKey, tokenSecretContext.PvcNamespace) + } - } else { a.insertToken(r, token) } next(w, r) @@ -195,82 +211,20 @@ func (a *authMiddleware) setWithAuth(w http.ResponseWriter, r *http.Request, nex return } - requestBody := a.getBody(r) - var ( - req api.VolumeSetRequest - resp api.VolumeSetResponse - isOpDone bool - ) - err = json.NewDecoder(requestBody).Decode(&req) + token, err := a.fetchSecretForVolume(d, volumeID) if err != nil { - a.log(volumeID, fn).WithError(err).Error("Failed to parse the request") - next(w, r) + volumeResponse := &api.VolumeResponse{} + a.log(volumeID, fn).WithError(err).Error("Failed to fetch secret") + volumeResponse.Error = err.Error() + json.NewEncoder(w).Encode(volumeResponse) return } - - // Not checking tokens for the following APIs - // - Resize - // - Attach/Detach - // - Mount/Unmount - - if req.Spec != nil && req.Spec.Size > 0 { - isOpDone = true - err = d.Set(volumeID, req.Locator, req.Spec) - } - - for err == nil && req.Action != nil { - if req.Action.Attach != api.VolumeActionParam_VOLUME_ACTION_PARAM_NONE { - isOpDone = true - if req.Action.Attach == api.VolumeActionParam_VOLUME_ACTION_PARAM_ON { - _, err = d.Attach(volumeID, req.Options) - } else { - err = d.Detach(volumeID, req.Options) - } - if err != nil { - break - } - } - - if req.Action.Mount != api.VolumeActionParam_VOLUME_ACTION_PARAM_NONE { - isOpDone = true - if req.Action.Mount == api.VolumeActionParam_VOLUME_ACTION_PARAM_ON { - if req.Action.MountPath == "" { - err = fmt.Errorf("Invalid mount path") - break - } - err = d.Mount(volumeID, req.Action.MountPath, req.Options) - } else { - err = d.Unmount(volumeID, req.Action.MountPath, req.Options) - } - if err != nil { - break - } - } - break + if len(token) != 0 { + a.insertToken(r, token) } - if isOpDone { - if err != nil { - processErrorForVolSetResponse(req.Action, err, &resp) - } else { - v, err := d.Inspect([]string{volumeID}) - if err != nil { - processErrorForVolSetResponse(req.Action, err, &resp) - } else if v == nil || len(v) != 1 { - processErrorForVolSetResponse( - req.Action, - status.Errorf(codes.NotFound, "Volume with ID: %s is not found", volumeID), - &resp) - } else { - v0 := v[0] - resp.Volume = v0 - } - } - json.NewEncoder(w).Encode(resp) - // Not calling the next handler - return - } next(w, r) + } func (a *authMiddleware) deleteWithAuth(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { @@ -288,39 +242,22 @@ func (a *authMiddleware) deleteWithAuth(w http.ResponseWriter, r *http.Request, return } + // Idempotency vols, err := d.Inspect([]string{volumeID}) if err != nil || len(vols) == 0 || vols[0] == nil { - a.log(volumeID, fn).WithError(err).Error("Failed to get volume object") next(w, r) return } - volumeResponse := &api.VolumeResponse{} - tokenSecretContext, err := a.parseSecret(vols[0].Spec.VolumeLabels, vols[0].Locator.VolumeLabels, false) + token, err := a.fetchSecretForVolume(d, volumeID) if err != nil { - a.log(volumeID, fn).WithError(err).Error("failed to parse secret") - volumeResponse.Error = "failed to parse secret: " + err.Error() + volumeResponse := &api.VolumeResponse{} + a.log(volumeID, fn).WithError(err).Error("Failed to fetch secret") + volumeResponse.Error = err.Error() json.NewEncoder(w).Encode(volumeResponse) return } - if tokenSecretContext.SecretName == "" { - errorMessage := fmt.Sprintf("Error, unable to get secret information from the volume."+ - " You may need to re-add the following keys as volume labels to point to the secret: %s and %s", - osecrets.SecretNameKey, osecrets.SecretNamespaceKey) - a.log(volumeID, fn).Error(errorMessage) - volumeResponse = &api.VolumeResponse{Error: errorMessage} - json.NewEncoder(w).Encode(volumeResponse) - w.WriteHeader(http.StatusInternalServerError) - return - } - - token, err := osecrets.GetToken(tokenSecretContext) - if err != nil { - a.log(volumeID, fn).WithError(err).Error("failed to get token") - volumeResponse.Error = "failed to get token: " + err.Error() - json.NewEncoder(w).Encode(volumeResponse) - return - } else { + if len(token) != 0 { a.insertToken(r, token) } @@ -368,39 +305,15 @@ func (a *authMiddleware) enumerateWithAuth(w http.ResponseWriter, r *http.Reques } volumeID := volIDs[0] - vols, err := d.Inspect([]string{volumeID}) - if err != nil || len(vols) == 0 || vols[0] == nil { - a.log(volumeID, fn).WithError(err).Error("Failed to get volume object") - next(w, r) - return - } - - volumeResponse := &api.VolumeResponse{} - tokenSecretContext, err := a.parseSecret(vols[0].Spec.VolumeLabels, vols[0].Locator.VolumeLabels, false) + token, err := a.fetchSecretForVolume(d, volumeID) if err != nil { - a.log(volumeID, fn).WithError(err).Error("failed to parse secret") - volumeResponse.Error = "failed to parse secret: " + err.Error() + volumeResponse := &api.VolumeResponse{} + a.log(volumeID, fn).WithError(err).Error("Failed to fetch secret") + volumeResponse.Error = err.Error() json.NewEncoder(w).Encode(volumeResponse) return } - if tokenSecretContext.SecretName == "" { - errorMessage := fmt.Sprintf("Error, unable to get secret information from the volume."+ - " You may need to re-add the following keys as volume labels to point to the secret: %s and %s", - osecrets.SecretNameKey, osecrets.SecretNamespaceKey) - a.log(volumeID, fn).Error(errorMessage) - volumeResponse = &api.VolumeResponse{Error: errorMessage} - json.NewEncoder(w).Encode(volumeResponse) - w.WriteHeader(http.StatusInternalServerError) - return - } - - token, err := osecrets.GetToken(tokenSecretContext) - if err != nil { - a.log(volumeID, fn).WithError(err).Error("failed to get token") - volumeResponse.Error = "failed to get token: " + err.Error() - json.NewEncoder(w).Encode(volumeResponse) - return - } else { + if len(token) != 0 { a.insertToken(r, token) } @@ -414,7 +327,11 @@ func (a *authMiddleware) isTokenProcessingRequired(r *http.Request) (volume.Volu clientName := strings.Split(userAgent, "/") if len(clientName) > 0 { if strings.HasSuffix(clientName[0], schedDriverPostFix) { - d, err := volumedrivers.Get(clientName[0]) + driverName := clientName[0] + if len(OverrideSchedDriverName) != 0 { + driverName = OverrideSchedDriverName + } + d, err := volumedrivers.Get(driverName) if err != nil { return nil, false } @@ -450,44 +367,83 @@ func (a *authMiddleware) parseParam(r *http.Request, param string) (string, erro return "", fmt.Errorf("could not parse %s", param) } -func (a *authMiddleware) parseSecret( +// This functions makes it possible to secure the model of accessing the secret by allowing +// the definition of secret access to come from the storage class, as done by CSI. +func (a *authMiddleware) getSecretInformationInKubernetes( specLabels, locatorLabels map[string]string, - fetchCOLabels bool, ) (*api.TokenSecretContext, error) { - if lsecrets.Instance().String() == lsecrets.TypeK8s && fetchCOLabels { - // For k8s fetch the actual annotations - pvcName, ok := locatorLabels[PVCNameLabelKey] - if !ok { - // best effort to fetch the secret - return parseSecretFromLabels(specLabels, locatorLabels) - } - pvcNamespace, ok := locatorLabels[PVCNamespaceLabelKey] - if !ok { - // best effort to fetch the secret - return parseSecretFromLabels(specLabels, locatorLabels) - } + // Get pvc location and name + // For k8s fetch the actual annotations + pvcName, ok := getVolumeLabel(PVCNameLabelKey, specLabels, locatorLabels) + if !ok { + return nil, fmt.Errorf("Unable to authenticate request due to not able to determine name of the pvc from the volume") + } + pvcNamespace, ok := getVolumeLabel(PVCNamespaceLabelKey, specLabels, locatorLabels) + if !ok { + return nil, fmt.Errorf("Unable to authenticate request due to not able to determine namespace of the pvc from the volume") + } - pvc, err := core.Instance().GetPersistentVolumeClaim(pvcName, pvcNamespace) - if err != nil { - return nil, err - } - secretName := pvc.ObjectMeta.Annotations[osecrets.SecretNameKey] + // Get pvc object + pvc, err := core.Instance().GetPersistentVolumeClaim(pvcName, pvcNamespace) + if err != nil { + return nil, fmt.Errorf("Unable to get PVC information from Kubernetes: %v", err) + } - if len(secretName) == 0 { - return parseSecretFromLabels(specLabels, locatorLabels) - } - secretNamespace := pvc.ObjectMeta.Annotations[osecrets.SecretNamespaceKey] + // Get storageclass for pvc object + sc, err := core.Instance().GetStorageClassForPVC(pvc) + if err != nil { + return nil, fmt.Errorf("Unable to get StorageClass information from Kubernetes: %v", err) + } + + // Get secret namespace + secretNamespaceValue := sc.Parameters[osecrets.SecretNamespaceKey] + secretNameValue := sc.Parameters[osecrets.SecretNameKey] + if len(secretNameValue) == 0 && len(secretNamespaceValue) == 0 { + return &api.TokenSecretContext{}, nil + } + + // Allow ${pvc.namespace} to be set in the storage class + namespaceParams := map[string]string{"pvc.namespace": pvc.GetNamespace()} + secretNamespace, err := util.ResolveTemplate(secretNamespaceValue, namespaceParams) + if err != nil { + return nil, err + } + + // Get secret name + nameParams := make(map[string]string) + // Allow ${pvc.annotations['pvcNameKey']} to be set in the storage class + // See pkg/auth/secrets/secrets.go for more information + for k, v := range pvc.Annotations { + nameParams["pvc.annotations['"+k+"']"] = v + } + secretName, err := util.ResolveTemplate(secretNameValue, nameParams) + if err != nil { + return nil, err + } + + return &api.TokenSecretContext{ + SecretName: secretName, + SecretNamespace: secretNamespace, + PvcName: pvcName, + PvcNamespace: pvcNamespace, + }, nil +} - return &api.TokenSecretContext{ - SecretName: secretName, - SecretNamespace: secretNamespace, - }, nil +func (a *authMiddleware) parseSecret( + specLabels, locatorLabels map[string]string, +) (*api.TokenSecretContext, error) { + + // Check if it is Kubernetes + if lsecrets.Instance().String() == lsecrets.TypeK8s { + return a.getSecretInformationInKubernetes(specLabels, locatorLabels) } + + // Not Kubernetes, try to get secret information from labels return parseSecretFromLabels(specLabels, locatorLabels) } func parseSecretFromLabels(specLabels, locatorLabels map[string]string) (*api.TokenSecretContext, error) { - // Locator labels take precendence + // Locator labels take precedence secretName := locatorLabels[osecrets.SecretNameKey] secretNamespace := locatorLabels[osecrets.SecretNamespaceKey] if secretName == "" { @@ -524,3 +480,43 @@ func (a *authMiddleware) getBody(r *http.Request) io.ReadCloser { r.Body = rdr2 return rdr1 } + +func getVolumeLabel(key string, specLabels, locatorLabels map[string]string) (string, bool) { + if v, ok := locatorLabels[key]; ok { + return v, true + } + v, ok := specLabels[key] + return v, ok +} + +func (a *authMiddleware) fetchSecretForVolume(d volume.VolumeDriver, id string) (string, error) { + vols, err := d.Inspect([]string{id}) + if err != nil || len(vols) == 0 || vols[0] == nil { + return "", fmt.Errorf("Volume %s does not exist", id) + } + + v := vols[0] + if v.GetLocator().GetVolumeLabels() == nil { + return "", nil + } + + tokenSecretContext := &api.TokenSecretContext{ + SecretName: v.GetLocator().GetVolumeLabels()[secrets.SecretNameKey], + SecretNamespace: v.GetLocator().GetVolumeLabels()[secrets.SecretNamespaceKey], + } + + // If no secret is provided, then the caller is accessing publicly + if tokenSecretContext.SecretName == "" || tokenSecretContext.SecretNamespace == "" { + return "", nil + } + + // Retrieve secret + token, err := osecrets.GetToken(tokenSecretContext) + if err != nil { + return "", fmt.Errorf("Failed to get token from secret %s/%s: %v", + tokenSecretContext.SecretNamespace, + tokenSecretContext.SecretName, + err) + } + return token, nil +} diff --git a/api/server/mock/mock_schedops_k8s.go b/api/server/mock/mock_schedops_k8s.go new file mode 100644 index 000000000..3e0a4b11f --- /dev/null +++ b/api/server/mock/mock_schedops_k8s.go @@ -0,0 +1,1388 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/portworx/sched-ops/k8s/core (interfaces: Ops) + +// Package mock is a generated GoMock package. +package mock + +import ( + gomock "github.com/golang/mock/gomock" + core "github.com/portworx/sched-ops/k8s/core" + v1 "k8s.io/api/core/v1" + v10 "k8s.io/api/storage/v1" + v11 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + version "k8s.io/apimachinery/pkg/version" + rest "k8s.io/client-go/rest" + reflect "reflect" + time "time" +) + +// MockOps is a mock of Ops interface +type MockOps struct { + ctrl *gomock.Controller + recorder *MockOpsMockRecorder +} + +// MockOpsMockRecorder is the mock recorder for MockOps +type MockOpsMockRecorder struct { + mock *MockOps +} + +// NewMockOps creates a new mock instance +func NewMockOps(ctrl *gomock.Controller) *MockOps { + mock := &MockOps{ctrl: ctrl} + mock.recorder = &MockOpsMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockOps) EXPECT() *MockOpsMockRecorder { + return m.recorder +} + +// AddLabelOnNode mocks base method +func (m *MockOps) AddLabelOnNode(arg0, arg1, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddLabelOnNode", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddLabelOnNode indicates an expected call of AddLabelOnNode +func (mr *MockOpsMockRecorder) AddLabelOnNode(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddLabelOnNode", reflect.TypeOf((*MockOps)(nil).AddLabelOnNode), arg0, arg1, arg2) +} + +// CordonNode mocks base method +func (m *MockOps) CordonNode(arg0 string, arg1, arg2 time.Duration) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CordonNode", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// CordonNode indicates an expected call of CordonNode +func (mr *MockOpsMockRecorder) CordonNode(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CordonNode", reflect.TypeOf((*MockOps)(nil).CordonNode), arg0, arg1, arg2) +} + +// CreateConfigMap mocks base method +func (m *MockOps) CreateConfigMap(arg0 *v1.ConfigMap) (*v1.ConfigMap, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateConfigMap", arg0) + ret0, _ := ret[0].(*v1.ConfigMap) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateConfigMap indicates an expected call of CreateConfigMap +func (mr *MockOpsMockRecorder) CreateConfigMap(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateConfigMap", reflect.TypeOf((*MockOps)(nil).CreateConfigMap), arg0) +} + +// CreateEndpoints mocks base method +func (m *MockOps) CreateEndpoints(arg0 *v1.Endpoints) (*v1.Endpoints, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateEndpoints", arg0) + ret0, _ := ret[0].(*v1.Endpoints) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateEndpoints indicates an expected call of CreateEndpoints +func (mr *MockOpsMockRecorder) CreateEndpoints(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEndpoints", reflect.TypeOf((*MockOps)(nil).CreateEndpoints), arg0) +} + +// CreateEvent mocks base method +func (m *MockOps) CreateEvent(arg0 *v1.Event) (*v1.Event, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateEvent", arg0) + ret0, _ := ret[0].(*v1.Event) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateEvent indicates an expected call of CreateEvent +func (mr *MockOpsMockRecorder) CreateEvent(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEvent", reflect.TypeOf((*MockOps)(nil).CreateEvent), arg0) +} + +// CreateNamespace mocks base method +func (m *MockOps) CreateNamespace(arg0 string, arg1 map[string]string) (*v1.Namespace, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateNamespace", arg0, arg1) + ret0, _ := ret[0].(*v1.Namespace) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateNamespace indicates an expected call of CreateNamespace +func (mr *MockOpsMockRecorder) CreateNamespace(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNamespace", reflect.TypeOf((*MockOps)(nil).CreateNamespace), arg0, arg1) +} + +// CreateNode mocks base method +func (m *MockOps) CreateNode(arg0 *v1.Node) (*v1.Node, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateNode", arg0) + ret0, _ := ret[0].(*v1.Node) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateNode indicates an expected call of CreateNode +func (mr *MockOpsMockRecorder) CreateNode(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNode", reflect.TypeOf((*MockOps)(nil).CreateNode), arg0) +} + +// CreatePersistentVolume mocks base method +func (m *MockOps) CreatePersistentVolume(arg0 *v1.PersistentVolume) (*v1.PersistentVolume, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatePersistentVolume", arg0) + ret0, _ := ret[0].(*v1.PersistentVolume) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreatePersistentVolume indicates an expected call of CreatePersistentVolume +func (mr *MockOpsMockRecorder) CreatePersistentVolume(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePersistentVolume", reflect.TypeOf((*MockOps)(nil).CreatePersistentVolume), arg0) +} + +// CreatePersistentVolumeClaim mocks base method +func (m *MockOps) CreatePersistentVolumeClaim(arg0 *v1.PersistentVolumeClaim) (*v1.PersistentVolumeClaim, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatePersistentVolumeClaim", arg0) + ret0, _ := ret[0].(*v1.PersistentVolumeClaim) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreatePersistentVolumeClaim indicates an expected call of CreatePersistentVolumeClaim +func (mr *MockOpsMockRecorder) CreatePersistentVolumeClaim(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePersistentVolumeClaim", reflect.TypeOf((*MockOps)(nil).CreatePersistentVolumeClaim), arg0) +} + +// CreatePod mocks base method +func (m *MockOps) CreatePod(arg0 *v1.Pod) (*v1.Pod, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatePod", arg0) + ret0, _ := ret[0].(*v1.Pod) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreatePod indicates an expected call of CreatePod +func (mr *MockOpsMockRecorder) CreatePod(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePod", reflect.TypeOf((*MockOps)(nil).CreatePod), arg0) +} + +// CreateSecret mocks base method +func (m *MockOps) CreateSecret(arg0 *v1.Secret) (*v1.Secret, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateSecret", arg0) + ret0, _ := ret[0].(*v1.Secret) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateSecret indicates an expected call of CreateSecret +func (mr *MockOpsMockRecorder) CreateSecret(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSecret", reflect.TypeOf((*MockOps)(nil).CreateSecret), arg0) +} + +// CreateService mocks base method +func (m *MockOps) CreateService(arg0 *v1.Service) (*v1.Service, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateService", arg0) + ret0, _ := ret[0].(*v1.Service) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateService indicates an expected call of CreateService +func (mr *MockOpsMockRecorder) CreateService(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateService", reflect.TypeOf((*MockOps)(nil).CreateService), arg0) +} + +// CreateServiceAccount mocks base method +func (m *MockOps) CreateServiceAccount(arg0 *v1.ServiceAccount) (*v1.ServiceAccount, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateServiceAccount", arg0) + ret0, _ := ret[0].(*v1.ServiceAccount) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateServiceAccount indicates an expected call of CreateServiceAccount +func (mr *MockOpsMockRecorder) CreateServiceAccount(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateServiceAccount", reflect.TypeOf((*MockOps)(nil).CreateServiceAccount), arg0) +} + +// DeleteConfigMap mocks base method +func (m *MockOps) DeleteConfigMap(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteConfigMap", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteConfigMap indicates an expected call of DeleteConfigMap +func (mr *MockOpsMockRecorder) DeleteConfigMap(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteConfigMap", reflect.TypeOf((*MockOps)(nil).DeleteConfigMap), arg0, arg1) +} + +// DeleteEndpoints mocks base method +func (m *MockOps) DeleteEndpoints(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteEndpoints", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteEndpoints indicates an expected call of DeleteEndpoints +func (mr *MockOpsMockRecorder) DeleteEndpoints(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEndpoints", reflect.TypeOf((*MockOps)(nil).DeleteEndpoints), arg0, arg1) +} + +// DeleteNamespace mocks base method +func (m *MockOps) DeleteNamespace(arg0 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteNamespace", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteNamespace indicates an expected call of DeleteNamespace +func (mr *MockOpsMockRecorder) DeleteNamespace(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteNamespace", reflect.TypeOf((*MockOps)(nil).DeleteNamespace), arg0) +} + +// DeletePersistentVolume mocks base method +func (m *MockOps) DeletePersistentVolume(arg0 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeletePersistentVolume", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeletePersistentVolume indicates an expected call of DeletePersistentVolume +func (mr *MockOpsMockRecorder) DeletePersistentVolume(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePersistentVolume", reflect.TypeOf((*MockOps)(nil).DeletePersistentVolume), arg0) +} + +// DeletePersistentVolumeClaim mocks base method +func (m *MockOps) DeletePersistentVolumeClaim(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeletePersistentVolumeClaim", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeletePersistentVolumeClaim indicates an expected call of DeletePersistentVolumeClaim +func (mr *MockOpsMockRecorder) DeletePersistentVolumeClaim(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePersistentVolumeClaim", reflect.TypeOf((*MockOps)(nil).DeletePersistentVolumeClaim), arg0, arg1) +} + +// DeletePod mocks base method +func (m *MockOps) DeletePod(arg0, arg1 string, arg2 bool) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeletePod", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeletePod indicates an expected call of DeletePod +func (mr *MockOpsMockRecorder) DeletePod(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePod", reflect.TypeOf((*MockOps)(nil).DeletePod), arg0, arg1, arg2) +} + +// DeletePods mocks base method +func (m *MockOps) DeletePods(arg0 []v1.Pod, arg1 bool) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeletePods", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeletePods indicates an expected call of DeletePods +func (mr *MockOpsMockRecorder) DeletePods(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePods", reflect.TypeOf((*MockOps)(nil).DeletePods), arg0, arg1) +} + +// DeleteSecret mocks base method +func (m *MockOps) DeleteSecret(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteSecret", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteSecret indicates an expected call of DeleteSecret +func (mr *MockOpsMockRecorder) DeleteSecret(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSecret", reflect.TypeOf((*MockOps)(nil).DeleteSecret), arg0, arg1) +} + +// DeleteService mocks base method +func (m *MockOps) DeleteService(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteService", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteService indicates an expected call of DeleteService +func (mr *MockOpsMockRecorder) DeleteService(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteService", reflect.TypeOf((*MockOps)(nil).DeleteService), arg0, arg1) +} + +// DeleteServiceAccount mocks base method +func (m *MockOps) DeleteServiceAccount(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteServiceAccount", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteServiceAccount indicates an expected call of DeleteServiceAccount +func (mr *MockOpsMockRecorder) DeleteServiceAccount(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteServiceAccount", reflect.TypeOf((*MockOps)(nil).DeleteServiceAccount), arg0, arg1) +} + +// DescribeService mocks base method +func (m *MockOps) DescribeService(arg0, arg1 string) (*v1.ServiceStatus, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DescribeService", arg0, arg1) + ret0, _ := ret[0].(*v1.ServiceStatus) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DescribeService indicates an expected call of DescribeService +func (mr *MockOpsMockRecorder) DescribeService(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeService", reflect.TypeOf((*MockOps)(nil).DescribeService), arg0, arg1) +} + +// DrainPodsFromNode mocks base method +func (m *MockOps) DrainPodsFromNode(arg0 string, arg1 []v1.Pod, arg2, arg3 time.Duration) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DrainPodsFromNode", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(error) + return ret0 +} + +// DrainPodsFromNode indicates an expected call of DrainPodsFromNode +func (mr *MockOpsMockRecorder) DrainPodsFromNode(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DrainPodsFromNode", reflect.TypeOf((*MockOps)(nil).DrainPodsFromNode), arg0, arg1, arg2, arg3) +} + +// FindMyNode mocks base method +func (m *MockOps) FindMyNode() (*v1.Node, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindMyNode") + ret0, _ := ret[0].(*v1.Node) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindMyNode indicates an expected call of FindMyNode +func (mr *MockOpsMockRecorder) FindMyNode() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindMyNode", reflect.TypeOf((*MockOps)(nil).FindMyNode)) +} + +// GetConfigMap mocks base method +func (m *MockOps) GetConfigMap(arg0, arg1 string) (*v1.ConfigMap, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetConfigMap", arg0, arg1) + ret0, _ := ret[0].(*v1.ConfigMap) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetConfigMap indicates an expected call of GetConfigMap +func (mr *MockOpsMockRecorder) GetConfigMap(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConfigMap", reflect.TypeOf((*MockOps)(nil).GetConfigMap), arg0, arg1) +} + +// GetEndpoints mocks base method +func (m *MockOps) GetEndpoints(arg0, arg1 string) (*v1.Endpoints, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEndpoints", arg0, arg1) + ret0, _ := ret[0].(*v1.Endpoints) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetEndpoints indicates an expected call of GetEndpoints +func (mr *MockOpsMockRecorder) GetEndpoints(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEndpoints", reflect.TypeOf((*MockOps)(nil).GetEndpoints), arg0, arg1) +} + +// GetLabelsOnNode mocks base method +func (m *MockOps) GetLabelsOnNode(arg0 string) (map[string]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLabelsOnNode", arg0) + ret0, _ := ret[0].(map[string]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLabelsOnNode indicates an expected call of GetLabelsOnNode +func (mr *MockOpsMockRecorder) GetLabelsOnNode(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLabelsOnNode", reflect.TypeOf((*MockOps)(nil).GetLabelsOnNode), arg0) +} + +// GetNamespace mocks base method +func (m *MockOps) GetNamespace(arg0 string) (*v1.Namespace, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetNamespace", arg0) + ret0, _ := ret[0].(*v1.Namespace) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetNamespace indicates an expected call of GetNamespace +func (mr *MockOpsMockRecorder) GetNamespace(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNamespace", reflect.TypeOf((*MockOps)(nil).GetNamespace), arg0) +} + +// GetNodeByName mocks base method +func (m *MockOps) GetNodeByName(arg0 string) (*v1.Node, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetNodeByName", arg0) + ret0, _ := ret[0].(*v1.Node) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetNodeByName indicates an expected call of GetNodeByName +func (mr *MockOpsMockRecorder) GetNodeByName(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNodeByName", reflect.TypeOf((*MockOps)(nil).GetNodeByName), arg0) +} + +// GetNodes mocks base method +func (m *MockOps) GetNodes() (*v1.NodeList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetNodes") + ret0, _ := ret[0].(*v1.NodeList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetNodes indicates an expected call of GetNodes +func (mr *MockOpsMockRecorder) GetNodes() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNodes", reflect.TypeOf((*MockOps)(nil).GetNodes)) +} + +// GetPVCsUsingStorageClass mocks base method +func (m *MockOps) GetPVCsUsingStorageClass(arg0 string) ([]v1.PersistentVolumeClaim, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPVCsUsingStorageClass", arg0) + ret0, _ := ret[0].([]v1.PersistentVolumeClaim) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPVCsUsingStorageClass indicates an expected call of GetPVCsUsingStorageClass +func (mr *MockOpsMockRecorder) GetPVCsUsingStorageClass(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPVCsUsingStorageClass", reflect.TypeOf((*MockOps)(nil).GetPVCsUsingStorageClass), arg0) +} + +// GetPersistentVolume mocks base method +func (m *MockOps) GetPersistentVolume(arg0 string) (*v1.PersistentVolume, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPersistentVolume", arg0) + ret0, _ := ret[0].(*v1.PersistentVolume) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPersistentVolume indicates an expected call of GetPersistentVolume +func (mr *MockOpsMockRecorder) GetPersistentVolume(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPersistentVolume", reflect.TypeOf((*MockOps)(nil).GetPersistentVolume), arg0) +} + +// GetPersistentVolumeClaim mocks base method +func (m *MockOps) GetPersistentVolumeClaim(arg0, arg1 string) (*v1.PersistentVolumeClaim, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPersistentVolumeClaim", arg0, arg1) + ret0, _ := ret[0].(*v1.PersistentVolumeClaim) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPersistentVolumeClaim indicates an expected call of GetPersistentVolumeClaim +func (mr *MockOpsMockRecorder) GetPersistentVolumeClaim(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPersistentVolumeClaim", reflect.TypeOf((*MockOps)(nil).GetPersistentVolumeClaim), arg0, arg1) +} + +// GetPersistentVolumeClaimParams mocks base method +func (m *MockOps) GetPersistentVolumeClaimParams(arg0 *v1.PersistentVolumeClaim) (map[string]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPersistentVolumeClaimParams", arg0) + ret0, _ := ret[0].(map[string]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPersistentVolumeClaimParams indicates an expected call of GetPersistentVolumeClaimParams +func (mr *MockOpsMockRecorder) GetPersistentVolumeClaimParams(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPersistentVolumeClaimParams", reflect.TypeOf((*MockOps)(nil).GetPersistentVolumeClaimParams), arg0) +} + +// GetPersistentVolumeClaimStatus mocks base method +func (m *MockOps) GetPersistentVolumeClaimStatus(arg0 *v1.PersistentVolumeClaim) (*v1.PersistentVolumeClaimStatus, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPersistentVolumeClaimStatus", arg0) + ret0, _ := ret[0].(*v1.PersistentVolumeClaimStatus) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPersistentVolumeClaimStatus indicates an expected call of GetPersistentVolumeClaimStatus +func (mr *MockOpsMockRecorder) GetPersistentVolumeClaimStatus(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPersistentVolumeClaimStatus", reflect.TypeOf((*MockOps)(nil).GetPersistentVolumeClaimStatus), arg0) +} + +// GetPersistentVolumeClaims mocks base method +func (m *MockOps) GetPersistentVolumeClaims(arg0 string, arg1 map[string]string) (*v1.PersistentVolumeClaimList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPersistentVolumeClaims", arg0, arg1) + ret0, _ := ret[0].(*v1.PersistentVolumeClaimList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPersistentVolumeClaims indicates an expected call of GetPersistentVolumeClaims +func (mr *MockOpsMockRecorder) GetPersistentVolumeClaims(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPersistentVolumeClaims", reflect.TypeOf((*MockOps)(nil).GetPersistentVolumeClaims), arg0, arg1) +} + +// GetPersistentVolumes mocks base method +func (m *MockOps) GetPersistentVolumes() (*v1.PersistentVolumeList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPersistentVolumes") + ret0, _ := ret[0].(*v1.PersistentVolumeList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPersistentVolumes indicates an expected call of GetPersistentVolumes +func (mr *MockOpsMockRecorder) GetPersistentVolumes() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPersistentVolumes", reflect.TypeOf((*MockOps)(nil).GetPersistentVolumes)) +} + +// GetPodByName mocks base method +func (m *MockOps) GetPodByName(arg0, arg1 string) (*v1.Pod, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPodByName", arg0, arg1) + ret0, _ := ret[0].(*v1.Pod) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPodByName indicates an expected call of GetPodByName +func (mr *MockOpsMockRecorder) GetPodByName(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodByName", reflect.TypeOf((*MockOps)(nil).GetPodByName), arg0, arg1) +} + +// GetPodByUID mocks base method +func (m *MockOps) GetPodByUID(arg0 types.UID, arg1 string) (*v1.Pod, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPodByUID", arg0, arg1) + ret0, _ := ret[0].(*v1.Pod) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPodByUID indicates an expected call of GetPodByUID +func (mr *MockOpsMockRecorder) GetPodByUID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodByUID", reflect.TypeOf((*MockOps)(nil).GetPodByUID), arg0, arg1) +} + +// GetPods mocks base method +func (m *MockOps) GetPods(arg0 string, arg1 map[string]string) (*v1.PodList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPods", arg0, arg1) + ret0, _ := ret[0].(*v1.PodList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPods indicates an expected call of GetPods +func (mr *MockOpsMockRecorder) GetPods(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPods", reflect.TypeOf((*MockOps)(nil).GetPods), arg0, arg1) +} + +// GetPodsByNode mocks base method +func (m *MockOps) GetPodsByNode(arg0, arg1 string) (*v1.PodList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPodsByNode", arg0, arg1) + ret0, _ := ret[0].(*v1.PodList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPodsByNode indicates an expected call of GetPodsByNode +func (mr *MockOpsMockRecorder) GetPodsByNode(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodsByNode", reflect.TypeOf((*MockOps)(nil).GetPodsByNode), arg0, arg1) +} + +// GetPodsByNodeAndLabels mocks base method +func (m *MockOps) GetPodsByNodeAndLabels(arg0, arg1 string, arg2 map[string]string) (*v1.PodList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPodsByNodeAndLabels", arg0, arg1, arg2) + ret0, _ := ret[0].(*v1.PodList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPodsByNodeAndLabels indicates an expected call of GetPodsByNodeAndLabels +func (mr *MockOpsMockRecorder) GetPodsByNodeAndLabels(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodsByNodeAndLabels", reflect.TypeOf((*MockOps)(nil).GetPodsByNodeAndLabels), arg0, arg1, arg2) +} + +// GetPodsByOwner mocks base method +func (m *MockOps) GetPodsByOwner(arg0 types.UID, arg1 string) ([]v1.Pod, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPodsByOwner", arg0, arg1) + ret0, _ := ret[0].([]v1.Pod) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPodsByOwner indicates an expected call of GetPodsByOwner +func (mr *MockOpsMockRecorder) GetPodsByOwner(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodsByOwner", reflect.TypeOf((*MockOps)(nil).GetPodsByOwner), arg0, arg1) +} + +// GetPodsUsingPV mocks base method +func (m *MockOps) GetPodsUsingPV(arg0 string) ([]v1.Pod, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPodsUsingPV", arg0) + ret0, _ := ret[0].([]v1.Pod) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPodsUsingPV indicates an expected call of GetPodsUsingPV +func (mr *MockOpsMockRecorder) GetPodsUsingPV(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodsUsingPV", reflect.TypeOf((*MockOps)(nil).GetPodsUsingPV), arg0) +} + +// GetPodsUsingPVByNodeName mocks base method +func (m *MockOps) GetPodsUsingPVByNodeName(arg0, arg1 string) ([]v1.Pod, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPodsUsingPVByNodeName", arg0, arg1) + ret0, _ := ret[0].([]v1.Pod) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPodsUsingPVByNodeName indicates an expected call of GetPodsUsingPVByNodeName +func (mr *MockOpsMockRecorder) GetPodsUsingPVByNodeName(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodsUsingPVByNodeName", reflect.TypeOf((*MockOps)(nil).GetPodsUsingPVByNodeName), arg0, arg1) +} + +// GetPodsUsingPVC mocks base method +func (m *MockOps) GetPodsUsingPVC(arg0, arg1 string) ([]v1.Pod, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPodsUsingPVC", arg0, arg1) + ret0, _ := ret[0].([]v1.Pod) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPodsUsingPVC indicates an expected call of GetPodsUsingPVC +func (mr *MockOpsMockRecorder) GetPodsUsingPVC(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodsUsingPVC", reflect.TypeOf((*MockOps)(nil).GetPodsUsingPVC), arg0, arg1) +} + +// GetPodsUsingPVCByNodeName mocks base method +func (m *MockOps) GetPodsUsingPVCByNodeName(arg0, arg1, arg2 string) ([]v1.Pod, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPodsUsingPVCByNodeName", arg0, arg1, arg2) + ret0, _ := ret[0].([]v1.Pod) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPodsUsingPVCByNodeName indicates an expected call of GetPodsUsingPVCByNodeName +func (mr *MockOpsMockRecorder) GetPodsUsingPVCByNodeName(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodsUsingPVCByNodeName", reflect.TypeOf((*MockOps)(nil).GetPodsUsingPVCByNodeName), arg0, arg1, arg2) +} + +// GetPodsUsingVolumePlugin mocks base method +func (m *MockOps) GetPodsUsingVolumePlugin(arg0 string) ([]v1.Pod, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPodsUsingVolumePlugin", arg0) + ret0, _ := ret[0].([]v1.Pod) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPodsUsingVolumePlugin indicates an expected call of GetPodsUsingVolumePlugin +func (mr *MockOpsMockRecorder) GetPodsUsingVolumePlugin(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodsUsingVolumePlugin", reflect.TypeOf((*MockOps)(nil).GetPodsUsingVolumePlugin), arg0) +} + +// GetPodsUsingVolumePluginByNodeName mocks base method +func (m *MockOps) GetPodsUsingVolumePluginByNodeName(arg0, arg1 string) ([]v1.Pod, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPodsUsingVolumePluginByNodeName", arg0, arg1) + ret0, _ := ret[0].([]v1.Pod) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPodsUsingVolumePluginByNodeName indicates an expected call of GetPodsUsingVolumePluginByNodeName +func (mr *MockOpsMockRecorder) GetPodsUsingVolumePluginByNodeName(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPodsUsingVolumePluginByNodeName", reflect.TypeOf((*MockOps)(nil).GetPodsUsingVolumePluginByNodeName), arg0, arg1) +} + +// GetSecret mocks base method +func (m *MockOps) GetSecret(arg0, arg1 string) (*v1.Secret, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSecret", arg0, arg1) + ret0, _ := ret[0].(*v1.Secret) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetSecret indicates an expected call of GetSecret +func (mr *MockOpsMockRecorder) GetSecret(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSecret", reflect.TypeOf((*MockOps)(nil).GetSecret), arg0, arg1) +} + +// GetService mocks base method +func (m *MockOps) GetService(arg0, arg1 string) (*v1.Service, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetService", arg0, arg1) + ret0, _ := ret[0].(*v1.Service) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetService indicates an expected call of GetService +func (mr *MockOpsMockRecorder) GetService(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetService", reflect.TypeOf((*MockOps)(nil).GetService), arg0, arg1) +} + +// GetServiceAccount mocks base method +func (m *MockOps) GetServiceAccount(arg0, arg1 string) (*v1.ServiceAccount, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetServiceAccount", arg0, arg1) + ret0, _ := ret[0].(*v1.ServiceAccount) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetServiceAccount indicates an expected call of GetServiceAccount +func (mr *MockOpsMockRecorder) GetServiceAccount(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceAccount", reflect.TypeOf((*MockOps)(nil).GetServiceAccount), arg0, arg1) +} + +// GetServiceEndpoint mocks base method +func (m *MockOps) GetServiceEndpoint(arg0, arg1 string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetServiceEndpoint", arg0, arg1) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetServiceEndpoint indicates an expected call of GetServiceEndpoint +func (mr *MockOpsMockRecorder) GetServiceEndpoint(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceEndpoint", reflect.TypeOf((*MockOps)(nil).GetServiceEndpoint), arg0, arg1) +} + +// GetStorageClassForPVC mocks base method +func (m *MockOps) GetStorageClassForPVC(arg0 *v1.PersistentVolumeClaim) (*v10.StorageClass, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetStorageClassForPVC", arg0) + ret0, _ := ret[0].(*v10.StorageClass) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetStorageClassForPVC indicates an expected call of GetStorageClassForPVC +func (mr *MockOpsMockRecorder) GetStorageClassForPVC(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStorageClassForPVC", reflect.TypeOf((*MockOps)(nil).GetStorageClassForPVC), arg0) +} + +// GetStorageProvisionerForPVC mocks base method +func (m *MockOps) GetStorageProvisionerForPVC(arg0 *v1.PersistentVolumeClaim) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetStorageProvisionerForPVC", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetStorageProvisionerForPVC indicates an expected call of GetStorageProvisionerForPVC +func (mr *MockOpsMockRecorder) GetStorageProvisionerForPVC(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStorageProvisionerForPVC", reflect.TypeOf((*MockOps)(nil).GetStorageProvisionerForPVC), arg0) +} + +// GetVersion mocks base method +func (m *MockOps) GetVersion() (*version.Info, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetVersion") + ret0, _ := ret[0].(*version.Info) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetVersion indicates an expected call of GetVersion +func (mr *MockOpsMockRecorder) GetVersion() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVersion", reflect.TypeOf((*MockOps)(nil).GetVersion)) +} + +// GetVolumeForPersistentVolumeClaim mocks base method +func (m *MockOps) GetVolumeForPersistentVolumeClaim(arg0 *v1.PersistentVolumeClaim) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetVolumeForPersistentVolumeClaim", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetVolumeForPersistentVolumeClaim indicates an expected call of GetVolumeForPersistentVolumeClaim +func (mr *MockOpsMockRecorder) GetVolumeForPersistentVolumeClaim(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVolumeForPersistentVolumeClaim", reflect.TypeOf((*MockOps)(nil).GetVolumeForPersistentVolumeClaim), arg0) +} + +// IsNodeMaster mocks base method +func (m *MockOps) IsNodeMaster(arg0 v1.Node) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsNodeMaster", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsNodeMaster indicates an expected call of IsNodeMaster +func (mr *MockOpsMockRecorder) IsNodeMaster(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsNodeMaster", reflect.TypeOf((*MockOps)(nil).IsNodeMaster), arg0) +} + +// IsNodeReady mocks base method +func (m *MockOps) IsNodeReady(arg0 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsNodeReady", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// IsNodeReady indicates an expected call of IsNodeReady +func (mr *MockOpsMockRecorder) IsNodeReady(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsNodeReady", reflect.TypeOf((*MockOps)(nil).IsNodeReady), arg0) +} + +// IsPodBeingManaged mocks base method +func (m *MockOps) IsPodBeingManaged(arg0 v1.Pod) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsPodBeingManaged", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsPodBeingManaged indicates an expected call of IsPodBeingManaged +func (mr *MockOpsMockRecorder) IsPodBeingManaged(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsPodBeingManaged", reflect.TypeOf((*MockOps)(nil).IsPodBeingManaged), arg0) +} + +// IsPodReady mocks base method +func (m *MockOps) IsPodReady(arg0 v1.Pod) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsPodReady", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsPodReady indicates an expected call of IsPodReady +func (mr *MockOpsMockRecorder) IsPodReady(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsPodReady", reflect.TypeOf((*MockOps)(nil).IsPodReady), arg0) +} + +// IsPodRunning mocks base method +func (m *MockOps) IsPodRunning(arg0 v1.Pod) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsPodRunning", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsPodRunning indicates an expected call of IsPodRunning +func (mr *MockOpsMockRecorder) IsPodRunning(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsPodRunning", reflect.TypeOf((*MockOps)(nil).IsPodRunning), arg0) +} + +// ListEvents mocks base method +func (m *MockOps) ListEvents(arg0 string, arg1 v11.ListOptions) (*v1.EventList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListEvents", arg0, arg1) + ret0, _ := ret[0].(*v1.EventList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListEvents indicates an expected call of ListEvents +func (mr *MockOpsMockRecorder) ListEvents(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListEvents", reflect.TypeOf((*MockOps)(nil).ListEvents), arg0, arg1) +} + +// ListNamespaces mocks base method +func (m *MockOps) ListNamespaces(arg0 map[string]string) (*v1.NamespaceList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListNamespaces", arg0) + ret0, _ := ret[0].(*v1.NamespaceList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListNamespaces indicates an expected call of ListNamespaces +func (mr *MockOpsMockRecorder) ListNamespaces(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListNamespaces", reflect.TypeOf((*MockOps)(nil).ListNamespaces), arg0) +} + +// ListServices mocks base method +func (m *MockOps) ListServices(arg0 string, arg1 v11.ListOptions) (*v1.ServiceList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListServices", arg0, arg1) + ret0, _ := ret[0].(*v1.ServiceList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListServices indicates an expected call of ListServices +func (mr *MockOpsMockRecorder) ListServices(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*MockOps)(nil).ListServices), arg0, arg1) +} + +// PatchEndpoints mocks base method +func (m *MockOps) PatchEndpoints(arg0, arg1 string, arg2 types.PatchType, arg3 []byte) (*v1.Endpoints, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PatchEndpoints", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*v1.Endpoints) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PatchEndpoints indicates an expected call of PatchEndpoints +func (mr *MockOpsMockRecorder) PatchEndpoints(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PatchEndpoints", reflect.TypeOf((*MockOps)(nil).PatchEndpoints), arg0, arg1, arg2, arg3) +} + +// PatchService mocks base method +func (m *MockOps) PatchService(arg0, arg1 string, arg2 []byte) (*v1.Service, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PatchService", arg0, arg1, arg2) + ret0, _ := ret[0].(*v1.Service) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PatchService indicates an expected call of PatchService +func (mr *MockOpsMockRecorder) PatchService(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PatchService", reflect.TypeOf((*MockOps)(nil).PatchService), arg0, arg1, arg2) +} + +// RecordEvent mocks base method +func (m *MockOps) RecordEvent(arg0 v1.EventSource, arg1 runtime.Object, arg2, arg3, arg4 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RecordEvent", arg0, arg1, arg2, arg3, arg4) +} + +// RecordEvent indicates an expected call of RecordEvent +func (mr *MockOpsMockRecorder) RecordEvent(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordEvent", reflect.TypeOf((*MockOps)(nil).RecordEvent), arg0, arg1, arg2, arg3, arg4) +} + +// RemoveLabelOnNode mocks base method +func (m *MockOps) RemoveLabelOnNode(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveLabelOnNode", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveLabelOnNode indicates an expected call of RemoveLabelOnNode +func (mr *MockOpsMockRecorder) RemoveLabelOnNode(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveLabelOnNode", reflect.TypeOf((*MockOps)(nil).RemoveLabelOnNode), arg0, arg1) +} + +// ResourceExists mocks base method +func (m *MockOps) ResourceExists(arg0 schema.GroupVersionKind) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ResourceExists", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ResourceExists indicates an expected call of ResourceExists +func (mr *MockOpsMockRecorder) ResourceExists(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResourceExists", reflect.TypeOf((*MockOps)(nil).ResourceExists), arg0) +} + +// RunCommandInPod mocks base method +func (m *MockOps) RunCommandInPod(arg0 []string, arg1, arg2, arg3 string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RunCommandInPod", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RunCommandInPod indicates an expected call of RunCommandInPod +func (mr *MockOpsMockRecorder) RunCommandInPod(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunCommandInPod", reflect.TypeOf((*MockOps)(nil).RunCommandInPod), arg0, arg1, arg2, arg3) +} + +// SearchNodeByAddresses mocks base method +func (m *MockOps) SearchNodeByAddresses(arg0 []string) (*v1.Node, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchNodeByAddresses", arg0) + ret0, _ := ret[0].(*v1.Node) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchNodeByAddresses indicates an expected call of SearchNodeByAddresses +func (mr *MockOpsMockRecorder) SearchNodeByAddresses(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchNodeByAddresses", reflect.TypeOf((*MockOps)(nil).SearchNodeByAddresses), arg0) +} + +// SetConfig mocks base method +func (m *MockOps) SetConfig(arg0 *rest.Config) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetConfig", arg0) +} + +// SetConfig indicates an expected call of SetConfig +func (mr *MockOpsMockRecorder) SetConfig(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConfig", reflect.TypeOf((*MockOps)(nil).SetConfig), arg0) +} + +// UnCordonNode mocks base method +func (m *MockOps) UnCordonNode(arg0 string, arg1, arg2 time.Duration) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UnCordonNode", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// UnCordonNode indicates an expected call of UnCordonNode +func (mr *MockOpsMockRecorder) UnCordonNode(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnCordonNode", reflect.TypeOf((*MockOps)(nil).UnCordonNode), arg0, arg1, arg2) +} + +// UpdateConfigMap mocks base method +func (m *MockOps) UpdateConfigMap(arg0 *v1.ConfigMap) (*v1.ConfigMap, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateConfigMap", arg0) + ret0, _ := ret[0].(*v1.ConfigMap) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateConfigMap indicates an expected call of UpdateConfigMap +func (mr *MockOpsMockRecorder) UpdateConfigMap(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateConfigMap", reflect.TypeOf((*MockOps)(nil).UpdateConfigMap), arg0) +} + +// UpdateNode mocks base method +func (m *MockOps) UpdateNode(arg0 *v1.Node) (*v1.Node, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateNode", arg0) + ret0, _ := ret[0].(*v1.Node) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateNode indicates an expected call of UpdateNode +func (mr *MockOpsMockRecorder) UpdateNode(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateNode", reflect.TypeOf((*MockOps)(nil).UpdateNode), arg0) +} + +// UpdatePersistentVolumeClaim mocks base method +func (m *MockOps) UpdatePersistentVolumeClaim(arg0 *v1.PersistentVolumeClaim) (*v1.PersistentVolumeClaim, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatePersistentVolumeClaim", arg0) + ret0, _ := ret[0].(*v1.PersistentVolumeClaim) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdatePersistentVolumeClaim indicates an expected call of UpdatePersistentVolumeClaim +func (mr *MockOpsMockRecorder) UpdatePersistentVolumeClaim(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePersistentVolumeClaim", reflect.TypeOf((*MockOps)(nil).UpdatePersistentVolumeClaim), arg0) +} + +// UpdatePod mocks base method +func (m *MockOps) UpdatePod(arg0 *v1.Pod) (*v1.Pod, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatePod", arg0) + ret0, _ := ret[0].(*v1.Pod) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdatePod indicates an expected call of UpdatePod +func (mr *MockOpsMockRecorder) UpdatePod(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePod", reflect.TypeOf((*MockOps)(nil).UpdatePod), arg0) +} + +// UpdateSecret mocks base method +func (m *MockOps) UpdateSecret(arg0 *v1.Secret) (*v1.Secret, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateSecret", arg0) + ret0, _ := ret[0].(*v1.Secret) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateSecret indicates an expected call of UpdateSecret +func (mr *MockOpsMockRecorder) UpdateSecret(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateSecret", reflect.TypeOf((*MockOps)(nil).UpdateSecret), arg0) +} + +// UpdateSecretData mocks base method +func (m *MockOps) UpdateSecretData(arg0, arg1 string, arg2 map[string][]byte) (*v1.Secret, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateSecretData", arg0, arg1, arg2) + ret0, _ := ret[0].(*v1.Secret) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateSecretData indicates an expected call of UpdateSecretData +func (mr *MockOpsMockRecorder) UpdateSecretData(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateSecretData", reflect.TypeOf((*MockOps)(nil).UpdateSecretData), arg0, arg1, arg2) +} + +// UpdateServiceAccount mocks base method +func (m *MockOps) UpdateServiceAccount(arg0 *v1.ServiceAccount) (*v1.ServiceAccount, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateServiceAccount", arg0) + ret0, _ := ret[0].(*v1.ServiceAccount) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateServiceAccount indicates an expected call of UpdateServiceAccount +func (mr *MockOpsMockRecorder) UpdateServiceAccount(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateServiceAccount", reflect.TypeOf((*MockOps)(nil).UpdateServiceAccount), arg0) +} + +// ValidateDeletedService mocks base method +func (m *MockOps) ValidateDeletedService(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateDeletedService", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// ValidateDeletedService indicates an expected call of ValidateDeletedService +func (mr *MockOpsMockRecorder) ValidateDeletedService(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateDeletedService", reflect.TypeOf((*MockOps)(nil).ValidateDeletedService), arg0, arg1) +} + +// ValidatePersistentVolumeClaim mocks base method +func (m *MockOps) ValidatePersistentVolumeClaim(arg0 *v1.PersistentVolumeClaim, arg1, arg2 time.Duration) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidatePersistentVolumeClaim", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// ValidatePersistentVolumeClaim indicates an expected call of ValidatePersistentVolumeClaim +func (mr *MockOpsMockRecorder) ValidatePersistentVolumeClaim(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatePersistentVolumeClaim", reflect.TypeOf((*MockOps)(nil).ValidatePersistentVolumeClaim), arg0, arg1, arg2) +} + +// ValidatePersistentVolumeClaimSize mocks base method +func (m *MockOps) ValidatePersistentVolumeClaimSize(arg0 *v1.PersistentVolumeClaim, arg1 int64, arg2, arg3 time.Duration) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidatePersistentVolumeClaimSize", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(error) + return ret0 +} + +// ValidatePersistentVolumeClaimSize indicates an expected call of ValidatePersistentVolumeClaimSize +func (mr *MockOpsMockRecorder) ValidatePersistentVolumeClaimSize(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatePersistentVolumeClaimSize", reflect.TypeOf((*MockOps)(nil).ValidatePersistentVolumeClaimSize), arg0, arg1, arg2, arg3) +} + +// ValidatePod mocks base method +func (m *MockOps) ValidatePod(arg0 *v1.Pod, arg1, arg2 time.Duration) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidatePod", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// ValidatePod indicates an expected call of ValidatePod +func (mr *MockOpsMockRecorder) ValidatePod(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatePod", reflect.TypeOf((*MockOps)(nil).ValidatePod), arg0, arg1, arg2) +} + +// WaitForPodDeletion mocks base method +func (m *MockOps) WaitForPodDeletion(arg0 types.UID, arg1 string, arg2 time.Duration) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WaitForPodDeletion", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// WaitForPodDeletion indicates an expected call of WaitForPodDeletion +func (mr *MockOpsMockRecorder) WaitForPodDeletion(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForPodDeletion", reflect.TypeOf((*MockOps)(nil).WaitForPodDeletion), arg0, arg1, arg2) +} + +// WatchConfigMap mocks base method +func (m *MockOps) WatchConfigMap(arg0 *v1.ConfigMap, arg1 core.WatchFunc) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WatchConfigMap", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// WatchConfigMap indicates an expected call of WatchConfigMap +func (mr *MockOpsMockRecorder) WatchConfigMap(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WatchConfigMap", reflect.TypeOf((*MockOps)(nil).WatchConfigMap), arg0, arg1) +} + +// WatchNode mocks base method +func (m *MockOps) WatchNode(arg0 *v1.Node, arg1 core.WatchFunc) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WatchNode", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// WatchNode indicates an expected call of WatchNode +func (mr *MockOpsMockRecorder) WatchNode(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WatchNode", reflect.TypeOf((*MockOps)(nil).WatchNode), arg0, arg1) +} + +// WatchPods mocks base method +func (m *MockOps) WatchPods(arg0 string, arg1 core.WatchFunc, arg2 v11.ListOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WatchPods", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// WatchPods indicates an expected call of WatchPods +func (mr *MockOpsMockRecorder) WatchPods(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WatchPods", reflect.TypeOf((*MockOps)(nil).WatchPods), arg0, arg1, arg2) +} + +// WatchSecret mocks base method +func (m *MockOps) WatchSecret(arg0 *v1.Secret, arg1 core.WatchFunc) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WatchSecret", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// WatchSecret indicates an expected call of WatchSecret +func (mr *MockOpsMockRecorder) WatchSecret(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WatchSecret", reflect.TypeOf((*MockOps)(nil).WatchSecret), arg0, arg1) +} diff --git a/api/server/sdk/volume_ops.go b/api/server/sdk/volume_ops.go index 097d6588e..3c8be3a64 100644 --- a/api/server/sdk/volume_ops.go +++ b/api/server/sdk/volume_ops.go @@ -25,6 +25,7 @@ import ( "github.com/libopenstorage/openstorage/api" "github.com/libopenstorage/openstorage/pkg/auth" + "github.com/libopenstorage/openstorage/pkg/auth/secrets" policy "github.com/libopenstorage/openstorage/pkg/storagepolicy" "github.com/libopenstorage/openstorage/pkg/util" "github.com/libopenstorage/openstorage/volume" @@ -33,6 +34,17 @@ import ( "google.golang.org/grpc/status" ) +var ( + // AdminOwnedLabelKeys is a set of labels that only the storage admin + // can change. + AdminOwnedLabelKeys = []string{ + secrets.SecretNameKey, + secrets.SecretNamespaceKey, + api.KubernetesPvcNameKey, + api.KubernetesPvcNamespaceKey, + } +) + // When create is called for an existing volume, this function is called to make sure // the SDK only returns that the volume is ready when the status is UP func (s *VolumeServer) waitForVolumeReady(ctx context.Context, id string) (*api.Volume, error) { @@ -563,6 +575,15 @@ func (s *VolumeServer) Update( return nil, err } + // Only the administrator can change admin-only labels + if !api.IsAdminByContext(ctx) && req.GetLabels() != nil { + for _, adminKey := range AdminOwnedLabelKeys { + if _, ok := req.GetLabels()[adminKey]; ok { + return nil, status.Errorf(codes.PermissionDenied, "Only the administrator can update label %s", adminKey) + } + } + } + // Check if the caller can update the volume if !resp.GetVolume().IsPermitted(ctx, api.Ownership_Write) { return nil, status.Errorf(codes.PermissionDenied, "Cannot update volume") diff --git a/api/server/sdk/volume_ops_test.go b/api/server/sdk/volume_ops_test.go index adcaad157..9a5f4d1dd 100644 --- a/api/server/sdk/volume_ops_test.go +++ b/api/server/sdk/volume_ops_test.go @@ -621,6 +621,80 @@ func TestSdkVolumeEnumerateWithFilters(t *testing.T) { assert.Equal(t, r.GetVolumeIds()[0], id) } +func TestSdkVolumeUpdateAdminLabels(t *testing.T) { + // This test does not use the gRPC server + mc := gomock.NewController(&utils.SafeGoroutineTester{}) + mv := mockdriver.NewMockVolumeDriver(mc) + mcluster := mockcluster.NewMockCluster(mc) + + // Setup server + s := VolumeServer{ + server: &sdkGrpcServer{ + // This will enable isAuthEnabled to return true + config: ServerConfig{ + Security: &SecurityConfig{ + Authenticators: map[string]auth.Authenticator{ + "hello": nil, + "another": nil, + }, + }, + }, + driverHandlers: map[string]volume.VolumeDriver{ + "mock": mv, + DefaultDriverName: mv, + }, + clusterHandler: mcluster, + }, + } + + id := "myid" + newlabels := map[string]string{ + api.KubernetesPvcNameKey: "hello", + } + req := &api.SdkVolumeUpdateRequest{ + VolumeId: id, + Labels: newlabels, + } + + // Check Locator + mv. + EXPECT(). + Enumerate(&api.VolumeLocator{ + VolumeIds: []string{id}, + }, nil). + Return([]*api.Volume{&api.Volume{Spec: &api.VolumeSpec{}}}, nil). + AnyTimes() + mv. + EXPECT(). + Set(gomock.Any(), gomock.Any(), gomock.Any()). + Return(nil). + AnyTimes() + + // m + ctxNoAuth := context.Background() + ctxNotAdmin := auth.ContextSaveUserInfo(context.Background(), &auth.UserInfo{ + Username: "notmyname", + }) + ctxAdmin := auth.ContextSaveUserInfo(context.Background(), &auth.UserInfo{ + Username: "admin", + Claims: auth.Claims{ + Groups: []string{"*"}, + }, + }) + + // No auth enabled + _, err := s.Update(ctxNoAuth, req) + assert.NoError(t, err) + + // Ctx has auth but not admin + _, err = s.Update(ctxNotAdmin, req) + assert.Error(t, err) + + // Ctx has auth but not admin + _, err = s.Update(ctxAdmin, req) + assert.NoError(t, err) +} + func TestSdkVolumeUpdate(t *testing.T) { // Create server and client connection diff --git a/api/server/testutils_test.go b/api/server/testutils_test.go index 9edbe31fd..a7eadddd3 100644 --- a/api/server/testutils_test.go +++ b/api/server/testutils_test.go @@ -17,6 +17,7 @@ import ( "github.com/kubernetes-csi/csi-test/utils" "github.com/libopenstorage/openstorage/api" mockapi "github.com/libopenstorage/openstorage/api/mock" + servermock "github.com/libopenstorage/openstorage/api/server/mock" "github.com/libopenstorage/openstorage/api/server/sdk" "github.com/libopenstorage/openstorage/cluster" clustermanager "github.com/libopenstorage/openstorage/cluster/manager" @@ -42,6 +43,8 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" + + schedopsk8s "github.com/portworx/sched-ops/k8s/core" ) const ( @@ -63,14 +66,16 @@ var ( // testServer is a simple struct used abstract // the creation and setup of the gRPC CSI service and REST server type testServer struct { - conn *grpc.ClientConn - m *mockdriver.MockVolumeDriver - c cluster.Cluster - s *mockapi.MockOpenStoragePoolServer - mc *gomock.Controller - sdk *sdk.Server - port string - gwport string + conn *grpc.ClientConn + m *mockdriver.MockVolumeDriver + c cluster.Cluster + s *mockapi.MockOpenStoragePoolServer + k8sops *servermock.MockOps + originalOps schedopsk8s.Ops + mc *gomock.Controller + sdk *sdk.Server + port string + gwport string } // Struct used for creation and setup of cluster api testing @@ -138,6 +143,10 @@ func newTestServerSdkNoAuth(t *testing.T) *testServer { tester.m = mockdriver.NewMockVolumeDriver(tester.mc) tester.c = mockcluster.NewMockCluster(tester.mc) tester.s = mockapi.NewMockOpenStoragePoolServer(tester.mc) + tester.k8sops = servermock.NewMockOps(tester.mc) + + tester.originalOps = schedopsk8s.Instance() + schedopsk8s.SetInstance(tester.k8sops) kv, err := kvdb.New(mem.Name, "test", []string{}, nil, kvdb.LogFatalErrorCB) assert.NoError(t, err) @@ -194,6 +203,10 @@ func newTestServerSdk(t *testing.T) *testServer { tester.m = mockdriver.NewMockVolumeDriver(tester.mc) tester.c = mockcluster.NewMockCluster(tester.mc) tester.s = mockapi.NewMockOpenStoragePoolServer(tester.mc) + tester.k8sops = servermock.NewMockOps(tester.mc) + + tester.originalOps = schedopsk8s.Instance() + schedopsk8s.SetInstance(tester.k8sops) // Create a role manager kv, err := kvdb.New(mem.Name, "test", []string{}, nil, kvdb.LogFatalErrorCB) @@ -308,6 +321,10 @@ func (s *testServer) MockDriver() *mockdriver.MockVolumeDriver { return s.m } +func (s *testServer) MockK8sOps() *servermock.MockOps { + return s.k8sops +} + func (s *testServer) Conn() *grpc.ClientConn { return s.conn } @@ -416,6 +433,8 @@ func (s *testServer) Stop() { // Remove from registry volumedrivers.Remove(mockDriverName) + + schedopsk8s.SetInstance(s.originalOps) } func createToken(name, role, secret string) (string, error) { diff --git a/api/server/volume.go b/api/server/volume.go index f1a2968aa..1d2a802e9 100644 --- a/api/server/volume.go +++ b/api/server/volume.go @@ -22,6 +22,7 @@ import ( "github.com/libopenstorage/openstorage/api/server/sdk" clustermanager "github.com/libopenstorage/openstorage/cluster/manager" "github.com/libopenstorage/openstorage/pkg/auth" + "github.com/libopenstorage/openstorage/pkg/auth/secrets" "github.com/libopenstorage/openstorage/pkg/grpcserver" "github.com/libopenstorage/openstorage/pkg/options" "github.com/libopenstorage/openstorage/volume" @@ -194,6 +195,12 @@ func (vd *volAPI) create(w http.ResponseWriter, r *http.Request) { if err := json.NewDecoder(r.Body).Decode(&dcReq); err != nil { fmt.Println("returning error here") vd.sendError(vd.name, method, w, err.Error(), http.StatusBadRequest) + } + if dcReq.GetSpec() == nil { + vd.sendError(vd.name, method, w, "Must supply a volume specification", http.StatusBadRequest) + return + } else if dcReq.GetLocator() == nil { + vd.sendError(vd.name, method, w, "Must supply a volume locator", http.StatusBadRequest) return } @@ -204,6 +211,26 @@ func (vd *volAPI) create(w http.ResponseWriter, r *http.Request) { return } + // Check headers for secret reference. These are set by the Kubernetes auth middleware + secretName := r.Header.Get(secrets.SecretNameKey) + secretNamespace := r.Header.Get(secrets.SecretNamespaceKey) + pvcName := r.Header.Get(api.KubernetesPvcNameKey) + pvcNamespace := r.Header.Get(api.KubernetesPvcNamespaceKey) + if len(secretName) != 0 && len(secretNamespace) != 0 { + if dcReq.GetLocator().GetVolumeLabels() == nil { + dcReq.GetLocator().VolumeLabels = make(map[string]string) + } + dcReq.GetLocator().GetVolumeLabels()[secrets.SecretNameKey] = secretName + dcReq.GetLocator().GetVolumeLabels()[secrets.SecretNamespaceKey] = secretNamespace + + // Only add the pvc name and namespace if we had the secrets and if the + // pvc values where passed + if len(pvcName) != 0 && len(pvcNamespace) != 0 { + dcReq.GetLocator().GetVolumeLabels()[api.KubernetesPvcNameKey] = pvcName + dcReq.GetLocator().GetVolumeLabels()[api.KubernetesPvcNamespaceKey] = pvcNamespace + } + } + // Get gRPC connection conn, err := vd.getConn() if err != nil { @@ -452,7 +479,6 @@ func (vd *volAPI) volumeSet(w http.ResponseWriter, r *http.Request) { } } json.NewEncoder(w).Encode(resp) - } func getVolumeUpdateSpec(spec *api.VolumeSpec, vol *api.Volume) *api.VolumeSpecUpdate { @@ -1822,14 +1848,14 @@ func (vd *volAPI) SetupRoutesWithAuth( nInspect := negroni.New() nInspect.Use(negroni.HandlerFunc(authM.inspectWithAuth)) inspectRoute := vd.volumeInspectRoute() - nSet.UseHandlerFunc(inspectRoute.fn) + nInspect.UseHandlerFunc(inspectRoute.fn) router.Methods(inspectRoute.verb).Path(inspectRoute.path).Handler(nInspect) // Setup middleware for enumerate nEnumerate := negroni.New() nEnumerate.Use(negroni.HandlerFunc(authM.enumerateWithAuth)) enumerateRoute := vd.volumeEnumerateRoute() - nSet.UseHandlerFunc(enumerateRoute.fn) + nEnumerate.UseHandlerFunc(enumerateRoute.fn) router.Methods(enumerateRoute.verb).Path(enumerateRoute.path).Handler(nEnumerate) routes := []*Route{vd.versionRoute()} diff --git a/api/server/volume_test.go b/api/server/volume_test.go index 50d7b3f03..405ca4549 100644 --- a/api/server/volume_test.go +++ b/api/server/volume_test.go @@ -17,8 +17,18 @@ import ( "github.com/stretchr/testify/assert" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + "github.com/sirupsen/logrus" + + corev1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +func init() { + logrus.SetLevel(logrus.PanicLevel) +} + func TestVolumeNoAuth(t *testing.T) { var err error @@ -189,7 +199,8 @@ func TestMiddlewareVolumeCreateFailure(t *testing.T) { size := uint64(1234) secretName := "secret-name" namespace := "ns" - tokenKey := "token-key" + pvcName := "mypvc" + storageClassName := "storageclass1" req := &api.VolumeCreateRequest{ Locator: &api.VolumeLocator{ @@ -218,13 +229,32 @@ func TestMiddlewareVolumeCreateFailure(t *testing.T) { _, err = driverclient.Create(req.GetLocator(), req.GetSource(), req.GetSpec()) assert.Error(t, err, "Expected an error on Create") + pvc := corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: pvcName, + Namespace: namespace, + }, + Spec: corev1.PersistentVolumeClaimSpec{ + StorageClassName: &storageClassName, + }, + } + + storageClass := storagev1.StorageClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: storageClassName, + }, + Parameters: map[string]string{ + secrets.SecretNameKey: secretName, + secrets.SecretNamespaceKey: "${pvc.namespace}", + }, + } + req = &api.VolumeCreateRequest{ Locator: &api.VolumeLocator{ Name: name, VolumeLabels: map[string]string{ - secrets.SecretNameKey: secretName, - secrets.SecretTokenKey: tokenKey, - secrets.SecretNamespaceKey: namespace, + PVCNameLabelKey: pvcName, + PVCNamespaceLabelKey: namespace, }, }, Source: &api.Source{}, @@ -236,6 +266,11 @@ func TestMiddlewareVolumeCreateFailure(t *testing.T) { }, } + testVolDriver.MockK8sOps().EXPECT(). + GetPersistentVolumeClaim(pvcName, namespace).Return(&pvc, nil).AnyTimes() + testVolDriver.MockK8sOps().EXPECT(). + GetStorageClassForPVC(&pvc).Return(&storageClass, nil).AnyTimes() + // Send a request and fail to get a token mockSecret.EXPECT(). GetSecret( @@ -873,38 +908,6 @@ func TestMiddlewareVolumeSetSizeSuccess(t *testing.T) { assert.NoError(t, err) } -func TestMiddlewareVolumeSetFailure(t *testing.T) { - testVolDriver := newTestServerSdk(t) - defer testVolDriver.Stop() - - _, mockSecret, mc := getSecretsMock(t) - defer mc.Finish() - lsecrets.SetInstance(mockSecret) - - // TODO(stgleb): Fix it - unixServer, portServer, err := StartVolumeMgmtAPI(fakeWithSched, testSdkSock, testMgmtBase, testMgmtPort, true, nil) - assert.NoError(t, err, "Unexpected error on StartVolumeMgmtAPI") - defer unixServer.Close() - defer portServer.Close() - - time.Sleep(1 * time.Second) - c, err := volumeclient.NewDriverClient(testMockURL, fakeWithSched, version, fakeWithSched) - assert.NoError(t, err, "Unexpected error on NewDriverClient") - - driverclient := volumeclient.VolumeDriver(c) - id, _, _, _ := testMiddlewareCreateVolume(t, driverclient, mockSecret, testVolDriver) - - req := &api.VolumeSetRequest{ - Spec: &api.VolumeSpec{Shared: true}, - } - - // Not setting mock secrets - - err = driverclient.Set(id, &api.VolumeLocator{Name: "myvol"}, req.GetSpec()) - assert.Error(t, err, "Unexpected error on Set") - -} - func TestVolumeAttachSuccess(t *testing.T) { var err error @@ -2438,18 +2441,38 @@ func TestMiddlewareVolumeDeleteFailureIncorrectToken(t *testing.T) { size := uint64(1234) secretName := "secret-name" namespace := "ns" - tokenKey := "token-key" + pvcName := "mypvc" + storageClassName := "storageclass1" // get token token, err := createToken("test", "system.admin", testSharedSecret) assert.NoError(t, err) + pvc := corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: pvcName, + Namespace: namespace, + }, + Spec: corev1.PersistentVolumeClaimSpec{ + StorageClassName: &storageClassName, + }, + } + + storageClass := storagev1.StorageClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: storageClassName, + }, + Parameters: map[string]string{ + secrets.SecretNameKey: secretName, + secrets.SecretNamespaceKey: "${pvc.namespace}", + }, + } + req := &api.VolumeCreateRequest{ Locator: &api.VolumeLocator{ Name: name, VolumeLabels: map[string]string{ - secrets.SecretNameKey: secretName, - secrets.SecretTokenKey: tokenKey, - secrets.SecretNamespaceKey: namespace, + PVCNameLabelKey: pvcName, + PVCNamespaceLabelKey: namespace, }, }, Source: &api.Source{}, @@ -2461,6 +2484,11 @@ func TestMiddlewareVolumeDeleteFailureIncorrectToken(t *testing.T) { }, } + testVolDriver.MockK8sOps().EXPECT(). + GetPersistentVolumeClaim(pvcName, namespace).Return(&pvc, nil) + testVolDriver.MockK8sOps().EXPECT(). + GetStorageClassForPVC(&pvc).Return(&storageClass, nil) + mockSecret.EXPECT(). String(). Return(lsecrets.TypeK8s). @@ -2525,18 +2553,38 @@ func testMiddlewareCreateVolume( size := uint64(1234) secretName := "secret-name" namespace := "ns" - tokenKey := "token-key" + pvcName := "mypvc" + storageClassName := "storageclass1" // get token token, err := createToken("test", "system.admin", testSharedSecret) assert.NoError(t, err) + pvc := corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: pvcName, + Namespace: namespace, + }, + Spec: corev1.PersistentVolumeClaimSpec{ + StorageClassName: &storageClassName, + }, + } + + storageClass := storagev1.StorageClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: storageClassName, + }, + Parameters: map[string]string{ + secrets.SecretNameKey: secretName, + secrets.SecretNamespaceKey: "${pvc.namespace}", + }, + } + req := &api.VolumeCreateRequest{ Locator: &api.VolumeLocator{ Name: name, VolumeLabels: map[string]string{ - secrets.SecretNameKey: secretName, - secrets.SecretTokenKey: tokenKey, - secrets.SecretNamespaceKey: namespace, + PVCNameLabelKey: pvcName, + PVCNamespaceLabelKey: namespace, }, }, Source: &api.Source{}, @@ -2547,6 +2595,11 @@ func testMiddlewareCreateVolume( Shared: true, }, } + testVolDriver.MockK8sOps().EXPECT(). + GetPersistentVolumeClaim(pvcName, namespace).Return(&pvc, nil) + testVolDriver.MockK8sOps().EXPECT(). + GetStorageClassForPVC(&pvc).Return(&storageClass, nil) + mockSecret.EXPECT(). String(). Return(lsecrets.TypeK8s). diff --git a/cmd/osd/main.go b/cmd/osd/main.go index 853d42fb2..b111381c0 100644 --- a/cmd/osd/main.go +++ b/cmd/osd/main.go @@ -36,7 +36,6 @@ import ( "github.com/codegangsta/cli" "github.com/docker/docker/pkg/reexec" "github.com/libopenstorage/openstorage/api" - "github.com/libopenstorage/openstorage/api/flexvolume" "github.com/libopenstorage/openstorage/api/server" "github.com/libopenstorage/openstorage/api/server/sdk" osdcli "github.com/libopenstorage/openstorage/cli" @@ -53,6 +52,7 @@ import ( "github.com/libopenstorage/openstorage/schedpolicy" "github.com/libopenstorage/openstorage/volume" volumedrivers "github.com/libopenstorage/openstorage/volume/drivers" + "github.com/libopenstorage/secrets" "github.com/portworx/kvdb" "github.com/portworx/kvdb/consul" etcd "github.com/portworx/kvdb/etcd/v2" @@ -183,6 +183,11 @@ func main() { Usage: "CSI Driver name", Value: "", }, + cli.StringFlag{ + Name: "secrets-type", + Usage: "Secrets manager type. For example \"k8s\"", + Value: "", + }, } app.Action = wrapAction(start) app.Commands = []cli.Command{ @@ -334,6 +339,15 @@ func start(c *cli.Context) error { return fmt.Errorf("Failed to initialize KVDB: %v", err) } + // Setup secrets type if any + if secretsType := c.String("secrets-type"); len(secretsType) > 0 { + i, err := secrets.New(secretsType, nil) + if err != nil { + return fmt.Errorf("Failed to set secrets type: %v", err) + } + secrets.SetInstance(i) + } + // Get authenticators authenticators := make(map[string]auth.Authenticator) selfSigned, err := selfSignedAuth(c) @@ -393,6 +407,9 @@ func start(c *cli.Context) error { isDefaultSet := false // Start the volume drivers. for d, v := range cfg.Osd.Drivers { + // Override sched driver with the current one + server.OverrideSchedDriverName = d + logrus.Infof("Starting volume driver: %v", d) if err := volumedrivers.Register(d, v); err != nil { return fmt.Errorf("Unable to start volume driver: %v, %v", d, err) @@ -432,11 +449,15 @@ func start(c *cli.Context) error { return fmt.Errorf("Unable to start plugin api server: %v", err) } + authEnabled := len(authenticators) > 0 + if authEnabled { + logrus.Info("Management API (deprecated) starting with authentication enabled") + } if _, _, err := server.StartVolumeMgmtAPI( d, sdksocket, volume.DriverAPIBase, uint16(mgmtPort), - false, + authEnabled, authenticators, ); err != nil { return fmt.Errorf("Unable to start volume mgmt api server: %v", err) @@ -512,10 +533,6 @@ func start(c *cli.Context) error { return fmt.Errorf("Invalid OSD config file: Default Driver specified but driver not initialized") } - if err := flexvolume.StartFlexVolumeAPI(config.FlexVolumePort, cfg.Osd.ClusterConfig.DefaultDriver); err != nil { - return fmt.Errorf("Unable to start flexvolume API: %v", err) - } - // Start the graph drivers. for d := range cfg.Osd.GraphDrivers { logrus.Infof("Starting graph driver: %v", d) diff --git a/pkg/auth/secrets/secrets.go b/pkg/auth/secrets/secrets.go index 45a040292..db3ddf8fd 100644 --- a/pkg/auth/secrets/secrets.go +++ b/pkg/auth/secrets/secrets.go @@ -12,11 +12,17 @@ const ( // SecretNameKey is a label on the openstorage.Volume object // which corresponds to the name of the secret which holds the // token information. Used for all secret providers + // This key supports the CSI compatible value of ${pvc.annotations['team.example.com/key']} + // as described in https://kubernetes-csi.github.io/docs/secrets-and-credentials-storage-class.html + // to specify to use the annotations on the pvc. SecretNameKey = "openstorage.io/auth-secret-name" // SecretNamespaceKey is a label on the openstorage.Volume object // which corresponds to the namespace of the secret which holds the // token information. Used for all secret providers + // This key supports the CSI compatible value of ${pvc.namespace} + // as described in https://kubernetes-csi.github.io/docs/secrets-and-credentials-storage-class.html + // to specify to use the namespace of the pvc SecretNamespaceKey = "openstorage.io/auth-secret-namespace" // SecretTokenKey corresponds to the key at which the auth token is stored diff --git a/pkg/util/template.go b/pkg/util/template.go new file mode 100644 index 000000000..0eedd9de2 --- /dev/null +++ b/pkg/util/template.go @@ -0,0 +1,39 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "fmt" + "os" + + "k8s.io/apimachinery/pkg/util/sets" +) + +func ResolveTemplate(template string, params map[string]string) (string, error) { + missingParams := sets.NewString() + resolved := os.Expand(template, func(k string) string { + v, ok := params[k] + if !ok { + missingParams.Insert(k) + } + return v + }) + if missingParams.Len() > 0 { + return "", fmt.Errorf("invalid tokens: %q", missingParams.List()) + } + return resolved, nil +} diff --git a/test/run.bash b/test/run.bash index 697c72129..f85687387 100755 --- a/test/run.bash +++ b/test/run.bash @@ -9,8 +9,8 @@ for d in $dependecies ; do fi done -# Location of bart -BART=./node_modules/bats/bin/bats +# Location of bats +BATS=./node_modules/bats/bin/bats # Setup export KIND_CLUSTER=${USER}-kind-openstorage-test @@ -25,4 +25,4 @@ export TENANT1_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InN1cHBvcn export TENANT2_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InN1cHBvcnRAdGVuYW50LXR3by5jb20iLCJleHAiOjE5MDE3MzA1NDksImdyb3VwcyI6WyJ0ZW5hbnQtdHdvIl0sImlhdCI6MTU4NjM3MDU0OSwiaXNzIjoib3BlbnN0b3JhZ2UuaW8iLCJuYW1lIjoiVGVuYW50IFR3byIsInJvbGVzIjpbInN5c3RlbS51c2VyIl0sInN1YiI6InN1cHBvcnRAdGVuYW50LXR3by5jb20ifQ.6t3DiToB5ttTKZ9IuSoM4XTKKltpBq84kz7HseehjFc # Set env DEBUG=1 to show output of osd::echo and osd::by -${BART} setup testcases && rm -rf ${TMPDIR} +${BATS} setup testcases && rm -rf ${TMPDIR} diff --git a/volume/drivers/fake/fake.go b/volume/drivers/fake/fake.go index a8929b9c1..1f1a81201 100644 --- a/volume/drivers/fake/fake.go +++ b/volume/drivers/fake/fake.go @@ -140,14 +140,23 @@ func (d *driver) Status() [][2]string { } func (d *driver) Inspect(volumeIDs []string) ([]*api.Volume, error) { + empty := make([]*api.Volume, 0, len(volumeIDs)) + + // The Kubernetes intree driver for portworx incorrectly requests version + // from Inspect, which can be interpreted as a volumd id. Instead we catch + // it here and return success with an empty list. + if len(volumeIDs) > 0 && volumeIDs[0] == "versions" { + return empty, nil + } + volumes, err := d.StoreEnumerator.Inspect(volumeIDs) if err != nil { - return nil, err + return empty, err } else if err == nil && len(volumes) == 0 { - return nil, kvdb.ErrNotFound + return empty, kvdb.ErrNotFound } - return volumes, err + return volumes, nil } // diff --git a/volume/drivers/fake/fake_test.go b/volume/drivers/fake/fake_test.go index d91453935..d45dd0f53 100644 --- a/volume/drivers/fake/fake_test.go +++ b/volume/drivers/fake/fake_test.go @@ -118,7 +118,7 @@ func TestFakeInspect(t *testing.T) { assert.NotNil(t, err) assert.Error(t, err) assert.Equal(t, err, kvdb.ErrNotFound) - assert.Nil(t, v) + assert.NotNil(t, v) } func TestFakeCapacityUsage(t *testing.T) {