Parcourir la source

Merge pull request #2165 from porter-dev/rudimk/infra-eks-dropdown

rudimk/infra-eks-dropdown -> dev
Rudi MK il y a 3 ans
Parent
commit
7b10a6a9a1

+ 115 - 0
api/server/handlers/cluster_integration/aws/get_cluster_info.go

@@ -0,0 +1,115 @@
+package aws
+
+import (
+	"errors"
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/service/ec2"
+	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+	"gorm.io/gorm"
+)
+
+type GetClusterInfoHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewGetClusterInfoHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *GetClusterInfoHandler {
+	return &GetClusterInfoHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (c *GetClusterInfoHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+
+	if cluster.AWSIntegrationID == 0 {
+		c.HandleAPIError(w, r, apierrors.NewErrForbidden(fmt.Errorf("no AWS cluster found with cluster ID: %d", cluster.ID)))
+		return
+	}
+
+	awsInt, err := c.Repo().AWSIntegration().ReadAWSIntegration(proj.ID, cluster.AWSIntegrationID)
+
+	if err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			c.HandleAPIError(w, r, apierrors.NewErrNotFound(fmt.Errorf("no AWS integration found with project ID: %d and "+
+				"integration ID: %d", proj.ID, cluster.AWSIntegrationID)))
+			return
+		}
+
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error fetching AWS integration with project ID: %d and "+
+			"integration ID: %d. Error: %w", proj.ID, cluster.AWSIntegrationID, err)))
+		return
+	}
+
+	awsSession, err := awsInt.GetSession()
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("error fetching new session for AWS with "+
+			"project ID: %d and integration ID: %d. Error: %w", proj.ID, cluster.AWSIntegrationID, err), http.StatusConflict))
+		return
+	}
+
+	clusterName := cluster.Name
+
+	if strings.HasPrefix(clusterName, "arn:aws:eks:") {
+		parts := strings.Split(clusterName, "/")
+		clusterName = parts[len(parts)-1]
+	}
+
+	awsConf := aws.NewConfig()
+
+	if awsInt.AWSRegion != "" {
+		awsConf = awsConf.WithRegion(awsInt.AWSRegion)
+	}
+
+	eksSvc := eks.New(awsSession, awsConf)
+
+	clusterInfo, err := eksSvc.DescribeCluster(&eks.DescribeClusterInput{
+		Name: &clusterName,
+	})
+
+	if err != nil || clusterInfo.Cluster == nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	ec2Svc := ec2.New(awsSession, awsConf)
+
+	subnetsInfo, err := ec2Svc.DescribeSubnets(&ec2.DescribeSubnetsInput{
+		SubnetIds: clusterInfo.Cluster.ResourcesVpcConfig.SubnetIds,
+	})
+
+	if err != nil || len(subnetsInfo.Subnets) == 0 {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	res := &types.GetAWSClusterInfoResponse{
+		Name:       clusterName,
+		K8sVersion: *clusterInfo.Cluster.Version,
+		EKSVersion: *clusterInfo.Cluster.PlatformVersion,
+	}
+
+	for _, subnet := range subnetsInfo.Subnets {
+		res.Subnets = append(res.Subnets, &types.AWSSubnet{
+			AvailabilityZone:        *subnet.AvailabilityZone,
+			AvailableIPAddressCount: *subnet.AvailableIpAddressCount,
+		})
+	}
+
+	c.WriteResult(w, r, res)
+}

+ 12 - 0
api/server/handlers/infra/forms.go

@@ -408,6 +408,18 @@ tabs:
       required: true
       required: true
       placeholder: my-cluster
       placeholder: my-cluster
       variable: cluster_name
       variable: cluster_name
