func TestErrors(t *testing.T) {
	oc, _, _ := NewErrorClients(errors.NewNotFound(deployapi.Resource("DeploymentConfigList"), ""))
	_, err := oc.DeploymentConfigs("test").List(kapi.ListOptions{})
	if !errors.IsNotFound(err) {
		t.Fatalf("unexpected error: %v", err)
	}

	oc, _, _ = NewErrorClients(errors.NewForbidden(deployapi.Resource("DeploymentConfigList"), "", nil))
	_, err = oc.DeploymentConfigs("test").List(kapi.ListOptions{})
	if !errors.IsForbidden(err) {
		t.Fatalf("unexpected error: %v", err)
	}
}
Exemple #2
0
// NewREST returns a deploymentConfigREST containing the REST storage for DeploymentConfig objects,
// a statusREST containing the REST storage for changing the status of a DeploymentConfig,
// and a scaleREST containing the REST storage for the Scale subresources of DeploymentConfigs.
func NewREST(optsGetter restoptions.Getter) (*REST, *StatusREST, *ScaleREST, error) {
	store := &registry.Store{
		NewFunc:           func() runtime.Object { return &api.DeploymentConfig{} },
		NewListFunc:       func() runtime.Object { return &api.DeploymentConfigList{} },
		QualifiedResource: api.Resource("deploymentconfigs"),
		ObjectNameFunc: func(obj runtime.Object) (string, error) {
			return obj.(*api.DeploymentConfig).Name, nil
		},
		PredicateFunc: func(label labels.Selector, field fields.Selector) storage.SelectionPredicate {
			return deployconfig.Matcher(label, field)
		},
		CreateStrategy:      deployconfig.Strategy,
		UpdateStrategy:      deployconfig.Strategy,
		DeleteStrategy:      deployconfig.Strategy,
		ReturnDeletedObject: false,
	}

	if err := restoptions.ApplyOptions(optsGetter, store, true, storage.NoTriggerPublisher); err != nil {
		return nil, nil, nil, err
	}

	deploymentConfigREST := &REST{store}
	statusStore := *store
	statusStore.UpdateStrategy = deployconfig.StatusStrategy
	statusREST := &StatusREST{store: &statusStore}
	scaleREST := &ScaleREST{registry: deployconfig.NewRegistry(deploymentConfigREST)}

	return deploymentConfigREST, statusREST, scaleREST, nil
}
Exemple #3
0
func AddHPAScaleRefEdges(g osgraph.Graph) {
	for _, node := range g.NodesByKind(kubegraph.HorizontalPodAutoscalerNodeKind) {
		hpaNode := node.(*kubegraph.HorizontalPodAutoscalerNode)

		syntheticMeta := kapi.ObjectMeta{
			Name:      hpaNode.HorizontalPodAutoscaler.Spec.ScaleRef.Name,
			Namespace: hpaNode.HorizontalPodAutoscaler.Namespace,
		}

		var groupVersionResource unversioned.GroupVersionResource
		resource := strings.ToLower(hpaNode.HorizontalPodAutoscaler.Spec.ScaleRef.Kind)
		if groupVersion, err := unversioned.ParseGroupVersion(hpaNode.HorizontalPodAutoscaler.Spec.ScaleRef.APIVersion); err == nil {
			groupVersionResource = groupVersion.WithResource(resource)
		} else {
			groupVersionResource = unversioned.GroupVersionResource{Resource: resource}
		}

		groupVersionResource, err := registered.RESTMapper().ResourceFor(groupVersionResource)
		if err != nil {
			continue
		}

		var syntheticNode graph.Node
		switch groupVersionResource.GroupResource() {
		case kapi.Resource("replicationcontrollers"):
			syntheticNode = kubegraph.FindOrCreateSyntheticReplicationControllerNode(g, &kapi.ReplicationController{ObjectMeta: syntheticMeta})
		case deployapi.Resource("deploymentconfigs"):
			syntheticNode = deploygraph.FindOrCreateSyntheticDeploymentConfigNode(g, &deployapi.DeploymentConfig{ObjectMeta: syntheticMeta})
		default:
			continue
		}

		g.AddEdge(hpaNode, syntheticNode, ScalingEdgeKind)
	}
}
func TestCreateMissingDeploymentConfigDepr(t *testing.T) {
	rest := DeprecatedREST{
		generator: Client{
			GRFn: func(from, to *deployapi.DeploymentConfig, spec *deployapi.DeploymentConfigRollbackSpec) (*deployapi.DeploymentConfig, error) {
				t.Fatal("unexpected call to generator")
				return nil, errors.New("something terrible happened")
			},
			RCFn: func(ctx kapi.Context, name string) (*kapi.ReplicationController, error) {
				deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
				return deployment, nil
			},
			DCFn: func(ctx kapi.Context, name string) (*deployapi.DeploymentConfig, error) {
				return nil, kerrors.NewNotFound(deployapi.Resource("deploymentConfig"), name)
			},
		},
		codec: kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion),
	}

	obj, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{
		Spec: deployapi.DeploymentConfigRollbackSpec{
			From: kapi.ObjectReference{
				Name:      "deployment",
				Namespace: kapi.NamespaceDefault,
			},
		},
	})

	if err == nil {
		t.Errorf("Expected an error")
	}

	if obj != nil {
		t.Error("Unexpected result obj")
	}
}
Exemple #5
0
func printDeploymentConfigSpec(kc kclient.Interface, dc deployapi.DeploymentConfig, w *tabwriter.Writer) error {
	spec := dc.Spec
	// Selector
	formatString(w, "Selector", formatLabels(spec.Selector))

	// Replicas
	test := ""
	if spec.Test {
		test = " (test, will be scaled down between deployments)"
	}
	formatString(w, "Replicas", fmt.Sprintf("%d%s", spec.Replicas, test))

	// Autoscaling info
	printAutoscalingInfo(deployapi.Resource("DeploymentConfig"), dc.Namespace, dc.Name, kc, w)

	// Triggers
	printTriggers(spec.Triggers, w)

	// Strategy
	formatString(w, "Strategy", spec.Strategy.Type)
	printStrategy(spec.Strategy, "  ", w)

	if dc.Spec.MinReadySeconds > 0 {
		formatString(w, "MinReadySeconds", fmt.Sprintf("%d", spec.MinReadySeconds))
	}

	// Pod template
	fmt.Fprintf(w, "Template:\n")
	kctl.DescribePodTemplate(spec.Template, w)

	return nil
}
Exemple #6
0
func TestCreateMissingDeploymentConfig(t *testing.T) {
	oc := &testclient.Fake{}
	oc.AddReactor("get", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
		dc := deploytest.OkDeploymentConfig(2)
		return true, nil, kerrors.NewNotFound(deployapi.Resource("deploymentConfig"), dc.Name)
	})
	kc := &ktestclient.Fake{}
	kc.AddReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
		deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), codec)
		return true, deployment, nil
	})

	obj, err := NewREST(oc, kc, codec).Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{
		Name: "config",
		Spec: deployapi.DeploymentConfigRollbackSpec{
			Revision: 1,
		},
	})

	if err == nil {
		t.Errorf("Expected an error")
	}

	if obj != nil {
		t.Error("Unexpected result obj")
	}
}
Exemple #7
0
// NewStorage returns a DeploymentConfigStorage containing the REST storage for
// DeploymentConfig objects and their Scale subresources.
func NewREST(s storage.Interface, rcNamespacer kclient.ReplicationControllersNamespacer) (*REST, *ScaleREST) {
	prefix := "/deploymentconfigs"

	store := &etcdgeneric.Etcd{
		NewFunc:           func() runtime.Object { return &api.DeploymentConfig{} },
		NewListFunc:       func() runtime.Object { return &api.DeploymentConfigList{} },
		QualifiedResource: api.Resource("deploymentconfigs"),
		KeyRootFunc: func(ctx kapi.Context) string {
			return etcdgeneric.NamespaceKeyRootFunc(ctx, prefix)
		},
		KeyFunc: func(ctx kapi.Context, id string) (string, error) {
			return etcdgeneric.NamespaceKeyFunc(ctx, prefix, id)
		},
		ObjectNameFunc: func(obj runtime.Object) (string, error) {
			return obj.(*api.DeploymentConfig).Name, nil
		},
		PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher {
			return deployconfig.Matcher(label, field)
		},
		CreateStrategy:      deployconfig.Strategy,
		UpdateStrategy:      deployconfig.Strategy,
		DeleteStrategy:      deployconfig.Strategy,
		ReturnDeletedObject: false,
		Storage:             s,
	}

	deploymentConfigREST := &REST{store}
	scaleREST := &ScaleREST{
		registry:     deployconfig.NewRegistry(deploymentConfigREST),
		rcNamespacer: rcNamespacer,
	}

	return deploymentConfigREST, scaleREST
}
Exemple #8
0
func TestErrors(t *testing.T) {
	o := testclient.NewObjects(kapi.Scheme, kapi.Codecs.UniversalDecoder())
	o.Add(&kapi.List{
		Items: []runtime.Object{
			&(errors.NewNotFound(deployapi.Resource("DeploymentConfigList"), "").ErrStatus),
			&(errors.NewForbidden(deployapi.Resource("DeploymentConfigList"), "", nil).ErrStatus),
		},
	})
	oc, _ := NewFixtureClients(o)
	_, err := oc.DeploymentConfigs("test").List(kapi.ListOptions{})
	if !errors.IsNotFound(err) {
		t.Fatalf("unexpected error: %v", err)
	}
	t.Logf("error: %#v", err.(*errors.StatusError).Status())
	_, err = oc.DeploymentConfigs("test").List(kapi.ListOptions{})
	if !errors.IsForbidden(err) {
		t.Fatalf("unexpected error: %v", err)
	}
}
// Get retrieves the DeploymentConfig from the indexer for a given namespace and name.
func (s deploymentConfigNamespaceLister) Get(name string) (*api.DeploymentConfig, error) {
	obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
	if err != nil {
		return nil, err
	}
	if !exists {
		return nil, errors.NewNotFound(api.Resource("deploymentconfig"), name)
	}
	return obj.(*api.DeploymentConfig), nil
}
Exemple #10
0
// GetConfigForPod returns the managing deployment config for the provided pod.
func (s *StoreToDeploymentConfigLister) GetConfigForPod(pod *kapi.Pod) (*deployapi.DeploymentConfig, error) {
	dcName := deployutil.DeploymentConfigNameFor(pod)
	obj, exists, err := s.Indexer.GetByKey(pod.Namespace + "/" + dcName)
	if err != nil {
		return nil, err
	}
	if !exists {
		return nil, kapierrors.NewNotFound(deployapi.Resource("deploymentconfig"), dcName)
	}
	return obj.(*deployapi.DeploymentConfig), nil
}
func TestGenerate_fromMissingDeploymentConfig(t *testing.T) {
	generator := &DeploymentConfigGenerator{
		Client: Client{
			DCFn: func(ctx kapi.Context, id string) (*deployapi.DeploymentConfig, error) {
				return nil, kerrors.NewNotFound(deployapi.Resource("DeploymentConfig"), id)
			},
		},
	}

	config, err := generator.Generate(kapi.NewDefaultContext(), "1234")

	if config != nil {
		t.Fatalf("Unexpected DeploymentConfig generated: %#v", config)
	}

	if err == nil {
		t.Fatalf("Expected an error")
	}
}
func TestGenerate_reportsNotFoundErrorWhenMissingDeploymentConfig(t *testing.T) {
	generator := &DeploymentConfigGenerator{
		Client: Client{
			DCFn: func(ctx kapi.Context, name string) (*deployapi.DeploymentConfig, error) {
				return nil, kerrors.NewNotFound(deployapi.Resource("DeploymentConfig"), name)
			},
			ISFn: func(ctx kapi.Context, name string) (*imageapi.ImageStream, error) {
				return nil, kerrors.NewNotFound(imageapi.Resource("ImageStream"), name)
			},
		},
	}
	_, err := generator.Generate(kapi.NewDefaultContext(), "deploy1")
	if err == nil || !kerrors.IsNotFound(err) {
		t.Fatalf("Unexpected error type: %v", err)
	}
	if !strings.Contains(err.Error(), "DeploymentConfig \"deploy1\" not found") {
		t.Errorf("unexpected error message: %v", err)
	}
}
Exemple #13
0
// NewStorage returns a DeploymentConfigStorage containing the REST storage for
// DeploymentConfig objects and their Scale subresources.
func NewREST(optsGetter restoptions.Getter, rcNamespacer kclient.ReplicationControllersNamespacer) (*REST, *StatusREST, *ScaleREST, error) {
	prefix := "/deploymentconfigs"

	store := &registry.Store{
		NewFunc:           func() runtime.Object { return &api.DeploymentConfig{} },
		NewListFunc:       func() runtime.Object { return &api.DeploymentConfigList{} },
		QualifiedResource: api.Resource("deploymentconfigs"),
		KeyRootFunc: func(ctx kapi.Context) string {
			return registry.NamespaceKeyRootFunc(ctx, prefix)
		},
		KeyFunc: func(ctx kapi.Context, id string) (string, error) {
			return registry.NamespaceKeyFunc(ctx, prefix, id)
		},
		ObjectNameFunc: func(obj runtime.Object) (string, error) {
			return obj.(*api.DeploymentConfig).Name, nil
		},
		PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher {
			return deployconfig.Matcher(label, field)
		},
		CreateStrategy:      deployconfig.Strategy,
		UpdateStrategy:      deployconfig.Strategy,
		DeleteStrategy:      deployconfig.Strategy,
		ReturnDeletedObject: false,
	}

	if err := restoptions.ApplyOptions(optsGetter, store, prefix); err != nil {
		return nil, nil, nil, err
	}

	deploymentConfigREST := &REST{store}
	statusStore := *store
	statusStore.UpdateStrategy = deployconfig.StatusStrategy
	statusREST := &StatusREST{store: &statusStore}
	scaleREST := &ScaleREST{
		registry:     deployconfig.NewRegistry(deploymentConfigREST),
		rcNamespacer: rcNamespacer,
	}

	return deploymentConfigREST, statusREST, scaleREST, nil
}
Exemple #14
0
// Get returns a streamer resource with the contents of the deployment log
func (r *REST) Get(ctx kapi.Context, name string, opts runtime.Object) (runtime.Object, error) {
	// Ensure we have a namespace in the context
	namespace, ok := kapi.NamespaceFrom(ctx)
	if !ok {
		return nil, errors.NewBadRequest("namespace parameter required.")
	}

	// Validate DeploymentLogOptions
	deployLogOpts, ok := opts.(*deployapi.DeploymentLogOptions)
	if !ok {
		return nil, errors.NewBadRequest("did not get an expected options.")
	}
	if errs := validation.ValidateDeploymentLogOptions(deployLogOpts); len(errs) > 0 {
		return nil, errors.NewInvalid(deployapi.Kind("DeploymentLogOptions"), "", errs)
	}

	// Fetch deploymentConfig and check latest version; if 0, there are no deployments
	// for this config
	config, err := r.dn.DeploymentConfigs(namespace).Get(name)
	if err != nil {
		return nil, errors.NewNotFound(deployapi.Resource("deploymentconfig"), name)
	}
	desiredVersion := config.Status.LatestVersion
	if desiredVersion == 0 {
		return nil, errors.NewBadRequest(fmt.Sprintf("no deployment exists for deploymentConfig %q", config.Name))
	}

	// Support retrieving logs for older deployments
	switch {
	case deployLogOpts.Version == nil:
		// Latest or previous
		if deployLogOpts.Previous {
			desiredVersion--
			if desiredVersion < 1 {
				return nil, errors.NewBadRequest(fmt.Sprintf("no previous deployment exists for deploymentConfig %q", config.Name))
			}
		}
	case *deployLogOpts.Version <= 0 || *deployLogOpts.Version > config.Status.LatestVersion:
		// Invalid version
		return nil, errors.NewBadRequest(fmt.Sprintf("invalid version for deploymentConfig %q: %d", config.Name, *deployLogOpts.Version))
	default:
		desiredVersion = *deployLogOpts.Version
	}

	// Get desired deployment
	targetName := deployutil.DeploymentNameForConfigVersion(config.Name, desiredVersion)
	target, err := r.waitForExistingDeployment(namespace, targetName)
	if err != nil {
		return nil, err
	}
	podName := deployutil.DeployerPodNameForDeployment(target.Name)

	// Check for deployment status; if it is new or pending, we will wait for it. If it is complete,
	// the deployment completed successfully and the deployer pod will be deleted so we will return a
	// success message. If it is running or failed, retrieve the log from the deployer pod.
	status := deployutil.DeploymentStatusFor(target)
	switch status {
	case deployapi.DeploymentStatusNew, deployapi.DeploymentStatusPending:
		if deployLogOpts.NoWait {
			glog.V(4).Infof("Deployment %s is in %s state. No logs to retrieve yet.", deployutil.LabelForDeployment(target), status)
			return &genericrest.LocationStreamer{}, nil
		}
		glog.V(4).Infof("Deployment %s is in %s state, waiting for it to start...", deployutil.LabelForDeployment(target), status)

		if err := deployutil.WaitForRunningDeployerPod(r.pn, target, r.timeout); err != nil {
			return nil, errors.NewBadRequest(fmt.Sprintf("failed to run deployer pod %s: %v", podName, err))
		}

		latest, ok, err := registry.WaitForRunningDeployment(r.rn, target, r.timeout)
		if err != nil {
			return nil, errors.NewBadRequest(fmt.Sprintf("unable to wait for deployment %s to run: %v", deployutil.LabelForDeployment(target), err))
		}
		if !ok {
			return nil, errors.NewServerTimeout(kapi.Resource("ReplicationController"), "get", 2)
		}
		if deployutil.DeploymentStatusFor(latest) == deployapi.DeploymentStatusComplete {
			podName, err = r.returnApplicationPodName(target)
			if err != nil {
				return nil, err
			}
		}
	case deployapi.DeploymentStatusComplete:
		podName, err = r.returnApplicationPodName(target)
		if err != nil {
			return nil, err
		}
	}

	logOpts := deployapi.DeploymentToPodLogOptions(deployLogOpts)
	location, transport, err := pod.LogLocation(&podGetter{r.pn}, r.connInfo, ctx, podName, logOpts)
	if err != nil {
		return nil, errors.NewBadRequest(err.Error())
	}

	return &genericrest.LocationStreamer{
		Location:        location,
		Transport:       transport,
		ContentType:     "text/plain",
		Flush:           deployLogOpts.Follow,
		ResponseChecker: genericrest.NewGenericHttpResponseChecker(kapi.Resource("pod"), podName),
	}, nil
}
Exemple #15
0
func (f *Factory) PodForResource(resource string, timeout time.Duration) (string, error) {
	sortBy := func(pods []*api.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) }
	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return "", err
	}
	mapper, _ := f.Object(false)
	resourceType, name, err := util.ResolveResource(api.Resource("pods"), resource, mapper)
	if err != nil {
		return "", err
	}

	switch resourceType {
	case api.Resource("pods"):
		return name, nil
	case api.Resource("replicationcontrollers"):
		kc, err := f.Client()
		if err != nil {
			return "", err
		}
		rc, err := kc.ReplicationControllers(namespace).Get(name)
		if err != nil {
			return "", err
		}
		selector := labels.SelectorFromSet(rc.Spec.Selector)
		pod, _, err := cmdutil.GetFirstPod(kc, namespace, selector, timeout, sortBy)
		if err != nil {
			return "", err
		}
		return pod.Name, nil
	case deployapi.Resource("deploymentconfigs"):
		oc, kc, err := f.Clients()
		if err != nil {
			return "", err
		}
		dc, err := oc.DeploymentConfigs(namespace).Get(name)
		if err != nil {
			return "", err
		}
		selector := labels.SelectorFromSet(dc.Spec.Selector)
		pod, _, err := cmdutil.GetFirstPod(kc, namespace, selector, timeout, sortBy)
		if err != nil {
			return "", err
		}
		return pod.Name, nil
	case extensions.Resource("daemonsets"):
		kc, err := f.Client()
		if err != nil {
			return "", err
		}
		ds, err := kc.Extensions().DaemonSets(namespace).Get(name)
		if err != nil {
			return "", err
		}
		selector, err := unversioned.LabelSelectorAsSelector(ds.Spec.Selector)
		if err != nil {
			return "", err
		}
		pod, _, err := cmdutil.GetFirstPod(kc, namespace, selector, timeout, sortBy)
		if err != nil {
			return "", err
		}
		return pod.Name, nil
	case extensions.Resource("jobs"):
		kc, err := f.Client()
		if err != nil {
			return "", err
		}
		job, err := kc.Extensions().Jobs(namespace).Get(name)
		if err != nil {
			return "", err
		}
		return podNameForJob(job, kc, timeout, sortBy)
	case batch.Resource("jobs"):
		kc, err := f.Client()
		if err != nil {
			return "", err
		}
		job, err := kc.Batch().Jobs(namespace).Get(name)
		if err != nil {
			return "", err
		}
		return podNameForJob(job, kc, timeout, sortBy)
	default:
		return "", fmt.Errorf("remote shell for %s is not supported", resourceType)
	}
}
Exemple #16
0
// Create instantiates a deployment config
func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) {
	req, ok := obj.(*deployapi.DeploymentRequest)
	if !ok {
		return nil, errors.NewInternalError(fmt.Errorf("wrong object passed for requesting a new rollout: %#v", obj))
	}

	configObj, err := r.store.Get(ctx, req.Name)
	if err != nil {
		return nil, err
	}
	config := configObj.(*deployapi.DeploymentConfig)
	old := config

	if errs := validation.ValidateRequestForDeploymentConfig(req, config); len(errs) > 0 {
		return nil, errors.NewInvalid(deployapi.Kind("DeploymentRequest"), req.Name, errs)
	}

	// We need to process the deployment config before we can determine if it is possible to trigger
	// a deployment.
	if req.Latest {
		if err := processTriggers(config, r.isn, req.Force); err != nil {
			return nil, err
		}
	}

	canTrigger, causes, err := canTrigger(config, r.rn, r.decoder, req.Force)
	if err != nil {
		return nil, err
	}
	// If we cannot trigger then there is nothing to do here.
	if !canTrigger {
		return &unversioned.Status{
			Message: fmt.Sprintf("deployment config %q cannot be instantiated", config.Name),
			Code:    int32(204),
		}, nil
	}
	glog.V(4).Infof("New deployment for %q caused by %#v", config.Name, causes)

	config.Status.Details = new(deployapi.DeploymentDetails)
	config.Status.Details.Causes = causes
	switch causes[0].Type {
	case deployapi.DeploymentTriggerOnConfigChange:
		config.Status.Details.Message = "config change"
	case deployapi.DeploymentTriggerOnImageChange:
		config.Status.Details.Message = "image change"
	case deployapi.DeploymentTriggerManual:
		config.Status.Details.Message = "manual change"
	}
	config.Status.LatestVersion++

	userInfo, _ := kapi.UserFrom(ctx)
	attrs := admission.NewAttributesRecord(config, old, deployapi.Kind("DeploymentConfig").WithVersion(""), config.Namespace, config.Name, deployapi.Resource("DeploymentConfig").WithVersion(""), "", admission.Update, userInfo)
	if err := r.admit.Admit(attrs); err != nil {
		return nil, err
	}

	updated, _, err := r.store.Update(ctx, config.Name, rest.DefaultUpdatedObjectInfo(config, kapi.Scheme))
	return updated, err
}
Exemple #17
0
func TestClusterReaderCoverage(t *testing.T) {
	testutil.RequireEtcd(t)
	defer testutil.DumpEtcdOnFailure(t)

	_, clusterAdminKubeConfig, err := testserver.StartTestMasterAPI()
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	discoveryClient := client.NewDiscoveryClient(clusterAdminClient.RESTClient)

	// (map[string]*unversioned.APIResourceList, error)
	allResourceList, err := discoveryClient.ServerResources()
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	allResources := map[unversioned.GroupResource]bool{}
	for _, resources := range allResourceList {
		version, err := unversioned.ParseGroupVersion(resources.GroupVersion)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		for _, resource := range resources.APIResources {
			allResources[version.WithResource(resource.Name).GroupResource()] = true
		}
	}

	escalatingResources := map[unversioned.GroupResource]bool{
		oauthapi.Resource("oauthauthorizetokens"): true,
		oauthapi.Resource("oauthaccesstokens"):    true,
		oauthapi.Resource("oauthclients"):         true,
		imageapi.Resource("imagestreams/secrets"): true,
		kapi.Resource("secrets"):                  true,
		kapi.Resource("pods/exec"):                true,
		kapi.Resource("pods/proxy"):               true,
		kapi.Resource("pods/portforward"):         true,
		kapi.Resource("nodes/proxy"):              true,
		kapi.Resource("services/proxy"):           true,
	}

	readerRole, err := clusterAdminClient.ClusterRoles().Get(bootstrappolicy.ClusterReaderRoleName)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	for _, rule := range readerRole.Rules {
		for _, group := range rule.APIGroups {
			for resource := range rule.Resources {
				gr := unversioned.GroupResource{Group: group, Resource: resource}
				if escalatingResources[gr] {
					t.Errorf("cluster-reader role has escalating resource %v.  Check pkg/cmd/server/bootstrappolicy/policy.go.", gr)
				}
				delete(allResources, gr)
			}
		}
	}

	// remove escalating resources that cluster-reader should not have access to
	for resource := range escalatingResources {
		delete(allResources, resource)
	}

	// remove resources without read APIs
	nonreadingResources := []unversioned.GroupResource{
		buildapi.Resource("buildconfigs/instantiatebinary"), buildapi.Resource("buildconfigs/instantiate"), buildapi.Resource("builds/clone"),
		deployapi.Resource("deploymentconfigrollbacks"), deployapi.Resource("generatedeploymentconfigs"), deployapi.Resource("deploymentconfigs/rollback"),
		imageapi.Resource("imagestreamimports"), imageapi.Resource("imagestreammappings"),
		extensionsapi.Resource("deployments/rollback"),
		kapi.Resource("pods/attach"), kapi.Resource("namespaces/finalize"),
	}
	for _, resource := range nonreadingResources {
		delete(allResources, resource)
	}

	// anything left in the map is missing from the permissions
	if len(allResources) > 0 {
		t.Errorf("cluster-reader role is missing %v.  Check pkg/cmd/server/bootstrappolicy/policy.go.", allResources)
	}
}
Exemple #18
0
	authorizer             authorizer.Authorizer
}

