Skip to content
This repository has been archived by the owner on Mar 11, 2021. It is now read-only.

Commit

Permalink
deletes pipelines on space removal
Browse files Browse the repository at this point in the history
pipelines doesnt get deleted while removing a space
which leaves dangling pipelines in OpenShift.

This patch deletes the pipelines while removing a
space

Patch adds
- REST API to delete pipeline by space label
- Test cases for delete pipeline(buildconfig) function
- Delete BuildConfig API in OpenShift client
- Test cases for delete BuildConfig API
- Refactors kubernetes_client to get client objects
- Fixes delete OpenShift resources tests

Fixes
 -openshiftio/openshift.io#3802
  • Loading branch information
hrishin committed Nov 21, 2018
1 parent 539f671 commit 165ab7a
Show file tree
Hide file tree
Showing 15 changed files with 970 additions and 149 deletions.
120 changes: 2 additions & 118 deletions controller/deployments.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"context"
"encoding/json"
"io"
"net/url"
"os"
"time"

"github.com/fabric8-services/fabric8-wit/app"
Expand All @@ -17,10 +15,10 @@ import (

"github.com/goadesign/goa"
errs "github.com/pkg/errors"
uuid "github.com/satori/go.uuid"
"github.com/satori/go.uuid"
"golang.org/x/net/websocket"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/tools/cache"
)

Expand All @@ -31,17 +29,6 @@ type DeploymentsController struct {
ClientGetter
}

// ClientGetter creates an instances of clients used by this controller
type ClientGetter interface {
GetKubeClient(ctx context.Context) (kubernetes.KubeClientInterface, error)
GetAndCheckOSIOClient(ctx context.Context) (OpenshiftIOClient, error)
}

// Default implementation of KubeClientGetter and OSIOClientGetter used by NewDeploymentsController
type defaultClientGetter struct {
config *configuration.Registry
}

