Change:
<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks! If the matter is security related, please disclose it privately via --What happened: kube-controller-manager is unable to locate the credentials of the vCenter host, even though they are defined and cased identically to the hostname in the cloud-provider-config. What you expected to happen: vCenter hostname should not be case-sensitive, or should be documented that it is. It should successfully locate credentials from the manager How to reproduce it (as minimally and precisely as possible): to an upper-case name kube-controller-manager daemon to update the secret to provision storage with the "thin" storage class will stay suck in pending Anything else we need to know?: Log Messages: ` This appears to be induced by the way the vCenter server name is calculated when the secret containing the credentials is parsed[]. The credentialKey is converted to lower case and is then parsed to lookup the server name. Environment: Kubernetes version (use ): v1.14 Cloud provider or hardware configuration: vSphere OS (e.g: ): Unknown Kernel (e.g. ): Unknown Install tools: Network plugin and version (if this is a network-related bug): Others:
/sig cloud-provider /area/provider/vmware
/area provider/vmware

Discussion:
klog.Warningf("secret %q not found in namespace %q", secretCredentialManager.SecretName, secretCredentialManager.SecretNamespace) } <ins> // Converting server FQIN to lowercase to consolidate with config parsing approach server = strings.ToLower(server) </ins> credential, found := secretCredentialManager.Cache.GetCredential(server) if !found { klog.Errorf("credentials not found for server %q", server)

import ( "reflect" <ins> "strings" </ins> "testing" corev1 "k8s.io/api/core/v1"

testPassword        = "password" testServer          = "0.0.0.0" testServer2         = "0.0.1.1" <ins> testServerFQIN      = "ExAmple.com" </ins> testUserServer2     = "user1" testPasswordServer2 = "password1" testIncorrectServer = "1.1.1.1"

}, } <ins> fqinSecret := &corev1.Secret{ ObjectMeta: metaObj, Data: map[string][]byte{ testServerFQIN + "." + userKey:     []byte(testUser), testServerFQIN + "." + passwordKey: []byte(testPassword), }, } </ins> emptySecret := &corev1.Secret{ ObjectMeta: metaObj, Data:       map[string][]byte{},

}, }, }, <ins> { testName: "GetCredential for FQIN server name", ops:      []string{addSecretOp, getCredentialsOp}, expectedValues: []interface{}{ OpSecretTest{ fqinSecret, }, GetCredentialsTest{ username: testUser, password: testPassword, server:   testServerFQIN, }, }, }, </ins> } // TODO: replace 0 with NoResyncPeriodFunc() once it moved out pkg/controller/controller_utils.go in k/k.

func TestParseSecretConfig(t *testing.T) { var ( <del> testUsername = "Admin" testPassword = "Password" testIP       = "10.20.30.40" </del> <ins> testUsername   = "Admin" testPassword   = "Password" testIP         = "10.20.30.40" testServerFQIN = "ExAmple.com" </ins> ) var testcases = []struct { testName      string

expectedError: ErrCredentialMissing, }, { <ins> testName: "FQIN stored as lowercase", data: map[string][]byte{ testServerFQIN + ".username": []byte(testUsername), testServerFQIN + ".password": []byte(testPassword), }, config: map[string]*Credential{ strings.ToLower(testServerFQIN): { User:     testUsername, Password: testPassword, }, }, expectedError: nil, }, { </ins> testName: "IP with unknown key", data: map[string][]byte{ "10.20.30.40": []byte(testUsername),