Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Makeuse of PVC namespace when provisioning gluster volumes. #34705

Merged
merged 1 commit into from
Oct 20, 2016

Conversation

humblec
Copy link
Contributor

@humblec humblec commented Oct 13, 2016

Depends on #34611


This change is Reviewable

@k8s-ci-robot
Copy link
Contributor

Can a kubernetes member verify that this patch is reasonable to test? If so, please reply with "@k8s-bot ok to test" on its own line.

Regular contributors should join the org to skip this step.

@humblec humblec force-pushed the gluster-pvc-namespace-1 branch 2 times, most recently from 091489c to 0fc1655 Compare October 13, 2016 11:20
@k8s-github-robot k8s-github-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. release-note-label-needed labels Oct 13, 2016
@humblec
Copy link
Contributor Author

humblec commented Oct 13, 2016

@rootfs @jsafrane PTAL.

resturl: "http://127.0.0.1:8081"
restuser: "admin"
secretNamespace: "default"
secretName: "heketi-secret"
```

* `endpoint`: `glusterfs-cluster` is the endpoint name which includes GlusterFS trusted pool IP addresses. This parameter is mandatory. We need to also create a service for this endpoint, so that the endpoint will be persisted. This service can be without a selector to tell Kubernetes we want to add its endpoints manually. Please note that, glusterfs plugin looks for the endpoint in the pod namespace, so it is mandatory that the endpoint and service have to be created in Pod's namespace for successful mount of gluster volumes in the pod.
* `endpoint`: This option is deprecated as the provisioner now create endpoint and service dynamically to support multi cluster setup.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just remove it? it is a parameter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

for _, a := range s.Addresses {
addr[a.IP] = struct{}{}
var addrlist []string
if b.hosts != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add b.hosts == nil test, return error; keep rest as it is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

if pvSpec.Glusterfs.EndpointsName != "" {
dynamicEndpoint = pvSpec.Glusterfs.EndpointsName
}
glog.V(1).Infof("glusterfs: dynamic endpoint and namespace : [%v/%v]", dynamicEndpoint, dynamicNamespace)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

V(1) -> V(3 or 4)
swap endpoint and namespace; usually we print namespace/endpoint

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

glog.Errorf("glusterfs: error when deleting endpoint/service :%s", err)
}
} else {
glog.V(3).Infof("glusterfs: cluster is not empty")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of logging cluster is not empty, log when the endpoint is deleted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

return endpoint, service, nil
}

func (d *glusterfsVolumeDeleter) DeleteEndpointService(namespace string, epServiceName string) (err error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since DeleteEndpointService is not used outside of deleter, make it lower case deleteEndpointService

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete service first then endpoint. If endpoint is deleted then kubelet crashes, we leak a hanging service.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. afaict, if we delete svc first , it will delete the ep as well. So I kept ep deletion followed by svc to make sure both are gone. Any way reverted the change and only keeping service delete.

ipaddr := dstrings.Join(nodei.NodeAddRequest.Hostnames.Storage, "")
dynamicHostIps = append(dynamicHostIps, ipaddr)
}
glog.V(1).Infof("glusterfs: hostlist :%v", dynamicHostIps)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

V(3)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}
glog.V(1).Infof("glusterfs: hostlist :%v", dynamicHostIps)
if len(dynamicHostIps) == 0 {
glog.Errorf("glusterfs: no endpoint hosts found %s ", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no hosts found %v

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

for _, node := range clusterinfo.Nodes {
nodei, err := cli.NodeInfo(string(node))
if err != nil {
glog.Errorf("glusterfs: failed to get hostip %s ", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

failed to get host ip %v

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -528,20 +563,113 @@ func (p *glusterfsVolumeProvisioner) CreateVolume() (r *api.GlusterfsVolumeSourc
glog.Errorf("glusterfs: failed to create gluster rest client")
return nil, 0, fmt.Errorf("failed to create gluster REST client, REST server authentication failed")
}
volumeReq := &gapi.VolumeCreateRequest{Size: sz, Durability: gapi.VolumeDurabilityInfo{Type: durabilitytype, Replicate: gapi.ReplicaDurability{Replica: replicacount}}}
volumeReq := &gapi.VolumeCreateRequest{Size: sz, Durability: gapi.VolumeDurabilityInfo{Type: durabilityType, Replicate: gapi.ReplicaDurability{Replica: replicaCount}}}
volume, err := cli.VolumeCreate(volumeReq)
if err != nil {
glog.Errorf("glusterfs: error creating volume %s ", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error creating volume %v

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

return &api.GlusterfsVolumeSource{
EndpointsName: p.endpoint,
EndpointsName: endpoint.Name,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't see Name in api.Endpoints

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rootfs it resolves from ObjectMeta. For ex:61917ff#diff-e97253dd603331ffca81131a4b67264fR626

@rootfs
Copy link
Contributor

rootfs commented Oct 13, 2016

@jsafrane

Copy link
Contributor

@rootfs rootfs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass baton to @jsafrane @childsb

//Deleter takes endpoint and endpointnamespace from pv spec.
pvSpec := d.spec.Spec
var dynamicEndpoint, dynamicNamespace string
if pvSpec.ClaimRef.Namespace != "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jsafrane I don't think of any empty namespace, but is any special meaning when we get an empty namespace?

@rootfs
Copy link
Contributor

rootfs commented Oct 17, 2016

@k8s-bot gci gce e2e test this

@humblec
Copy link
Contributor Author

humblec commented Oct 18, 2016

@rootfs @jsafrane looks like we need @k8s-bot gci gke e2e test this, Could you please help ?

@rootfs
Copy link
Contributor

rootfs commented Oct 18, 2016

@childsb ^^^

@childsb
Copy link
Contributor

childsb commented Oct 18, 2016

@k8s-bot gci gke e2e test this

@humblec
Copy link
Contributor Author

humblec commented Oct 18, 2016

@gnufied
Copy link
Member

gnufied commented Oct 18, 2016

This looks like #33388 flake.

@humblec
Copy link
Contributor Author

humblec commented Oct 18, 2016

Thanks @gnufied !

@childsb
Copy link
Contributor

childsb commented Oct 18, 2016

flake on #33388
@k8s-bot gce e2e test this

@humblec
Copy link
Contributor Author

humblec commented Oct 19, 2016

@rootfs @childsb Can you please tag this PR for retriggering the tests?

@humblec
Copy link
Contributor Author

humblec commented Oct 19, 2016

Looks like the GCE e2e tests are stuck on this , its running for >13 hours now.

@jsafrane
Copy link
Member

@k8s-bot test this issue: #IGNORE

@k8s-ci-robot
Copy link
Contributor

Jenkins verification failed for commit b5733fb828fece9ab232a1182090e397f9559491. Full PR test history.

The magic incantation to run this job again is @k8s-bot verify test this. Please help us cut down flakes by linking to an open flake issue when you hit one in your PR.

@jsafrane
Copy link
Member

@k8s-bot test this issue: #IGNORE

@humblec
Copy link
Contributor Author

humblec commented Oct 19, 2016

Thanks @jsafrane !!. The flake failure looks to be same which @gnufied mentioned.

@humblec
Copy link
Contributor Author

humblec commented Oct 19, 2016

@childsb @rootfs can you please approve this PR ?

@rootfs
Copy link
Contributor

rootfs commented Oct 19, 2016

lgtm, @jsafrane @childsb ?

var addrlist []string
if b.hosts == nil {
return fmt.Errorf("glusterfs: endpoint is nil")
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you do not need extra else branch after return above, you ca save yourself one indentation level.

if b.hosts == nil {
return fmt.Errorf("glusterfs: endpoint is nil")
} else {
addr := make(map[string]struct{})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addr seems not used, it's filled with addresses, is it read anywhere?


// Avoid mount storm, pick a host randomly.
// Iterate all hosts until mount succeeds.
for _, ip := range addrlist {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"pick a host randomly" - the code above does not look too much random

var dynamicEndpoint, dynamicNamespace string
if pvSpec.ClaimRef.Namespace != "" {
dynamicNamespace = pvSpec.ClaimRef.Namespace
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please check if pvSpec.ClaimRef is nil (and throw an error if it is) and throw an error when ClaimRef.Namespace is empty

}
_, err = p.plugin.host.GetKubeClient().Core().Endpoints(namespace).Create(endpoint)
if err != nil && errors.IsAlreadyExists(err) {
glog.V(1).Infof("glusterfs: endpoint %s already exist", endpoint)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please log also namespace when logging endpoint or service name (this applies to most of logging below)

}
glog.V(3).Infof("glusterfs: dynamic namespace and endpoint : [%v/%v]", dynamicNamespace, dynamicEndpoint)
//If there are no volumes exist in the cluster, the endpoint and svc
//will be deleted.
Copy link
Member

@jsafrane jsafrane Oct 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic is suspicious. Let there be two namespaces, nsA and nsB, both with one dynamically created endpoint, nsA/ep1 (used by pv1) and nsB/ep2 (used by pv2). Now, when pv1 is deleted, heketi returns that there is still a volume (pv2) in the cluster and nsA/ep1 is not deleted. Subsequently, when pv2 is deleted, heketi cluster is empty and ep2 is deleted.

ep1 is never deleted. Who/when is supposed to delete it? You should delete all these stray endpoints in all namespaces.

Also, at the time you check len(clusterinfo.Volumes) below, there may already be a new volume just created by another provisioning goroutine.

IMO, the safest (and race free) way is to create an endpoint/service for each provisioned PV. When you delete a PV, you always delete associated endpoint + service.

It could be possible to share one EP + service in a namespace for all PVs, however you need to be extra careful not to delete it in corner cases when a new PV is being provisioned and some old PV is being deleted at the same time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jsafrane for the review. Reg# creating an ep/svc for each PV, It was discussed that, it may be a tedious approach. Reg# the stale EPs in the some of the Namespaces, even today once the admin create an endpoint in one or more NS, he has to manually delete the ep/svc if not required. I am open to take any path though :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way, endpoints/services are deleted from some namespaces, while they are kept in others. It's IMO very bad user experience, it should behave consistently and it should be well documented.

@jsafrane
Copy link
Member

There are minor issues I can live with (logging, claimref check), however this PR will most probably create endpoints in user namespaces that nobody deletes when they are not needed. I'd rather have it done right instead of patching it later.

@k8s-github-robot k8s-github-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Oct 19, 2016
@k8s-github-robot k8s-github-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Oct 19, 2016
@jsafrane
Copy link
Member

@k8s-bot test this issue: #IGNORE

@k8s-ci-robot
Copy link
Contributor

Jenkins unit/integration failed for commit 5a60a5da2005fcc854210caa28eee5cd22db2de9. Full PR test history.

The magic incantation to run this job again is @k8s-bot unit test this. Please help us cut down flakes by linking to an open flake issue when you hit one in your PR.

@jsafrane
Copy link
Member

@k8s-bot test this issue: #IGNORE

@jsafrane jsafrane added sig/storage Categorizes an issue or PR as relevant to SIG Storage. team/cluster release-note-none Denotes a PR that doesn't merit a release note. and removed release-note-label-needed labels Oct 19, 2016
@k8s-ci-robot
Copy link
Contributor

Jenkins GCE etcd3 e2e failed for commit 7f9faef. Full PR test history.

The magic incantation to run this job again is @k8s-bot gce etcd3 e2e test this. Please help us cut down flakes by linking to an open flake issue when you hit one in your PR.

glog.Errorf("glusterfs: failed to delete service %s in namespace %s error %v", epServiceName, namespace, err)
return fmt.Errorf("error deleting service %v in namespace [%s]", err, namespace)
}
glog.V(1).Infof("glusterfs: service/endpoint [%s] in namespace [%s] deleted successfully", epServiceName, namespace)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we delete also the endpoint here? I know, it may be garbage collected automatically, however we created it, we should delete it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jsafrane at earlier patch set, I deleted ep followed with svc deletion. Then @rootfs suggested to remove service first. If we do so, endpoint is gone at the same moment. so only deleting svc now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@humblec @jsafrane removing service first can survive a sudden crash without leaking endpoint, since hanging endpoint is going to be cleaned up. But I would suggest removing endpoint as well - in case next time the endpoint is to be created and provisioner hit the line and prematurely exit without creating service.

    _, err = p.plugin.host.GetKubeClient().Core().Endpoints(namespace).Create(endpoint)
    if err != nil && errors.IsAlreadyExists(err) 

Copy link
Contributor Author

@humblec humblec Oct 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rootfs if we delete the svc first, the ep is gone at the same moment and the very next line which is delete endpoint give error saying non existence of ep. so I kept only svc deletion. Also when we delete svc from commandline, the ep is deleted internally. afaict, we only need to delete svc.

return nil, nil, fmt.Errorf("error creating endpoint %v", err)
}
service = &api.Service{
ObjectMeta: api.ObjectMeta{Name: epServiceName, Namespace: namespace},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add gluster.kubernetes.io/provisioned-for-pvc label to Service

return nil, 0, fmt.Errorf("no hosts found %v", err)
}

// The 'endpointname' is created in form of 'cluster-<id>' where 'id' is the cluster id.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cluster-<id> is no longer used

Signed-off-by: Humble Chirammal <hchiramm@redhat.com>
@jsafrane
Copy link
Member

@k8s-bot test this issue: #IGNORE

@jsafrane
Copy link
Member

lgtm

@jsafrane jsafrane added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Oct 19, 2016
@k8s-ci-robot
Copy link
Contributor

Jenkins GCI GKE smoke e2e failed for commit 0d080f9. Full PR test history.

The magic incantation to run this job again is @k8s-bot gci gke e2e test this. Please help us cut down flakes by linking to an open flake issue when you hit one in your PR.

@k8s-github-robot
Copy link

Automatic merge from submit-queue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lgtm "Looks good to me", indicates that a PR is ready to be merged. release-note-none Denotes a PR that doesn't merit a release note. sig/storage Categorizes an issue or PR as relevant to SIG Storage. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants