Skip to content

Commit

Permalink
add nodeselector and annotation build pod overrides and defaulters
Browse files Browse the repository at this point in the history
  • Loading branch information
bparees committed Oct 20, 2016
1 parent 0a022ab commit b952064
Show file tree
Hide file tree
Showing 48 changed files with 1,176 additions and 503 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions api/swagger-spec/oapi-v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -21462,6 +21462,10 @@
"type": "integer",
"format": "int64",
"description": "completionDeadlineSeconds is an optional duration in seconds, counted from the time when a build pod gets scheduled in the system, that the build may be active on a node before the system actively tries to terminate the build; value must be positive integer"
},
"nodeSelector": {
"type": "object",
"description": "nodeSelector is a selector which must be true for the build pod to fit on a node"
}
}
},
Expand Down Expand Up @@ -22513,6 +22517,10 @@
"format": "int64",
"description": "completionDeadlineSeconds is an optional duration in seconds, counted from the time when a build pod gets scheduled in the system, that the build may be active on a node before the system actively tries to terminate the build; value must be positive integer"
},
"nodeSelector": {
"type": "object",
"description": "nodeSelector is a selector which must be true for the build pod to fit on a node"
},
"triggeredBy": {
"type": "array",
"items": {
Expand Down
8 changes: 8 additions & 0 deletions api/swagger-spec/openshift-openapi-spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -44680,6 +44680,10 @@
"type": "integer",
"format": "int64"
},
"nodeSelector": {
"description": "nodeSelector is a selector which must be true for the build pod to fit on a node",
"type": "object"
},
"output": {
"$ref": "#/definitions/v1.BuildOutput"
},
Expand Down Expand Up @@ -44913,6 +44917,10 @@
"type": "integer",
"format": "int64"
},
"nodeSelector": {
"description": "nodeSelector is a selector which must be true for the build pod to fit on a node",
"type": "object"
},
"output": {
"$ref": "#/definitions/v1.BuildOutput"
},
Expand Down
2 changes: 1 addition & 1 deletion docs/man/man1/openshift-start-kubernetes-apiserver.1
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ This command launches an instance of the Kubernetes apiserver (kube\-apiserver).

.PP
\fB\-\-admission\-control\fP="AlwaysAdmit"
Ordered list of plug\-ins to do admission control of resources into cluster. Comma\-delimited list of: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, BuildByStrategy, BuildDefaults, BuildOverrides, ClusterResourceOverride, DefaultStorageClass, DenyEscalatingExec, DenyExecOnPrivileged, ExternalIPRanger, ImagePolicyWebhook, InitialResources, LimitPodHardAntiAffinityTopology, LimitRanger, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, OriginNamespaceLifecycle, OriginPodNodeEnvironment, PersistentVolumeLabel, PodNodeConstraints, PodSecurityPolicy, ProjectRequestLimit, ResourceQuota, RunOnceDuration, SCCExecRestrictions, SecurityContextConstraint, SecurityContextDeny, ServiceAccount, openshift.io/ClusterResourceQuota, openshift.io/ImageLimitRange, openshift.io/ImagePolicy, openshift.io/JenkinsBootstrapper, openshift.io/OriginResourceQuota, openshift.io/OwnerReference, openshift.io/RestrictedEndpointsAdmission.
Ordered list of plug\-ins to do admission control of resources into cluster. Comma\-delimited list of: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, BuildByStrategy, ClusterResourceOverride, DefaultStorageClass, DenyEscalatingExec, DenyExecOnPrivileged, ExternalIPRanger, ImagePolicyWebhook, InitialResources, LimitPodHardAntiAffinityTopology, LimitRanger, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, OriginNamespaceLifecycle, OriginPodNodeEnvironment, PersistentVolumeLabel, PodNodeConstraints, PodSecurityPolicy, ProjectRequestLimit, ResourceQuota, RunOnceDuration, SCCExecRestrictions, SecurityContextConstraint, SecurityContextDeny, ServiceAccount, openshift.io/ClusterResourceQuota, openshift.io/ImageLimitRange, openshift.io/ImagePolicy, openshift.io/JenkinsBootstrapper, openshift.io/OriginResourceQuota, openshift.io/OwnerReference, openshift.io/RestrictedEndpointsAdmission.

.PP
\fB\-\-admission\-control\-config\-file\fP=""
Expand Down
52 changes: 6 additions & 46 deletions pkg/build/admission/buildpodutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,64 +4,29 @@ import (
"errors"
"fmt"

"k8s.io/kubernetes/pkg/admission"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"

buildapi "github.com/openshift/origin/pkg/build/api"
)