+    - type: select
+      label: EKS control plane version
+      variable: cluster_version
+      settings:
+        default: 1.20
+        options:
+        - label: 1.20
+          value: 1.20
+        - label: 1.21
+          value: 1.21
+        - label: 1.22
+          value: 1.22
     - type: number-input
     - type: number-input
       label: Minimum number of EC2 instances to create in the application autoscaling group.
       label: Minimum number of EC2 instances to create in the application autoscaling group.
       variable: min_instances
       variable: min_instances

+ 45 - 36
api/server/handlers/webhook/github_incoming.go

@@ -77,31 +77,36 @@ func (c *GithubIncomingWebhookHandler) processPullRequestEvent(event *github.Pul
 		return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s] error reading environment: %w", webhookID, owner, repo, err)
 		return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s] error reading environment: %w", webhookID, owner, repo, err)
 	}
 	}
 
 
+	if event.GetPullRequest() == nil {
+		return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s] incoming webhook does not have pull request information: %w",
+			webhookID, owner, repo, err)
+	}
+
 	// create deployment on GitHub API
 	// create deployment on GitHub API
 	client, err := getGithubClientFromEnvironment(c.Config(), env)
 	client, err := getGithubClientFromEnvironment(c.Config(), env)
 
 
 	if err != nil {
 	if err != nil {
-		return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d] error getting github client: %w",
-			webhookID, owner, repo, env.ID, err)
+		return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d, prNumber: %d] "+
+			"error getting github client: %w", webhookID, owner, repo, env.ID, event.GetPullRequest().GetNumber(), err)
 	}
 	}
 
 
 	if env.Mode == "auto" && event.GetAction() == "opened" {
 	if env.Mode == "auto" && event.GetAction() == "opened" {
 		_, err := client.Actions.CreateWorkflowDispatchEventByFileName(
 		_, err := client.Actions.CreateWorkflowDispatchEventByFileName(
 			r.Context(), owner, repo, fmt.Sprintf("porter_%s_env.yml", env.Name),
 			r.Context(), owner, repo, fmt.Sprintf("porter_%s_env.yml", env.Name),
 			github.CreateWorkflowDispatchEventRequest{
 			github.CreateWorkflowDispatchEventRequest{
-				Ref: event.PullRequest.GetHead().GetRef(),
+				Ref: event.GetPullRequest().GetHead().GetRef(),
 				Inputs: map[string]interface{}{
 				Inputs: map[string]interface{}{
-					"pr_number":      strconv.FormatUint(uint64(event.PullRequest.GetNumber()), 10),
-					"pr_title":       event.PullRequest.GetTitle(),
-					"pr_branch_from": event.PullRequest.GetHead().GetRef(),
-					"pr_branch_into": event.PullRequest.GetBase().GetRef(),
+					"pr_number":      strconv.FormatUint(uint64(event.GetPullRequest().GetNumber()), 10),
+					"pr_title":       event.GetPullRequest().GetTitle(),
+					"pr_branch_from": event.GetPullRequest().GetHead().GetRef(),
+					"pr_branch_into": event.GetPullRequest().GetBase().GetRef(),
 				},
 				},
 			},
 			},
 		)
 		)
 
 
 		if err != nil {
 		if err != nil {
-			return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d] error creating workflow dispatch event: %w",
-				webhookID, owner, repo, env.ID, err)
+			return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d, prNumber: %d] "+
+				"error creating workflow dispatch event: %w", webhookID, owner, repo, env.ID, event.GetPullRequest().GetNumber(), err)
 		}
 		}
 	} else if event.GetAction() == "synchronize" || event.GetAction() == "closed" {
 	} else if event.GetAction() == "synchronize" || event.GetAction() == "closed" {
 		depl, err := c.Repo().Environment().ReadDeploymentByGitDetails(
 		depl, err := c.Repo().Environment().ReadDeploymentByGitDetails(
@@ -109,36 +114,40 @@ func (c *GithubIncomingWebhookHandler) processPullRequestEvent(event *github.Pul
 		)
 		)
 
 
 		if err != nil {
 		if err != nil {
-			return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d] error reading deployment: %w",
-				webhookID, owner, repo, env.ID, err)
+			return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d, prNumber: %d] "+
+				"error reading deployment: %w", webhookID, owner, repo, env.ID, event.GetPullRequest().GetNumber(), err)
+		}
+
+		if depl.Status == types.DeploymentStatusInactive {
+			return nil
 		}
 		}
 
 
