// newClusterResourceOverride returns an admission controller for containers that // configurably overrides container resource request/limits func newClusterResourceOverride(client clientset.Interface, config io.Reader) (admission.Interface, error) { parsed, err := ReadConfig(config) if err != nil { glog.V(5).Infof("%s admission controller loaded with error: (%T) %[2]v", api.PluginName, err) return nil, err } if errs := validation.Validate(parsed); len(errs) > 0 { return nil, errs.ToAggregate() } glog.V(5).Infof("%s admission controller loaded with config: %v", api.PluginName, parsed) var internal *internalConfig if parsed != nil { internal = &internalConfig{ limitCPUToMemoryRatio: inf.NewDec(parsed.LimitCPUToMemoryPercent, 2), cpuRequestToLimitRatio: inf.NewDec(parsed.CPURequestToLimitPercent, 2), memoryRequestToLimitRatio: inf.NewDec(parsed.MemoryRequestToLimitPercent, 2), } } limitRanger, err := limitranger.NewLimitRanger(client, wrapLimit) if err != nil { return nil, err } return &clusterResourceOverridePlugin{ Handler: admission.NewHandler(admission.Create), config: internal, LimitRanger: limitRanger, }, nil }
func ReadConfig(configFile io.Reader) (*api.ClusterResourceOverrideConfig, error) { obj, err := configlatest.ReadYAML(configFile) if err != nil { glog.V(5).Infof("%s error reading config: %v", api.PluginName, err) return nil, err } if obj == nil { return nil, nil } config, ok := obj.(*api.ClusterResourceOverrideConfig) if !ok { return nil, fmt.Errorf("unexpected config object: %#v", obj) } glog.V(5).Infof("%s config is: %v", api.PluginName, config) if errs := validation.Validate(config); len(errs) > 0 { return nil, errs.ToAggregate() } return config, nil }
func TestConfigReader(t *testing.T) { initialConfig := testConfig(10, 20, 30) serializedConfig, serializationErr := configapilatest.WriteYAML(initialConfig) if serializationErr != nil { t.Fatalf("WriteYAML: config serialize failed: %v", serializationErr) } tests := []struct { name string config io.Reader expectErr bool expectNil bool expectInvalid bool expectedConfig *api.ClusterResourceOverrideConfig }{ { name: "process nil config", config: nil, expectNil: true, }, { name: "deserialize initialConfig yaml", config: bytes.NewReader(serializedConfig), expectedConfig: initialConfig, }, { name: "completely broken config", config: bytes.NewReader([]byte("asdfasdfasdF")), expectErr: true, }, { name: "deserialize yamlConfig", config: bytes.NewReader([]byte(yamlConfig)), expectedConfig: deserializedYamlConfig, }, { name: "choke on out-of-bounds ratio", config: bytes.NewReader([]byte(invalidConfig)), expectInvalid: true, }, { name: "complain about no settings", config: bytes.NewReader([]byte(invalidConfig2)), expectInvalid: true, }, } for _, test := range tests { config, err := ReadConfig(test.config) if test.expectErr && err == nil { t.Errorf("%s: expected error", test.name) } else if !test.expectErr && err != nil { t.Errorf("%s: expected no error, saw %v", test.name, err) } if err == nil { if test.expectNil && config != nil { t.Errorf("%s: expected nil config, but saw: %v", test.name, config) } else if !test.expectNil && config == nil { t.Errorf("%s: expected config, but got nil", test.name) } } if config != nil { if test.expectedConfig != nil && *test.expectedConfig != *config { t.Errorf("%s: expected %v from reader, but got %v", test.name, test.expectErr, config) } if err := validation.Validate(config); test.expectInvalid && len(err) == 0 { t.Errorf("%s: expected validation to fail, but it passed", test.name) } else if !test.expectInvalid && len(err) > 0 { t.Errorf("%s: expected validation to pass, but it failed with %v", test.name, err) } } } }