// IsBuildPod returns true if a pod is a pod generated for a Build
func IsBuildPod(a admission.Attributes) bool {
if a.GetResource().GroupResource() != kapi.Resource("pods") {
return false
}
if len(a.GetSubresource()) != 0 {
return false
}
pod, err := GetPod(a)
if err != nil {
return false
}
return hasBuildAnnotation(pod) && hasBuildEnvVar(pod)
}

// GetBuild returns a build object encoded in a pod's BUILD environment variable along with
// its encoding version
func GetBuild(a admission.Attributes) (*buildapi.Build, unversioned.GroupVersion, error) {
pod, err := GetPod(a)
if err != nil {
return nil, unversioned.GroupVersion{}, err
}
func GetBuildFromPod(pod *kapi.Pod) (*buildapi.Build, unversioned.GroupVersion, error) {
build, version, err := getBuildFromPod(pod)
if err != nil {
return nil, unversioned.GroupVersion{}, admission.NewForbidden(a, fmt.Errorf("unable to get build from pod: %v", err))
return nil, unversioned.GroupVersion{}, fmt.Errorf("unable to get build from pod: %v", err)
}
return build, version, nil
}

// GetPod returns a pod from an admission attributes object
func GetPod(a admission.Attributes) (*kapi.Pod, error) {
pod, isPod := a.GetObject().(*kapi.Pod)
if !isPod {
return nil, admission.NewForbidden(a, fmt.Errorf("unrecognized request object: %#v", a.GetObject()))
}
return pod, nil
}

// SetBuild encodes a build object and sets it in a pod's BUILD environment variable
func SetBuild(a admission.Attributes, build *buildapi.Build, groupVersion unversioned.GroupVersion) error {
pod, err := GetPod(a)
if err != nil {
return err
}

err = setBuildInPod(build, pod, groupVersion)
func SetBuildInPod(pod *kapi.Pod, build *buildapi.Build, groupVersion unversioned.GroupVersion) error {
err := setBuildInPod(build, pod, groupVersion)
if err != nil {
return admission.NewForbidden(a, fmt.Errorf("unable to set build in pod: %v", err))
return fmt.Errorf("unable to set build in pod: %v", err)
}

return nil
}

Expand All @@ -70,12 +35,7 @@ func SetBuild(a admission.Attributes, build *buildapi.Build, groupVersion unvers
// environment variable may have been set in multiple ways: a default value,
// by a BuildConfig, or by the BuildDefaults admission plugin. In this method
// we finally act on the value by injecting it into the Pod.
func SetBuildLogLevel(attributes admission.Attributes, build *buildapi.Build) error {
pod, err := GetPod(attributes)
if err != nil {
return err
}

func SetPodLogLevelFromBuild(pod *kapi.Pod, build *buildapi.Build) error {
var envs []kapi.EnvVar

// Check whether the build strategy supports --loglevel parameter.
Expand Down
42 changes: 4 additions & 38 deletions pkg/build/admission/buildpodutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,13 @@ import (
"k8s.io/kubernetes/pkg/api/unversioned"

u "github.com/openshift/origin/pkg/build/admission/testutil"
buildapi "github.com/openshift/origin/pkg/build/api"
)

func TestIsBuildPod(t *testing.T) {
tests := []struct {
pod *u.TestPod
expected bool
}{
{
pod: u.Pod().WithAnnotation("foo", "bar"),
expected: false,
},
{
pod: u.Pod().WithEnvVar("BUILD", "blah"),
expected: false,
},
{
pod: u.Pod().WithAnnotation(buildapi.BuildAnnotation, "build"),
expected: false,
},
{
pod: u.Pod().
WithAnnotation(buildapi.BuildAnnotation, "build").
WithEnvVar("BUILD", "true"),
expected: true,
},
}

for _, tc := range tests {
actual := IsBuildPod(tc.pod.ToAttributes())
if actual != tc.expected {
t.Errorf("unexpected result (%v) for pod %#v", actual, tc.pod)
}
}
}

func TestGetBuild(t *testing.T) {
build := u.Build().WithDockerStrategy()
for _, version := range []string{"v1"} {
pod := u.Pod().WithBuild(t, build.AsBuild(), version)
resultBuild, resultVersion, err := GetBuild(pod.ToAttributes())
resultBuild, resultVersion, err := GetBuildFromPod((*kapi.Pod)(pod))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand All @@ -69,7 +35,7 @@ func TestSetBuild(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
err = SetBuild(pod.ToAttributes(), build.AsBuild(), groupVersion)
err = SetBuildInPod((*kapi.Pod)(pod), build.AsBuild(), groupVersion)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand All @@ -83,7 +49,7 @@ func TestSetBuild(t *testing.T) {
func TestSetBuildLogLevel(t *testing.T) {
build := u.Build().WithSourceStrategy()
pod := u.Pod().WithEnvVar("BUILD", "foo")
SetBuildLogLevel(pod.ToAttributes(), build.AsBuild())
SetPodLogLevelFromBuild((*kapi.Pod)(pod), build.AsBuild())

if len(pod.Spec.Containers[0].Args) == 0 {
t.Errorf("Builds pod loglevel was not set")
Expand All @@ -96,7 +62,7 @@ func TestSetBuildLogLevel(t *testing.T) {
build = u.Build().WithSourceStrategy()
pod = u.Pod().WithEnvVar("BUILD", "foo")
build.Spec.Strategy.SourceStrategy.Env = []kapi.EnvVar{{Name: "BUILD_LOGLEVEL", Value: "7", ValueFrom: nil}}
SetBuildLogLevel(pod.ToAttributes(), build.AsBuild())
SetPodLogLevelFromBuild((*kapi.Pod)(pod), build.AsBuild())

if pod.Spec.Containers[0].Args[0] != "--loglevel=7" {
t.Errorf("Build pod loglevel was not transferred from BUILD_LOGLEVEL environment variable: %#v", pod)
Expand Down
22 changes: 16 additions & 6 deletions pkg/build/admission/config.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
package admission

import (
"io"
"io/ioutil"
"reflect"
"os"

"github.com/golang/glog"

"k8s.io/kubernetes/pkg/runtime"

configapi "github.com/openshift/origin/pkg/cmd/server/api"
configlatest "github.com/openshift/origin/pkg/cmd/server/api/latest"
"github.com/openshift/origin/pkg/cmd/util/pluginconfig"
)

// ReadPluginConfig will read a plugin configuration object from a reader stream
func ReadPluginConfig(reader io.Reader, config runtime.Object) error {
if reader == nil || reflect.ValueOf(reader).IsNil() {
func ReadPluginConfig(pluginConfig map[string]configapi.AdmissionPluginConfig, name string, config runtime.Object) error {

configFilePath, err := pluginconfig.GetPluginConfigFile(pluginConfig, name, "")
if configFilePath == "" {
return nil
}

configBytes, err := ioutil.ReadAll(reader)
configData, err := os.Open(configFilePath)
if err != nil {
glog.Fatalf("Couldn't open plugin configuration %s: %#v", configFilePath, err)
return err
}

defer configData.Close()

configBytes, err := ioutil.ReadAll(configData)

err = configlatest.ReadYAMLInto(configBytes, config)
if err != nil {
return err
Expand Down
21 changes: 7 additions & 14 deletions pkg/build/admission/config_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package admission

import (
"bytes"
"reflect"
"testing"

Expand Down Expand Up @@ -48,39 +47,33 @@ func TestReadPluginConfig(t *testing.T) {
configapi.Scheme.AddKnownTypes(configapi.SchemeGroupVersion, &OtherTestConfig2{})
configapi.Scheme.AddKnownTypeWithName(configapiv1.SchemeGroupVersion.WithKind("OtherTestConfig2"), &OtherTestConfig2V2{})

configString := `apiVersion: v1
kind: TestConfig
item1: hello
item2:
- foo
- bar
`

config := &TestConfig{}

expected := &TestConfig{
Item1: "hello",
Item2: []string{"foo", "bar"},
}
pluginCfg := map[string]configapi.AdmissionPluginConfig{"testconfig": {"", expected}}
// The config should match the expected config object
err := ReadPluginConfig(bytes.NewBufferString(configString), config)
err := ReadPluginConfig(pluginCfg, "testconfig", config)
if err != nil {
t.Fatalf("unexpected: %v", err)
}
if !reflect.DeepEqual(config, expected) {
t.Errorf("config does not equal expected: %#v", config)
}

// Passing a nil reader, should not get an error
var nilBuffer *bytes.Buffer
err = ReadPluginConfig(nilBuffer, &TestConfig{})
// Passing a nil cfg, should not get an error
pluginCfg = map[string]configapi.AdmissionPluginConfig{}
err = ReadPluginConfig(pluginCfg, "testconfig", &TestConfig{})
if err != nil {
t.Fatalf("unexpected: %v", err)
}

// Passing the wrong type of destination object should result in an error
config2 := &OtherTestConfig2{}
err = ReadPluginConfig(bytes.NewBufferString(configString), config2)
pluginCfg = map[string]configapi.AdmissionPluginConfig{"testconfig": {"", expected}}
err = ReadPluginConfig(pluginCfg, "testconfig", config2)
if err == nil {
t.Fatalf("expected error")
}
Expand Down
Loading

0 comments on commit b952064

Please sign in to comment.