-		if depl.Status != types.DeploymentStatusInactive {
-			if event.GetAction() == "synchronize" {
-				_, err := client.Actions.CreateWorkflowDispatchEventByFileName(
-					r.Context(), owner, repo, fmt.Sprintf("porter_%s_env.yml", env.Name),
-					github.CreateWorkflowDispatchEventRequest{
-						Ref: event.PullRequest.GetHead().GetRef(),
-						Inputs: map[string]interface{}{
-							"pr_number":      strconv.FormatUint(uint64(event.PullRequest.GetNumber()), 10),
-							"pr_title":       event.PullRequest.GetTitle(),
-							"pr_branch_from": event.PullRequest.GetHead().GetRef(),
-							"pr_branch_into": event.PullRequest.GetBase().GetRef(),
-						},
+		if event.GetAction() == "synchronize" {
+			_, err := client.Actions.CreateWorkflowDispatchEventByFileName(
+				r.Context(), owner, repo, fmt.Sprintf("porter_%s_env.yml", env.Name),
+				github.CreateWorkflowDispatchEventRequest{
+					Ref: event.GetPullRequest().GetHead().GetRef(),
+					Inputs: map[string]interface{}{
+						"pr_number":      strconv.FormatUint(uint64(event.GetPullRequest().GetNumber()), 10),
+						"pr_title":       event.GetPullRequest().GetTitle(),
+						"pr_branch_from": event.GetPullRequest().GetHead().GetRef(),
+						"pr_branch_into": event.GetPullRequest().GetBase().GetRef(),
 					},
 					},
-				)
-
-				if err != nil {
-					return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d, deploymentID: %d] error creating workflow dispatch event: %w",
-						webhookID, owner, repo, env.ID, depl.ID, err)
-				}
-			} else {
-				err = c.deleteDeployment(r, depl, env, client)
-
-				if err != nil {
-					return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d, deploymentID: %d] error deleting deployment: %w",
-						webhookID, owner, repo, env.ID, depl.ID, err)
-				}
+				},
+			)
+
+			if err != nil {
+				return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d, deploymentID: %d, prNumber: %d] "+
+					"error creating workflow dispatch event: %w", webhookID, owner, repo, env.ID, depl.ID,
+					event.GetPullRequest().GetNumber(), err)
+			}
+		} else {
+			err = c.deleteDeployment(r, depl, env, client)
+
+			if err != nil {
+				return fmt.Errorf("[webhookID: %s, owner: %s, repo: %s, environmentID: %d, deploymentID: %d, prNumber: %d] "+
+					"error deleting deployment: %w", webhookID, owner, repo, env.ID, depl.ID,
+					event.GetPullRequest().GetNumber(), err)
 			}
 			}
 		}
 		}
 	}
 	}

+ 86 - 0
api/server/router/cluster_integration.go

