Skip to content

Commit

Permalink
Merge pull request #234 from AmitKumarDas/ns-fix-1055
Browse files Browse the repository at this point in the history
fixes maya api server issue of multiple namespaces
  • Loading branch information
kmova authored Dec 25, 2017
2 parents 4356876 + 65cc5c3 commit 4bdf139
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 25 deletions.
35 changes: 35 additions & 0 deletions cmd/maya-apiserver/app/server/volume_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import (
"github.com/openebs/maya/volume/provisioners"
)

const (
// NamespaceKey is used in request headers to get the
// namespace
NamespaceKey string = "namespace"
)

// VolumeSpecificRequest is a http handler implementation. It deals with HTTP
// requests w.r.t a single Volume.
//
Expand Down Expand Up @@ -60,8 +66,23 @@ func (s *HTTPServer) volumeList(resp http.ResponseWriter, req *http.Request) (in

glog.Infof("Processing Volume list request")

// Get the namespace if provided
ns := ""
if req != nil {
ns = req.Header.Get(NamespaceKey)
}

if ns == "" {
// We shall override if empty. This seems to be simple enough
// that works for most of the usecases.
// Otherwise we need to introduce logic to decide for default
// namespace depending on operation type.
ns = v1.DefaultNamespaceForListOps
}

// Create a Volume
vol := &v1.Volume{}
vol.Namespace = ns

// Pass through the policy enforcement logic
policy, err := policies_v1.VolumeGenericPolicy()
Expand Down Expand Up @@ -114,9 +135,16 @@ func (s *HTTPServer) volumeRead(resp http.ResponseWriter, req *http.Request, vol
return nil, CodedError(400, fmt.Sprintf("Volume name is missing"))
}

// Get the namespace if provided
ns := ""
if req != nil {
ns = req.Header.Get(NamespaceKey)
}

// Create a Volume
vol := &v1.Volume{}
vol.Name = volName
vol.Namespace = ns

// Pass through the policy enforcement logic
policy, err := policies_v1.VolumeGenericPolicy()
Expand Down Expand Up @@ -171,9 +199,16 @@ func (s *HTTPServer) volumeDelete(resp http.ResponseWriter, req *http.Request, v
return nil, CodedError(400, fmt.Sprintf("Volume name is missing"))
}

// Get the namespace if provided
ns := ""
if req != nil {
ns = req.Header.Get(NamespaceKey)
}

// Create a Volume
vol := &v1.Volume{}
vol.Name = volName
vol.Namespace = ns

// Pass through the policy enforcement logic
policy, err := policies_v1.VolumeGenericPolicy()
Expand Down
142 changes: 118 additions & 24 deletions orchprovider/k8s/v1/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -619,20 +619,65 @@ func (k *k8sOrchestrator) readVSM(vsm string, volProProfile volProfile.VolumePro
return pv, nil
}

// ListStorage will list a collections of VSMs
func (k *k8sOrchestrator) ListStorage(volProProfile volProfile.VolumeProvisionerProfile) (*v1.VolumeList, error) {
if volProProfile == nil {
return nil, fmt.Errorf("Nil volume provisioner profile provided")
// getAllNamespaces will get all the available namespaces
// in K8s cluster
func (k *k8sOrchestrator) getAllNamespaces(vol *v1.Volume) ([]string, error) {

ku := &k8sUtil{
volume: vol,
}

kc, supported, err := ku.K8sClientV2()
if err != nil {
return nil, err
}

glog.Infof("Listing VSMs at orchestrator '%s: %s'", k.Label(), k.Name())
if !supported {
return nil, fmt.Errorf("K8s client is not supported")
}

nsOps, err := kc.NamespaceOps()
if err != nil {
return nil, err
}

dl, err := k.getVSMDeployments(volProProfile)
nsl, err := nsOps.List(metav1.ListOptions{})
if err != nil {
return nil, err
}

if dl == nil || dl.Items == nil || len(dl.Items) == 0 {
var nss []string
for _, ns := range nsl.Items {
nss = append(nss, ns.Name)
}

return nss, nil
}

// listStorageByNS will list a collections of volumes for a
// particular namespace
func (k *k8sOrchestrator) listStorageByNS(vol *v1.Volume) (*v1.VolumeList, error) {
glog.Infof("Listing volumes for namespace '%s'", vol.Namespace)

vpp, err := volProfile.GetVolProProfile(vol)
if err != nil {
return nil, err
}

// Need to use a new version of k8sUtil as the volume
// it composes determines the namespace to be used
// for K8s list operation
//
// Note: Here volume acts as a placeholder for namespace &
// doesnot necessarily represent a volume
dl, err := k.getVSMDeployments(&k8sUtil{
volume: vol,
})
if err != nil {
return nil, err
}

if dl == nil || len(dl.Items) == 0 {
return nil, nil
}

Expand All @@ -648,19 +693,69 @@ func (k *k8sOrchestrator) ListStorage(volProProfile volProfile.VolumeProvisioner

vsm := v1.SanitiseVSMName(d.Name)
if vsm == "" {
return nil, fmt.Errorf("VSM name could not be determined from K8s Deployment 'name: %s'", d.Name)
return nil, fmt.Errorf("Volume name could not be determined from K8s Deployment '%s'", d.Name)
}

pv, err := k.readVSM(vsm, volProProfile)
if err != nil {
// Ignore the error of this particular VSM
// Cases where this particular VSM might be in a creating or deleting state
pv, _ := k.readVSM(vsm, vpp)
if pv == nil {
// Ignore the cases where this particular VSM might be in
// a creating or deleting state
continue
}

pvl.Items = append(pvl.Items, *pv)
}

glog.Infof("Listed VSMs 'count: %d' at orchestrator '%s: %s'", len(pvl.Items), k.Label(), k.Name())
glog.Infof("Listed volumes with count '%d' for namespace '%s'", len(pvl.Items), vol.Namespace)

return pvl, nil
}

// ListStorage will list a collections of VSMs
func (k *k8sOrchestrator) ListStorage(volProProfile volProfile.VolumeProvisionerProfile) (*v1.VolumeList, error) {
if volProProfile == nil {
return nil, fmt.Errorf("Nil volume provisioner profile provided")
}

vol, err := volProProfile.Volume()
if err != nil {
return nil, err
}

var nss []string
if vol.Namespace == v1.DefaultNamespaceForListOps {
nss, err = k.getAllNamespaces(vol)
if err != nil {
return nil, err
}
}

// This will be nil if the list operation is desired
// for a specific namespace
if nss == nil {
return k.listStorageByNS(vol)
}

pvl := &v1.VolumeList{}
// We take a copy to avoid mutating the original
// volume
volCpy := &v1.Volume{}
volCpy = vol
for _, ns := range nss {
// This is most important step
// Listing will be done based on namespace
volCpy.Namespace = ns
l, err := k.listStorageByNS(volCpy)
if err != nil {
return nil, err
}

if l == nil || len(l.Items) == 0 {
continue
}

pvl.Items = append(pvl.Items, l.Items...)
}

return pvl, nil
}
Expand Down Expand Up @@ -1390,16 +1485,18 @@ func (k *k8sOrchestrator) getDeploymentList(vsm string, volProProfile volProfile
}

// getVSMDeployments fetches all the VSM deployments
func (k *k8sOrchestrator) getVSMDeployments(volProProfile volProfile.VolumeProvisionerProfile) (*k8sApisExtnsBeta1.DeploymentList, error) {
func (k *k8sOrchestrator) getVSMDeployments(ku *k8sUtil) (*k8sApisExtnsBeta1.DeploymentList, error) {

k8sUtl := k8sOrchUtil(k, volProProfile)
kc, supported, err := ku.K8sClientV2()
if err != nil {
return nil, err
}

kc, supported := k8sUtl.K8sClient()
if !supported {
return nil, fmt.Errorf("K8s client not supported by '%s'", k8sUtl.Name())
return nil, fmt.Errorf("K8s client is not supported")
}

dOps, err := kc.DeploymentOps()
dOps, err := kc.DeploymentOps2()
if err != nil {
return nil, err
}
Expand All @@ -1424,13 +1521,10 @@ func (k *k8sOrchestrator) getVSMDeployments(volProProfile volProfile.VolumeProvi
}

// getVSMServices fetches all the VSM services
func (k *k8sOrchestrator) getVSMServices(volProProfile volProfile.VolumeProvisionerProfile) (*k8sApiV1.ServiceList, error) {

k8sUtl := k8sOrchUtil(k, volProProfile)

kc, supported := k8sUtl.K8sClient()
func (k *k8sOrchestrator) getVSMServices(k8sUtil *k8sUtil) (*k8sApiV1.ServiceList, error) {
kc, supported := k8sUtil.K8sClient()
if !supported {
return nil, fmt.Errorf("K8s client not supported by '%s'", k8sUtl.Name())
return nil, fmt.Errorf("K8s client not supported by '%s'", k8sUtil.Name())
}

sOps, err := kc.Services()
Expand Down
37 changes: 36 additions & 1 deletion orchprovider/k8s/v1/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,14 @@ type K8sClientV2 interface {
// NOTE:
// StoragePool is a K8s CRD resource
StoragePoolOps() (oe_client_v1alpha1.StoragePoolInterface, error)

// NamespaceOps provides a NamespaceInterface that exposes
// various CRUD operations w.r.t Namespace
NamespaceOps() (k8sCoreV1.NamespaceInterface, error)

// DeploymentOps2 provides all the CRUD operations associated
// w.r.t a Deployment
DeploymentOps2() (k8sExtnsV1Beta1.DeploymentInterface, error)
}

// k8sUtil provides the concrete implementation for below interfaces:
Expand Down Expand Up @@ -703,7 +711,7 @@ func (k *k8sUtil) Services() (k8sCoreV1.ServiceInterface, error) {
return cs.CoreV1().Services(ns), nil
}

// Services is a utility function that provides a instance capable of
// DeploymentOps is a utility function that provides a instance capable of
// executing various k8s Deployment related operations.
func (k *k8sUtil) DeploymentOps() (k8sExtnsV1Beta1.DeploymentInterface, error) {
var cs *kubernetes.Clientset
Expand Down Expand Up @@ -822,6 +830,33 @@ func (k *k8sUtil) PVCOps2() (k8sCoreV1.PersistentVolumeClaimInterface, error) {
return cs.CoreV1().PersistentVolumeClaims(k.volume.Namespace), nil
}

// DeploymentOps2 is a utility function that provides a instance capable of
// executing various k8s Deployment related operations.
func (k *k8sUtil) DeploymentOps2() (k8sExtnsV1Beta1.DeploymentInterface, error) {
cs, err := k.getClientSet()
if err != nil {
return nil, err
}

// error out if still empty
if len(k.volume.Namespace) == 0 {
return nil, fmt.Errorf("Nil namespace")
}

return cs.ExtensionsV1beta1().Deployments(k.volume.Namespace), nil
}

// NamespaceOps provides the NamespaceInterface object that exposes
// various CRUD operations
func (k *k8sUtil) NamespaceOps() (k8sCoreV1.NamespaceInterface, error) {
cs, err := k.getClientSet()
if err != nil {
return nil, err
}

return cs.CoreV1().Namespaces(), nil
}

func (k *k8sUtil) StoragePoolOps() (oe_client_v1alpha1.StoragePoolInterface, error) {
mcs, err := k.getOEClientSet()
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions types/v1/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ const (
// DefaultMonitoringImage contains the default image for
// volume monitoring
DefaultMonitoringImage string = "openebs/m-exporter:latest"

// DefaultNamespaceForListOps contains the default
DefaultNamespaceForListOps string = "all-namespaces"
)

var (
Expand Down
1 change: 1 addition & 0 deletions volume/policies/v1/policy_k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ func (p *K8sPolicies) initNS() {

// possible values for namespace
nsVals := []string{
p.volume.ObjectMeta.Namespace,
p.volume.Labels.K8sNamespace,
v1.NamespaceENV(),
v1.DefaultNamespace,
Expand Down

0 comments on commit 4bdf139

Please sign in to comment.