// resourcesToCheck is a map of resources and corresponding kinds of things that
// we want handled in this plugin
// TODO: Include a function that will extract the PodSpec from the resource for
// each type added here.
var resourcesToCheck = map[unversioned.GroupResource]unversioned.GroupKind{
	kapi.Resource("pods"):                   kapi.Kind("Pod"),
	kapi.Resource("podtemplates"):           kapi.Kind("PodTemplate"),
	kapi.Resource("replicationcontrollers"): kapi.Kind("ReplicationController"),
	batch.Resource("jobs"):                  batch.Kind("Job"),
	extensions.Resource("deployments"):      extensions.Kind("Deployment"),
	extensions.Resource("replicasets"):      extensions.Kind("ReplicaSet"),
	extensions.Resource("jobs"):             extensions.Kind("Job"),
	deployapi.Resource("deploymentconfigs"): deployapi.Kind("DeploymentConfig"),
}

// resourcesToIgnore is a list of resource kinds that contain a PodSpec that
// we choose not to handle in this plugin
var resourcesToIgnore = []unversioned.GroupKind{
	extensions.Kind("DaemonSet"),
}

func shouldCheckResource(resource unversioned.GroupResource, kind unversioned.GroupKind) (bool, error) {
	expectedKind, shouldCheck := resourcesToCheck[resource]
	if !shouldCheck {
		return false, nil
	}
	if expectedKind != kind {
		return false, fmt.Errorf("Unexpected resource kind %v for resource %v", &kind, &resource)
Exemple #19
0
func TestPodNodeConstraintsResources(t *testing.T) {
	ns := kapi.NamespaceDefault
	testconfigs := []struct {
		config         *api.PodNodeConstraintsConfig
		userinfo       user.Info
		reviewResponse *authorizationapi.SubjectAccessReviewResponse
	}{
		{
			config:         testConfig(),
			userinfo:       serviceaccount.UserInfo("", "", ""),
			reviewResponse: reviewResponse(false, ""),
		},
	}
	testresources := []struct {
		resource      func(bool) runtime.Object
		kind          unversioned.GroupKind
		groupresource unversioned.GroupResource
		prefix        string
	}{
		{
			resource:      replicationController,
			kind:          kapi.Kind("ReplicationController"),
			groupresource: kapi.Resource("replicationcontrollers"),
			prefix:        "ReplicationController",
		},
		{
			resource:      deployment,
			kind:          extensions.Kind("Deployment"),
			groupresource: extensions.Resource("deployments"),
			prefix:        "Deployment",
		},
		{
			resource:      replicaSet,
			kind:          extensions.Kind("ReplicaSet"),
			groupresource: extensions.Resource("replicasets"),
			prefix:        "ReplicaSet",
		},
		{
			resource:      job,
			kind:          extensions.Kind("Job"),
			groupresource: extensions.Resource("jobs"),
			prefix:        "Job",
		},
		{
			resource:      job,
			kind:          batch.Kind("Job"),
			groupresource: batch.Resource("jobs"),
			prefix:        "Job",
		},
		{
			resource:      deploymentConfig,
			kind:          deployapi.Kind("DeploymentConfig"),
			groupresource: deployapi.Resource("deploymentconfigs"),
			prefix:        "DeploymentConfig",
		},
		{
			resource:      podTemplate,
			kind:          deployapi.Kind("PodTemplate"),
			groupresource: deployapi.Resource("podtemplates"),
			prefix:        "PodTemplate",
		},
		{
			resource:      podSecurityPolicySubjectReview,
			kind:          securityapi.Kind("PodSecurityPolicySubjectReview"),
			groupresource: securityapi.Resource("podsecuritypolicysubjectreviews"),
			prefix:        "PodSecurityPolicy",
		},
		{
			resource:      podSecurityPolicySelfSubjectReview,
			kind:          securityapi.Kind("PodSecurityPolicySelfSubjectReview"),
			groupresource: securityapi.Resource("podsecuritypolicyselfsubjectreviews"),
			prefix:        "PodSecurityPolicy",
		},
		{
			resource:      podSecurityPolicyReview,
			kind:          securityapi.Kind("PodSecurityPolicyReview"),
			groupresource: securityapi.Resource("podsecuritypolicyreviews"),
			prefix:        "PodSecurityPolicy",
		},
	}
	testparams := []struct {
		nodeselector     bool
		expectedErrorMsg string
		prefix           string
	}{
		{
			nodeselector:     true,
			expectedErrorMsg: "node selection by label(s) [bogus] is prohibited by policy for your role",
			prefix:           "with nodeSelector",
		},
		{
			nodeselector:     false,
			expectedErrorMsg: "",
			prefix:           "without nodeSelector",
		},
	}
	testops := []struct {
		operation admission.Operation
	}{
		{
			operation: admission.Create,
		},
		{
			operation: admission.Update,
		},
	}
	for _, tc := range testconfigs {
		for _, tr := range testresources {
			for _, tp := range testparams {
				for _, top := range testops {
					var expectedError error
					errPrefix := fmt.Sprintf("%s; %s; %s", tr.prefix, tp.prefix, top.operation)
					prc := NewPodNodeConstraints(tc.config)
					prc.(oadmission.WantsAuthorizer).SetAuthorizer(fakeAuthorizer(t))
					err := prc.(oadmission.Validator).Validate()
					if err != nil {
						checkAdmitError(t, err, expectedError, errPrefix)
						continue
					}
					attrs := admission.NewAttributesRecord(tr.resource(tp.nodeselector), nil, tr.kind.WithVersion("version"), ns, "test", tr.groupresource.WithVersion("version"), "", top.operation, tc.userinfo)
					if tp.expectedErrorMsg != "" {
						expectedError = admission.NewForbidden(attrs, fmt.Errorf(tp.expectedErrorMsg))
					}
					err = prc.Admit(attrs)
					checkAdmitError(t, err, expectedError, errPrefix)
				}
			}
		}
	}
}
Exemple #20
0
// Complete calls the upstream Complete for the logs command and then resolves the
// resource a user requested to view its logs and creates the appropriate logOptions
// object for it.
func (o *OpenShiftLogsOptions) Complete(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
	if err := o.KubeLogOptions.Complete(f.Factory, out, cmd, args); err != nil {
		return err
	}
	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	podLogOptions := o.KubeLogOptions.Options.(*kapi.PodLogOptions)

	mapper, typer := f.Object()
	infos, err := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()).
		NamespaceParam(namespace).DefaultNamespace().
		ResourceNames("pods", args...).
		SingleResourceType().RequireObject(false).
		Do().Infos()
	if err != nil {
		return err
	}
	if len(infos) != 1 {
		return errors.New("expected a resource")
	}

	version := kcmdutil.GetFlagInt64(cmd, "version")
	_, resource := meta.KindToResource(infos[0].Mapping.GroupVersionKind, false)

	// TODO: podLogOptions should be included in our own logOptions objects.
	switch resource.GroupResource() {
	case buildapi.Resource("build"), buildapi.Resource("buildconfig"):
		bopts := &buildapi.BuildLogOptions{
			Follow:       podLogOptions.Follow,
			Previous:     podLogOptions.Previous,
			SinceSeconds: podLogOptions.SinceSeconds,
			SinceTime:    podLogOptions.SinceTime,
			Timestamps:   podLogOptions.Timestamps,
			TailLines:    podLogOptions.TailLines,
			LimitBytes:   podLogOptions.LimitBytes,
		}
		if version != 0 {
			bopts.Version = &version
		}
		o.Options = bopts
	case deployapi.Resource("deploymentconfig"):
		dopts := &deployapi.DeploymentLogOptions{
			Follow:       podLogOptions.Follow,
			Previous:     podLogOptions.Previous,
			SinceSeconds: podLogOptions.SinceSeconds,
			SinceTime:    podLogOptions.SinceTime,
			Timestamps:   podLogOptions.Timestamps,
			TailLines:    podLogOptions.TailLines,
			LimitBytes:   podLogOptions.LimitBytes,
		}
		if version != 0 {
			dopts.Version = &version
		}
		o.Options = dopts
	default:
		o.Options = nil
	}

	return nil
}