@@ -0,0 +1,86 @@
+package router
+
+import (
+	"github.com/go-chi/chi"
+	awsClusterInt "github.com/porter-dev/porter/api/server/handlers/cluster_integration/aws"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/server/shared/router"
+	"github.com/porter-dev/porter/api/types"
+)
+
+func NewClusterIntegrationScopedRegisterer(children ...*router.Registerer) *router.Registerer {
+	return &router.Registerer{
+		GetRoutes: GetClusterIntegrationScopedRoutes,
+		Children:  children,
+	}
+}
+
+func GetClusterIntegrationScopedRoutes(
+	r chi.Router,
+	config *config.Config,
+	basePath *types.Path,
+	factory shared.APIEndpointFactory,
+	children ...*router.Registerer,
+) []*router.Route {
+	routes, projPath := getClusterIntegrationRoutes(r, config, basePath, factory)
+
+	if len(children) > 0 {
+		r.Route(projPath.RelativePath, func(r chi.Router) {
+			for _, child := range children {
+				childRoutes := child.GetRoutes(r, config, basePath, factory, child.Children...)
+
+				routes = append(routes, childRoutes...)
+			}
+		})
+	}
+
+	return routes
+}
+
+func getClusterIntegrationRoutes(
+	r chi.Router,
+	config *config.Config,
+	basePath *types.Path,
+	factory shared.APIEndpointFactory,
+) ([]*router.Route, *types.Path) {
+	relPath := "/integrations"
+
+	newPath := &types.Path{
+		Parent:       basePath,
+		RelativePath: relPath,
+	}
+
+	routes := make([]*router.Route, 0)
+
+	// GET /api/projects/{project_id}/clusters/{cluster_id}/integrations/aws/info -> awsClusterInt.NewGetClusterInfoHandler
+	getAWSClusterInfoEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/aws/info",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+			},
+		},
+	)
+
+	getAWSClusterInfoHandler := awsClusterInt.NewGetClusterInfoHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &router.Route{
+		Endpoint: getAWSClusterInfoEndpoint,
+		Handler:  getAWSClusterInfoHandler,
+		Router:   r,
+	})
+
+	return routes, newPath
+}

+ 2 - 1
api/server/router/router.go

