func (h *Helper) updateConfig(configDir, hostDir, serverIP, metricsHost string) error { masterConfig := filepath.Join(configDir, "master", "master-config.yaml") glog.V(1).Infof("Reading master config from %s", masterConfig) cfg, err := configapilatest.ReadMasterConfig(masterConfig) if err != nil { glog.V(1).Infof("Could not read master config: %v", err) return err } if len(h.routingSuffix) > 0 { cfg.RoutingConfig.Subdomain = h.routingSuffix } else { cfg.RoutingConfig.Subdomain = fmt.Sprintf("%s.xip.io", serverIP) } if len(metricsHost) > 0 && cfg.AssetConfig != nil { cfg.AssetConfig.MetricsPublicURL = fmt.Sprintf("https://%s/hawkular/metrics", metricsHost) } cfgBytes, err := configapilatest.WriteYAML(cfg) if err != nil { return err } err = ioutil.WriteFile(masterConfig, cfgBytes, 0644) if err != nil { return err } return h.hostHelper.CopyMasterConfigToHost(masterConfig, hostDir) }
func (h *Helper) updateConfig(configDir, hostDir, routerIP, metricsHost, loggingHost string) error { cfg, configPath, err := h.GetConfig(configDir) if err != nil { return err } if len(h.routingSuffix) > 0 { cfg.RoutingConfig.Subdomain = h.routingSuffix } else { cfg.RoutingConfig.Subdomain = fmt.Sprintf("%s.xip.io", routerIP) } if len(metricsHost) > 0 && cfg.AssetConfig != nil { cfg.AssetConfig.MetricsPublicURL = fmt.Sprintf("https://%s/hawkular/metrics", metricsHost) } if len(loggingHost) > 0 && cfg.AssetConfig != nil { cfg.AssetConfig.LoggingPublicURL = fmt.Sprintf("https://%s", loggingHost) } cfgBytes, err := configapilatest.WriteYAML(cfg) if err != nil { return err } err = ioutil.WriteFile(configPath, cfgBytes, 0644) if err != nil { return err } return h.hostHelper.CopyMasterConfigToHost(configPath, hostDir) }
func TestGetValidSessionSecretsFile(t *testing.T) { tmpfile, err := ioutil.TempFile("", "valid.yaml") if err != nil { t.Fatalf("unexpected error: %v", err) } defer os.Remove(tmpfile.Name()) secrets := &api.SessionSecrets{ Secrets: []api.SessionSecret{ {Authentication: "a1", Encryption: "e1"}, {Authentication: "a2", Encryption: "e2"}, }, } expectedSecrets := []string{"a1", "e1", "a2", "e2"} yaml, err := latest.WriteYAML(secrets) if err != nil { t.Errorf("Unexpected error: %v", err) } ioutil.WriteFile(tmpfile.Name(), []byte(yaml), os.FileMode(0600)) readSecrets, err := getSessionSecrets(tmpfile.Name()) if err != nil { t.Errorf("Unexpected error: %v", err) } if !reflect.DeepEqual(readSecrets, expectedSecrets) { t.Errorf("Unexpected %v, got %v", expectedSecrets, readSecrets) } }
func setupAdmissionPluginTestConfig(t *testing.T, value string) string { configFile, err := ioutil.TempFile("", "admission-config") if err != nil { t.Fatalf("error creating temp file: %v", err) } configFile.Close() configObj := &TestPluginConfig{ Data: value, } configContent, err := configapilatest.WriteYAML(configObj) if err != nil { t.Fatalf("error writing config: %v", err) } ioutil.WriteFile(configFile.Name(), configContent, 0644) return configFile.Name() }
func GetPluginConfig(cfg configapi.AdmissionPluginConfig) (string, error) { obj := cfg.Configuration.Object if obj == nil { return cfg.Location, nil } configFile, err := ioutil.TempFile("", "admission-plugin-config") if err != nil { return "", err } if err = configFile.Close(); err != nil { return "", err } content, err := latest.WriteYAML(obj) if err != nil { return "", err } if err = ioutil.WriteFile(configFile.Name(), content, 0644); err != nil { return "", err } return configFile.Name(), nil }
func TestGetEmptySessionSecretsFile(t *testing.T) { tmpfile, err := ioutil.TempFile("", "empty.yaml") if err != nil { t.Fatalf("unexpected error: %v", err) } defer os.Remove(tmpfile.Name()) secrets := &api.SessionSecrets{ Secrets: []api.SessionSecret{}, } yaml, err := latest.WriteYAML(secrets) if err != nil { t.Errorf("Unexpected error: %v", err) } ioutil.WriteFile(tmpfile.Name(), []byte(yaml), os.FileMode(0600)) _, err = getSessionSecrets(tmpfile.Name()) if err == nil { t.Errorf("Expected error, got none") } }
// RunMaster takes the options and: // 1. Creates certs if needed // 2. Reads fully specified master config OR builds a fully specified master config from the args // 3. Writes the fully specified master config and exits if needed // 4. Starts the master based on the fully specified config func (o MasterOptions) RunMaster() error { startUsingConfigFile := !o.IsWriteConfigOnly() && o.IsRunFromConfig() if !startUsingConfigFile && o.CreateCertificates { glog.V(2).Infof("Generating master configuration") if err := o.CreateCerts(); err != nil { return err } if err := o.CreateBootstrapPolicy(); err != nil { return err } } var masterConfig *configapi.MasterConfig var err error if startUsingConfigFile { masterConfig, err = configapilatest.ReadAndResolveMasterConfig(o.ConfigFile) } else { masterConfig, err = o.MasterArgs.BuildSerializeableMasterConfig() } if err != nil { return err } if o.IsWriteConfigOnly() { // Resolve relative to CWD cwd, err := os.Getwd() if err != nil { return err } if err := configapi.ResolveMasterConfigPaths(masterConfig, cwd); err != nil { return err } // Relativize to config file dir base, err := cmdutil.MakeAbs(filepath.Dir(o.MasterArgs.GetConfigFileToWrite()), cwd) if err != nil { return err } if err := configapi.RelativizeMasterConfigPaths(masterConfig, base); err != nil { return err } content, err := configapilatest.WriteYAML(masterConfig) if err != nil { return err } if err := os.MkdirAll(path.Dir(o.MasterArgs.GetConfigFileToWrite()), os.FileMode(0755)); err != nil { return err } if err := ioutil.WriteFile(o.MasterArgs.GetConfigFileToWrite(), content, 0644); err != nil { return err } fmt.Fprintf(o.Output, "Wrote master config to: %s\n", o.MasterArgs.GetConfigFileToWrite()) return nil } if o.MasterArgs.OverrideConfig != nil { if err := o.MasterArgs.OverrideConfig(masterConfig); err != nil { return err } } // Inject disabled feature flags based on distribution being used and // regardless of configuration. They aren't written to config file to // prevent upgrade path issues. masterConfig.DisabledFeatures.Add(o.DisabledFeatures...) validationResults := validation.ValidateMasterConfig(masterConfig, nil) if len(validationResults.Warnings) != 0 { for _, warning := range validationResults.Warnings { glog.Warningf("%v", warning) } } if len(validationResults.Errors) != 0 { return kerrors.NewInvalid(configapi.Kind("MasterConfig"), o.ConfigFile, validationResults.Errors) } if !o.MasterArgs.StartControllers { masterConfig.Controllers = configapi.ControllersDisabled } m := &Master{ config: masterConfig, api: o.MasterArgs.StartAPI, controllers: o.MasterArgs.StartControllers, } return m.Start() }
func (o CreateNodeConfigOptions) MakeNodeConfig(serverCertFile, serverKeyFile, nodeClientCAFile, kubeConfigFile, nodeConfigFile string) error { config := &configapi.NodeConfig{ NodeName: o.NodeName, ServingInfo: configapi.ServingInfo{ BindAddress: net.JoinHostPort(o.ListenAddr.Host, strconv.Itoa(ports.KubeletPort)), }, VolumeDirectory: o.VolumeDir, AllowDisabledDocker: o.AllowDisabledDocker, ImageConfig: configapi.ImageConfig{ Format: o.ImageTemplate.Format, Latest: o.ImageTemplate.Latest, }, DNSDomain: o.DNSDomain, DNSIP: o.DNSIP, MasterKubeConfig: kubeConfigFile, NetworkConfig: configapi.NodeNetworkConfig{ NetworkPluginName: o.NetworkPluginName, }, } if o.UseTLS() { config.ServingInfo.ServerCert = configapi.CertInfo{ CertFile: serverCertFile, KeyFile: serverKeyFile, } config.ServingInfo.ClientCA = nodeClientCAFile } // Resolve relative to CWD cwd, err := os.Getwd() if err != nil { return err } if err := configapi.ResolveNodeConfigPaths(config, cwd); err != nil { return err } // Relativize to config file dir base, err := cmdutil.MakeAbs(o.NodeConfigDir, cwd) if err != nil { return err } if err := configapi.RelativizeNodeConfigPaths(config, base); err != nil { return err } // Roundtrip the config to v1 and back to ensure proper defaults are set. ext, err := configapi.Scheme.ConvertToVersion(config, latestconfigapi.Version) if err != nil { return err } internal, err := configapi.Scheme.ConvertToVersion(ext, configapi.SchemeGroupVersion) if err != nil { return err } content, err := latestconfigapi.WriteYAML(internal) if err != nil { return err } if err := ioutil.WriteFile(nodeConfigFile, content, 0644); err != nil { return err } return nil }
// RunMaster takes the options and: // 1. Creates certs if needed // 2. Reads fully specified master config OR builds a fully specified master config from the args // 3. Writes the fully specified master config and exits if needed // 4. Starts the master based on the fully specified config func (o MasterOptions) RunMaster() error { startUsingConfigFile := !o.IsWriteConfigOnly() && o.IsRunFromConfig() if !startUsingConfigFile && o.CreateCertificates { glog.V(2).Infof("Generating master configuration") if err := o.CreateCerts(); err != nil { return err } if err := o.CreateBootstrapPolicy(); err != nil { return err } } var masterConfig *configapi.MasterConfig var err error if startUsingConfigFile { masterConfig, err = configapilatest.ReadAndResolveMasterConfig(o.ConfigFile) } else { masterConfig, err = o.MasterArgs.BuildSerializeableMasterConfig() } if err != nil { return err } if o.IsWriteConfigOnly() { // Resolve relative to CWD cwd, err := os.Getwd() if err != nil { return err } if err := configapi.ResolveMasterConfigPaths(masterConfig, cwd); err != nil { return err } // Relativize to config file dir base, err := cmdutil.MakeAbs(filepath.Dir(o.MasterArgs.GetConfigFileToWrite()), cwd) if err != nil { return err } if err := configapi.RelativizeMasterConfigPaths(masterConfig, base); err != nil { return err } content, err := configapilatest.WriteYAML(masterConfig) if err != nil { return err } if err := os.MkdirAll(path.Dir(o.MasterArgs.GetConfigFileToWrite()), os.FileMode(0755)); err != nil { return err } if err := ioutil.WriteFile(o.MasterArgs.GetConfigFileToWrite(), content, 0644); err != nil { return err } fmt.Fprintf(o.Output, "Wrote master config to: %s\n", o.MasterArgs.GetConfigFileToWrite()) return nil } validationResults := validation.ValidateMasterConfig(masterConfig) if len(validationResults.Warnings) != 0 { for _, warning := range validationResults.Warnings { glog.Warningf("%v", warning) } } if len(validationResults.Errors) != 0 { return kerrors.NewInvalid("MasterConfig", o.ConfigFile, validationResults.Errors) } if err := StartMaster(masterConfig); err != nil { return err } return 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) } } } }
func TestOAuthLDAP(t *testing.T) { var ( randomSuffix = string(kutil.NewUUID()) providerName = "myldapprovider" bindDN = "uid=admin,ou=company,ou=" + randomSuffix bindPassword = "******" + randomSuffix searchDN = "ou=company,ou=" + randomSuffix searchAttr = "myuid" + randomSuffix searchScope = "one" // must be "one","sub", or "base" searchFilter = "(myAttr=myValue)" // must be a valid LDAP filter format nameAttr1 = "missing-name-attr" nameAttr2 = "a-display-name" + randomSuffix idAttr1 = "missing-id-attr" idAttr2 = "dn" // "dn" is a special value, so don't add a random suffix to make sure we handle it correctly emailAttr1 = "missing-attr" emailAttr2 = "c-mail" + randomSuffix loginAttr1 = "missing-attr" loginAttr2 = "d-mylogin" + randomSuffix myUserUID = "myuser" myUserName = "******" myUserEmail = "*****@*****.**" myUserDN = searchAttr + "=" + myUserUID + "," + searchDN myUserPassword = "******" + randomSuffix ) expectedAttributes := [][]byte{} for _, attr := range sets.NewString(searchAttr, nameAttr1, nameAttr2, idAttr1, idAttr2, emailAttr1, emailAttr2, loginAttr1, loginAttr2).List() { expectedAttributes = append(expectedAttributes, []byte(attr)) } expectedSearchRequest := ldapserver.SearchRequest{ BaseObject: []byte(searchDN), Scope: ldapserver.SearchRequestSingleLevel, DerefAliases: 0, SizeLimit: 2, TimeLimit: 0, TypesOnly: false, Attributes: expectedAttributes, Filter: fmt.Sprintf("(&%s(%s=%s))", searchFilter, searchAttr, myUserUID), } // Start LDAP server ldapAddress, err := testserver.FindAvailableBindAddress(8389, 8400) if err != nil { t.Fatalf("could not allocate LDAP bind address: %v", err) } ldapServer := testutil.NewTestLDAPServer() ldapServer.SetPassword(bindDN, bindPassword) ldapServer.Start(ldapAddress) defer ldapServer.Stop() testutil.RequireEtcd(t) defer testutil.DumpEtcdOnFailure(t) masterOptions, err := testserver.DefaultMasterOptions() if err != nil { t.Fatalf("unexpected error: %v", err) } // Generate an encrypted file/keyfile to contain the bindPassword bindPasswordFile, err := ioutil.TempFile("", "bindPassword") if err != nil { t.Fatalf("unexpected error: %v", err) } defer os.Remove(bindPasswordFile.Name()) bindPasswordKeyFile, err := ioutil.TempFile("", "bindPasswordKey") if err != nil { t.Fatalf("unexpected error: %v", err) } defer os.Remove(bindPasswordKeyFile.Name()) encryptOpts := &admin.EncryptOptions{ CleartextData: []byte(bindPassword), EncryptedFile: bindPasswordFile.Name(), GenKeyFile: bindPasswordKeyFile.Name(), } if err := encryptOpts.Encrypt(); err != nil { t.Fatalf("unexpected error: %v", err) } masterOptions.OAuthConfig.IdentityProviders[0] = configapi.IdentityProvider{ Name: providerName, UseAsChallenger: true, UseAsLogin: true, MappingMethod: "claim", Provider: &configapi.LDAPPasswordIdentityProvider{ URL: fmt.Sprintf("ldap://%s/%s?%s?%s?%s", ldapAddress, searchDN, searchAttr, searchScope, searchFilter), BindDN: bindDN, BindPassword: configapi.StringSource{ StringSourceSpec: configapi.StringSourceSpec{ File: bindPasswordFile.Name(), KeyFile: bindPasswordKeyFile.Name(), }, }, Insecure: true, CA: "", Attributes: configapi.LDAPAttributeMapping{ ID: []string{idAttr1, idAttr2}, PreferredUsername: []string{loginAttr1, loginAttr2}, Name: []string{nameAttr1, nameAttr2}, Email: []string{emailAttr1, emailAttr2}, }, }, } // serialize to YAML to make sure a complex StringSource survives a round-trip serializedOptions, err := configapilatest.WriteYAML(masterOptions) if err != nil { t.Fatalf("unexpected error: %v", err) } // read back in deserializedObject, err := configapilatest.ReadYAML(bytes.NewBuffer(serializedOptions)) if err != nil { t.Fatalf("unexpected error: %v", err) } // assert type and proceed, using the deserialized version as our config if deserializedOptions, ok := deserializedObject.(*configapi.MasterConfig); !ok { t.Fatalf("unexpected object: %v", deserializedObject) } else { masterOptions = deserializedOptions } clusterAdminKubeConfig, err := testserver.StartConfiguredMaster(masterOptions) if err != nil { t.Fatalf("unexpected error: %v", err) } clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) if err != nil { t.Errorf("unexpected error: %v", err) } clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) if err != nil { t.Errorf("unexpected error: %v", err) } // Use the server and CA info anonConfig := restclient.Config{} anonConfig.Host = clusterAdminClientConfig.Host anonConfig.CAFile = clusterAdminClientConfig.CAFile anonConfig.CAData = clusterAdminClientConfig.CAData // Make sure we can't authenticate as a missing user ldapServer.ResetRequests() if _, err := tokencmd.RequestToken(&anonConfig, nil, myUserUID, myUserPassword); err == nil { t.Error("Expected error, got none") } if len(ldapServer.BindRequests) != 1 { t.Errorf("Expected a single bind request for the search phase, got %d:\n%#v", len(ldapServer.BindRequests), ldapServer.BindRequests) } if len(ldapServer.SearchRequests) != 1 { t.Errorf("Expected a single search request, got %d:\n%#v", len(ldapServer.BindRequests), ldapServer.BindRequests) } // Add user ldapServer.SetPassword(myUserDN, myUserPassword) ldapServer.AddSearchResult(myUserDN, map[string]string{emailAttr2: myUserEmail, nameAttr2: myUserName, loginAttr2: myUserUID}) // Make sure we can't authenticate with a bad password ldapServer.ResetRequests() if _, err := tokencmd.RequestToken(&anonConfig, nil, myUserUID, "badpassword"); err == nil { t.Error("Expected error, got none") } if len(ldapServer.BindRequests) != 2 { t.Errorf("Expected a bind request for the search phase and a failed bind request for the auth phase, got %d:\n%#v", len(ldapServer.BindRequests), ldapServer.BindRequests) } if len(ldapServer.SearchRequests) != 1 { t.Errorf("Expected a single search request, got %d:\n%#v", len(ldapServer.BindRequests), ldapServer.BindRequests) } // Make sure we can get a token with a good password ldapServer.ResetRequests() accessToken, err := tokencmd.RequestToken(&anonConfig, nil, myUserUID, myUserPassword) if err != nil { t.Fatalf("Unexpected error: %v", err) } if len(accessToken) == 0 { t.Errorf("Expected access token, got none") } if len(ldapServer.BindRequests) != 2 { t.Errorf("Expected a bind request for the search phase and a failed bind request for the auth phase, got %d:\n%#v", len(ldapServer.BindRequests), ldapServer.BindRequests) } if len(ldapServer.SearchRequests) != 1 { t.Errorf("Expected a single search request, got %d:\n%#v", len(ldapServer.BindRequests), ldapServer.BindRequests) } if !reflect.DeepEqual(expectedSearchRequest.BaseObject, ldapServer.SearchRequests[0].BaseObject) { t.Errorf("Expected search base DN\n\t%#v\ngot\n\t%#v", string(expectedSearchRequest.BaseObject), string(ldapServer.SearchRequests[0].BaseObject), ) } if !reflect.DeepEqual(expectedSearchRequest.Filter, ldapServer.SearchRequests[0].Filter) { t.Errorf("Expected search filter\n\t%#v\ngot\n\t%#v", string(expectedSearchRequest.Filter), string(ldapServer.SearchRequests[0].Filter), ) } { expectedAttrs := []string{} for _, a := range expectedSearchRequest.Attributes { expectedAttrs = append(expectedAttrs, string(a)) } actualAttrs := []string{} for _, a := range ldapServer.SearchRequests[0].Attributes { actualAttrs = append(actualAttrs, string(a)) } if !reflect.DeepEqual(expectedAttrs, actualAttrs) { t.Errorf("Expected search attributes\n\t%#v\ngot\n\t%#v", expectedAttrs, actualAttrs) } } // Make sure we can use the token, and it represents who we expect userConfig := anonConfig userConfig.BearerToken = accessToken userClient, err := client.New(&userConfig) if err != nil { t.Fatalf("Unexpected error: %v", err) } user, err := userClient.Users().Get("~") if err != nil { t.Fatalf("Unexpected error: %v", err) } if user.Name != myUserUID { t.Fatalf("Expected %s as the user, got %v", myUserUID, user) } // Make sure the identity got created and contained the mapped attributes identity, err := clusterAdminClient.Identities().Get(fmt.Sprintf("%s:%s", providerName, myUserDN)) if err != nil { t.Fatalf("Unexpected error: %v", err) } if identity.ProviderUserName != myUserDN { t.Errorf("Expected %q, got %q", myUserDN, identity.ProviderUserName) } if v := identity.Extra[authapi.IdentityDisplayNameKey]; v != myUserName { t.Errorf("Expected %q, got %q", myUserName, v) } if v := identity.Extra[authapi.IdentityPreferredUsernameKey]; v != myUserUID { t.Errorf("Expected %q, got %q", myUserUID, v) } if v := identity.Extra[authapi.IdentityEmailKey]; v != myUserEmail { t.Errorf("Expected %q, got %q", myUserEmail, v) } }
func TestLimitRequestAdmission(t *testing.T) { tests := []struct { name string config *api.ClusterResourceOverrideConfig object runtime.Object expectedMemRequest resource.Quantity expectedCpuLimit resource.Quantity expectedCpuRequest resource.Quantity namespace *kapi.Namespace }{ { name: "this thing even runs", config: testConfig(100, 50, 50), object: testPod("0", "0", "0", "0"), expectedMemRequest: resource.MustParse("0"), expectedCpuLimit: resource.MustParse("0"), expectedCpuRequest: resource.MustParse("0"), namespace: fakeNamespace(true), }, { name: "nil config", config: nil, object: testPod("1", "1", "1", "1"), expectedMemRequest: resource.MustParse("1"), expectedCpuLimit: resource.MustParse("1"), expectedCpuRequest: resource.MustParse("1"), namespace: fakeNamespace(true), }, { name: "all values are adjusted", config: testConfig(100, 50, 50), object: testPod("1Gi", "0", "2000m", "0"), expectedMemRequest: resource.MustParse("512Mi"), expectedCpuLimit: resource.MustParse("1"), expectedCpuRequest: resource.MustParse("500m"), namespace: fakeNamespace(true), }, { name: "just requests are adjusted", config: testConfig(0, 50, 50), object: testPod("10Mi", "0", "50m", "0"), expectedMemRequest: resource.MustParse("5Mi"), expectedCpuLimit: resource.MustParse("50m"), expectedCpuRequest: resource.MustParse("25m"), namespace: fakeNamespace(true), }, { name: "project annotation disables overrides", config: testConfig(0, 50, 50), object: testPod("10Mi", "0", "50m", "0"), expectedMemRequest: resource.MustParse("0"), expectedCpuLimit: resource.MustParse("50m"), expectedCpuRequest: resource.MustParse("0"), namespace: fakeNamespace(false), }, { name: "large values don't overflow", config: testConfig(100, 50, 50), object: testPod("1Ti", "0", "0", "0"), expectedMemRequest: resource.MustParse("512Gi"), expectedCpuLimit: resource.MustParse("1024"), expectedCpuRequest: resource.MustParse("512"), namespace: fakeNamespace(true), }, { name: "little values don't get lost", config: testConfig(500, 10, 10), object: testPod("1.024Mi", "0", "0", "0"), expectedMemRequest: resource.MustParse(".0001Gi"), expectedCpuLimit: resource.MustParse("5m"), expectedCpuRequest: resource.MustParse(".5m"), namespace: fakeNamespace(true), }, } for _, test := range tests { var reader io.Reader if test.config != nil { // we would get nil with the plugin un-configured config, err := configapilatest.WriteYAML(test.config) if err != nil { t.Fatalf("unexpected: %v", err) } reader = bytes.NewReader(config) } c, err := newClusterResourceOverride(fake.NewSimpleClientset(), reader) if err != nil { t.Errorf("%s: config de/serialize failed: %v", test.name, err) continue } c.(*clusterResourceOverridePlugin).SetProjectCache(fakeProjectCache(test.namespace)) attrs := admission.NewAttributesRecord(test.object, unversioned.GroupKind{}, test.namespace.Name, "name", kapi.Resource("pods"), "", admission.Create, fakeUser()) if err := c.Admit(attrs); err != nil { t.Errorf("%s: admission controller should not return error", test.name) } // if it's a pod, test that the resources are as expected pod, ok := test.object.(*kapi.Pod) if !ok { continue } resources := pod.Spec.Containers[0].Resources // only test one container if actual := resources.Requests[kapi.ResourceMemory]; test.expectedMemRequest.Cmp(actual) != 0 { t.Errorf("%s: memory requests do not match; %s should be %s", test.name, actual, test.expectedMemRequest) } if actual := resources.Requests[kapi.ResourceCPU]; test.expectedCpuRequest.Cmp(actual) != 0 { t.Errorf("%s: cpu requests do not match; %s should be %s", test.name, actual, test.expectedCpuRequest) } if actual := resources.Limits[kapi.ResourceCPU]; test.expectedCpuLimit.Cmp(actual) != 0 { t.Errorf("%s: cpu limits do not match; %s should be %s", test.name, actual, test.expectedCpuLimit) } } }