// NewDeploymentsController creates a deployments controller.
func NewDeploymentsController(service *goa.Service, config *configuration.Registry) *DeploymentsController {
return &DeploymentsController{
Expand All @@ -61,41 +48,6 @@ func tostring(item interface{}) string {
return string(bytes)
}

func (g *defaultClientGetter) GetAndCheckOSIOClient(ctx context.Context) (OpenshiftIOClient, error) {

// defaults
host := "localhost"
scheme := "https"

req := goa.ContextRequest(ctx)
if req != nil {
// Note - it's probably more efficient to force a loopback host, and only use the port number here
// (on some systems using a non-loopback interface forces a network stack traverse)
host = req.Host
scheme = req.URL.Scheme
}

// The deployments API communicates with the rest of WIT via the stnadard WIT API.
// This environment variable is used for local development of the deployments API, to point ot a remote WIT.
witURLStr := os.Getenv("FABRIC8_WIT_API_URL")
if witURLStr != "" {
witurl, err := url.Parse(witURLStr)
if err != nil {
log.Error(ctx, map[string]interface{}{
"FABRIC8_WIT_API_URL": witURLStr,
"err": err,
}, "cannot parse FABRIC8_WIT_API_URL: %s", witURLStr)
return nil, errs.Wrapf(err, "cannot parse FABRIC8_WIT_API_URL: %s", witURLStr)
}
host = witurl.Host
scheme = witurl.Scheme
}

oc := NewOSIOClient(ctx, scheme, host)

return oc, nil
}

// getSpaceNameFromSpaceID() converts an OSIO Space UUID to an OpenShift space name.
// will return an error if the space is not found.
func (c *DeploymentsController) getSpaceNameFromSpaceID(ctx context.Context, spaceID uuid.UUID) (*string, error) {
Expand All @@ -116,74 +68,6 @@ func (c *DeploymentsController) getSpaceNameFromSpaceID(ctx context.Context, spa
return osioSpace.Attributes.Name, nil
}

func (g *defaultClientGetter) getNamespaceName(ctx context.Context) (*string, error) {

osioclient, err := g.GetAndCheckOSIOClient(ctx)
if err != nil {
return nil, err
}

kubeSpaceAttr, err := osioclient.GetNamespaceByType(ctx, nil, "user")
if err != nil {
return nil, errs.Wrap(err, "unable to retrieve 'user' namespace")
}
if kubeSpaceAttr == nil {
return nil, errors.NewNotFoundError("namespace", "user")
}

return kubeSpaceAttr.Name, nil
}

// GetKubeClient creates a kube client for the appropriate cluster assigned to the current user
func (g *defaultClientGetter) GetKubeClient(ctx context.Context) (kubernetes.KubeClientInterface, error) {

kubeNamespaceName, err := g.getNamespaceName(ctx)
if err != nil {
log.Error(ctx, map[string]interface{}{
"err": err,
}, "could not retrieve namespace name")
return nil, errs.Wrap(err, "could not retrieve namespace name")
}

osioclient, err := g.GetAndCheckOSIOClient(ctx)
if err != nil {
log.Error(ctx, map[string]interface{}{
"err": err,
}, "could not create OSIO client")
return nil, err
}

baseURLProvider, err := NewURLProvider(ctx, g.config, osioclient)
if err != nil {
log.Error(ctx, map[string]interface{}{
"err": err,
}, "could not retrieve tenant data")
return nil, errs.Wrap(err, "could not retrieve tenant data")
}

/* Timeout used per HTTP request to Kubernetes/OpenShift API servers.
* Communication with Hawkular currently uses a hard-coded 30 second
* timeout per request, and does not use this parameter. */
// create the cluster API client
kubeConfig := &kubernetes.KubeClientConfig{
BaseURLProvider: baseURLProvider,
UserNamespace: *kubeNamespaceName,
Timeout: g.config.GetDeploymentsHTTPTimeoutSeconds(),
}
kc, err := kubernetes.NewKubeClient(kubeConfig)
if err != nil {
url, _ := baseURLProvider.GetAPIURL()
log.Error(ctx, map[string]interface{}{
"err": err,
"user_namespace": *kubeNamespaceName,
"cluster": *url,
}, "could not create Kubernetes client object")
return nil, errs.Wrap(err, "could not create Kubernetes client object")
}
return kc, nil
}

// SetDeployment runs the setDeployment action.
func (c *DeploymentsController) SetDeployment(ctx *app.SetDeploymentDeploymentsContext) error {

// we double check podcount here, because in the future we might have different query parameters
Expand Down
11 changes: 11 additions & 0 deletions controller/deployments_blackbox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ type testOSIOClient struct {
controller.OpenshiftIOClient
}

type testOSClient struct {
fixture *deploymentsTestFixture
kubernetes.OpenShiftRESTAPI
}

func (kc *testKubeClient) Close() {
kc.closed = true
}
Expand Down Expand Up @@ -97,6 +102,12 @@ func (fixture *deploymentsTestFixture) GetAndCheckOSIOClient(ctx context.Context
}, nil
}

func (fixture *deploymentsTestFixture) GetOSClient(ctx context.Context) (kubernetes.OpenShiftRESTAPI, error) {
return &testOSClient {
fixture: fixture,
}, nil
}

func (c *testOSIOClient) GetSpaceByID(ctx context.Context, spaceID uuid.UUID) (*app.Space, error) {
var spaceName *string
uuidString := spaceID.String()
Expand Down
64 changes: 64 additions & 0 deletions controller/pipelines.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package controller

import (
"github.com/goadesign/goa"
errs "github.com/pkg/errors"
"github.com/fabric8-services/fabric8-wit/configuration"
"github.com/fabric8-services/fabric8-wit/app"
"github.com/fabric8-services/fabric8-wit/jsonapi"
"github.com/fabric8-services/fabric8-wit/log"
"github.com/fabric8-services/fabric8-wit/errors"
)

// pipeline implements the pipeline resource.
type PipelinesController struct {
*goa.Controller
Config *configuration.Registry
ClientGetter
}

func NewPipelineController(service *goa.Service, config *configuration.Registry) *PipelinesController {
return &PipelinesController{
Controller: service.NewController("PipelinesController"),
Config: config,
ClientGetter: &defaultClientGetter{
config: config,
},
}
}

// Delete a pipelines from given space
func (c *PipelinesController) Delete(ctx *app.DeletePipelinesContext) error {

osioClient, err := c.GetAndCheckOSIOClient(ctx)
if err != nil {
return jsonapi.JSONErrorResponse(ctx, err)
}

k8sSpace, err := osioClient.GetNamespaceByType(ctx, nil, "user")
if err != nil {
return jsonapi.JSONErrorResponse(ctx, errs.Wrap(err, "unable to retrieve 'user' namespace"))
}
if k8sSpace == nil {
return jsonapi.JSONErrorResponse(ctx, errors.NewNotFoundError("namespace", "user"))
}

osc, err := c.GetOSClient(ctx)
if err != nil {
return jsonapi.JSONErrorResponse(ctx, err)
}

userNS := *k8sSpace.Name
resp, err := osc.DeleteBuildConfig(userNS, map[string]string{"space": ctx.Space})
if err != nil {
log.Error(ctx, map[string]interface{}{
"err": err,
"space_name": ctx.Space,
}, "error occurred while deleting pipeline")
return jsonapi.JSONErrorResponse(ctx, err)
}

log.Info(ctx, map[string]interface{}{"response": resp}, "deleted pipelines :")

return ctx.OK([]byte{})
}
Loading

0 comments on commit 165ab7a

Please sign in to comment.