@@ -29,7 +29,8 @@ func NewAPIRouter(config *config.Config) *chi.Mux {
 
 
 	releaseRegisterer := NewReleaseScopedRegisterer()
 	releaseRegisterer := NewReleaseScopedRegisterer()
 	namespaceRegisterer := NewNamespaceScopedRegisterer(releaseRegisterer)
 	namespaceRegisterer := NewNamespaceScopedRegisterer(releaseRegisterer)
-	clusterRegisterer := NewClusterScopedRegisterer(namespaceRegisterer)
+	clusterIntegrationRegisterer := NewClusterIntegrationScopedRegisterer()
+	clusterRegisterer := NewClusterScopedRegisterer(namespaceRegisterer, clusterIntegrationRegisterer)
 	infraRegisterer := NewInfraScopedRegisterer()
 	infraRegisterer := NewInfraScopedRegisterer()
 	gitInstallationRegisterer := NewGitInstallationScopedRegisterer()
 	gitInstallationRegisterer := NewGitInstallationScopedRegisterer()
 	registryRegisterer := NewRegistryScopedRegisterer()
 	registryRegisterer := NewRegistryScopedRegisterer()

+ 13 - 0
api/types/cluster_integration.go

@@ -0,0 +1,13 @@
+package types
+
+type AWSSubnet struct {
+	AvailabilityZone        string `json:"availability_zone"`
+	AvailableIPAddressCount int64  `json:"available_ip_address_count"`
+}
+
+type GetAWSClusterInfoResponse struct {
+	Name       string       `json:"name"`
+	K8sVersion string       `json:"kubernetes_server_version"`
+	EKSVersion string       `json:"eks_version"`
+	Subnets    []*AWSSubnet `json:"subnets"`
+}

+ 9 - 0
cli/cmd/deploy/deploy.go

@@ -345,6 +345,15 @@ func (d *DeployAgent) Push() error {
 // reuses the configuration set for the application. If overrideValues is not nil,
 // reuses the configuration set for the application. If overrideValues is not nil,
 // it will merge the overriding values with the existing configuration.
 // it will merge the overriding values with the existing configuration.
 func (d *DeployAgent) UpdateImageAndValues(overrideValues map[string]interface{}) error {
 func (d *DeployAgent) UpdateImageAndValues(overrideValues map[string]interface{}) error {
+	// we should fetch the latest release and its config
+	release, err := d.Client.GetRelease(context.TODO(), d.Opts.ProjectID, d.Opts.ClusterID, d.Opts.Namespace, d.App)
+
+	if err != nil {
+		return err
+	}
+
+	d.Release = release
+
 	// if this is a job chart, set "paused" to false so that the job doesn't run, unless
 	// if this is a job chart, set "paused" to false so that the job doesn't run, unless
 	// the user has explicitly overriden the "paused" field
 	// the user has explicitly overriden the "paused" field
 	if _, exists := overrideValues["paused"]; d.Release.Chart.Name() == "job" && !exists {
 	if _, exists := overrideValues["paused"]; d.Release.Chart.Name() == "job" && !exists {

+ 17 - 12
internal/helm/agent.go

@@ -112,21 +112,26 @@ func (a *Agent) GetRelease(
 
 
 	if getDeps && release.Chart != nil && release.Chart.Metadata != nil {
 	if getDeps && release.Chart != nil && release.Chart.Metadata != nil {
 		for _, dep := range release.Chart.Metadata.Dependencies {
 		for _, dep := range release.Chart.Metadata.Dependencies {
-			depExists := false
-
-			for _, currDep := range release.Chart.Dependencies() {
-				// we just case on name for now -- there might be edge cases we're missing
-				// but this will cover 99% of cases
-				if dep != nil && currDep != nil && dep.Name == currDep.Name() {
-					depExists = true
-					break
+			// only search for dependency if it passes the condition specified in Chart.yaml
+			if dep.Enabled {
+				depExists := false
+
+				for _, currDep := range release.Chart.Dependencies() {
+					// we just case on name for now -- there might be edge cases we're missing
+					// but this will cover 99% of cases
+					if dep != nil && currDep != nil && dep.Name == currDep.Name() {
+						depExists = true
+						break
+					}
 				}
 				}
-			}
 
 
-			if !depExists {
-				depChart, err := loader.LoadChartPublic(dep.Repository, dep.Name, dep.Version)
+				if !depExists {
+					depChart, err := loader.LoadChartPublic(dep.Repository, dep.Name, dep.Version)
+
+					if err != nil {
+						return nil, fmt.Errorf("Error retrieving chart dependency %s/%s-%s: %s", dep.Repository, dep.Name, dep.Version, err.Error())
+					}
 
 
-				if err == nil {
 					release.Chart.AddDependency(depChart)
 					release.Chart.AddDependency(depChart)
 				}
 				}
 			}
 			}

+ 1 - 1
internal/helm/config.go

@@ -81,7 +81,7 @@ func GetAgentFromK8sAgent(stg string, ns string, l *logger.Logger, k8sAgent *kub
 // the underlying kubernetes.GetAgentInClusterConfig method
 // the underlying kubernetes.GetAgentInClusterConfig method
 func GetAgentInClusterConfig(form *Form, l *logger.Logger) (*Agent, error) {
 func GetAgentInClusterConfig(form *Form, l *logger.Logger) (*Agent, error) {
 	// create a kubernetes agent
 	// create a kubernetes agent
-	k8sAgent, err := kubernetes.GetAgentInClusterConfig()
+	k8sAgent, err := kubernetes.GetAgentInClusterConfig(form.Namespace)
 
 
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err

+ 8 - 4
internal/kubernetes/config.go

@@ -59,7 +59,7 @@ func GetDynamicClientOutOfClusterConfig(conf *OutOfClusterConfig) (dynamic.Inter
 // GetAgentOutOfClusterConfig creates a new Agent using the OutOfClusterConfig
 // GetAgentOutOfClusterConfig creates a new Agent using the OutOfClusterConfig
 func GetAgentOutOfClusterConfig(conf *OutOfClusterConfig) (*Agent, error) {
 func GetAgentOutOfClusterConfig(conf *OutOfClusterConfig) (*Agent, error) {
 	if conf.AllowInClusterConnections && conf.Cluster.AuthMechanism == models.InCluster {
 	if conf.AllowInClusterConnections && conf.Cluster.AuthMechanism == models.InCluster {
-		return GetAgentInClusterConfig()
+		return GetAgentInClusterConfig(conf.DefaultNamespace)
 	}
 	}
 
 
 	restConf, err := conf.ToRESTConfig()
 	restConf, err := conf.ToRESTConfig()
@@ -89,14 +89,14 @@ func IsInCluster() bool {
 
 
 // GetAgentInClusterConfig uses the service account that kubernetes
 // GetAgentInClusterConfig uses the service account that kubernetes
 // gives to pods to connect
 // gives to pods to connect
-func GetAgentInClusterConfig() (*Agent, error) {
+func GetAgentInClusterConfig(namespace string) (*Agent, error) {
 	conf, err := rest.InClusterConfig()
 	conf, err := rest.InClusterConfig()
 
 
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	restClientGetter := NewRESTClientGetterFromInClusterConfig(conf)
+	restClientGetter := NewRESTClientGetterFromInClusterConfig(conf, namespace)
 	clientset, err := kubernetes.NewForConfig(conf)
 	clientset, err := kubernetes.NewForConfig(conf)
 
 
 	return &Agent{restClientGetter, clientset}, nil
 	return &Agent{restClientGetter, clientset}, nil
@@ -419,9 +419,13 @@ func (conf *OutOfClusterConfig) setTokenCache(token string, expiry time.Time) er
 
 
 // NewRESTClientGetterFromInClusterConfig returns a RESTClientGetter using
 // NewRESTClientGetterFromInClusterConfig returns a RESTClientGetter using
 // default values set from the *rest.Config
 // default values set from the *rest.Config
-func NewRESTClientGetterFromInClusterConfig(conf *rest.Config) genericclioptions.RESTClientGetter {
+func NewRESTClientGetterFromInClusterConfig(conf *rest.Config, namespace string) genericclioptions.RESTClientGetter {
 	cfs := genericclioptions.NewConfigFlags(false)
 	cfs := genericclioptions.NewConfigFlags(false)
 
 
+	if namespace != "" {
+		cfs.Namespace = &namespace
+	}
+
 	cfs.ClusterName = &conf.ServerName
 	cfs.ClusterName = &conf.ServerName
 	cfs.Insecure = &conf.Insecure
 	cfs.Insecure = &conf.Insecure
 	cfs.APIServer = &conf.Host
 	cfs.APIServer = &conf.Host

+ 8 - 1
internal/kubernetes/local/kubeconfig.go

@@ -80,7 +80,14 @@ func GetSelfAgentFromFileConfig(kubeconfigPath string) (*kubernetes.Agent, error
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	restClientGetter := kubernetes.NewRESTClientGetterFromInClusterConfig(restConf)
+	var namespace string
+	cmdConfNamespace, _, err := cmdConf.Namespace()
+
+	if err == nil && cmdConfNamespace != "" {
+		namespace = cmdConfNamespace
+	}
+
+	restClientGetter := kubernetes.NewRESTClientGetterFromInClusterConfig(restConf, namespace)
 	clientset, err := k8s.NewForConfig(restConf)
 	clientset, err := k8s.NewForConfig(restConf)
 
 
 	return &kubernetes.Agent{
 	return &kubernetes.Agent{

+ 1 - 1
provisioner/server/config/config.go

@@ -248,7 +248,7 @@ func getProvisionerAgent(conf *ProvisionerConf) (*kubernetes.Agent, error) {
 		return nil, fmt.Errorf(`"kubeconfig" cluster option requires path to kubeconfig`)
 		return nil, fmt.Errorf(`"kubeconfig" cluster option requires path to kubeconfig`)
 	}
 	}
 
 
-	agent, _ := kubernetes.GetAgentInClusterConfig()
+	agent, _ := kubernetes.GetAgentInClusterConfig(conf.ProvisionerJobNamespace)
 
 
 	return agent, nil
 	return agent, nil
 }
 }