Skip to content

Commit 99bc92c

Browse files
Support new Nutanix-style credentials in "secretdir" (#34)
* Refactored Prism credential types and parsing into own package * Addressed PR feedback * Generated DeepCopy function to satisfy k8s Object interface ``` controller-gen object paths=./environment/credentials/types.go ``` * Made namespace optional in NutanixCredentialReference * Add kubebuilder validations for credential types (#35) Co-authored-by: Yannick Struyf <yannick.struyf@nutanix.com>
1 parent 4b76a34 commit 99bc92c

File tree

8 files changed

+331
-52
lines changed

8 files changed

+331
-52
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
- Add `WithCertificate` functional option for v3 client constructor
1212
- Add `WithRoundTripper` functional option for v3 client to add custom interceptors
1313
- Add `WithLogger` functional option for v3 client
14+
- Add support for Nutanix-style credentials to "secretdir" environment provider
1415

1516
### Changed
1617
- The http client has been moved from pkg/nutanix to repo root

environment/credentials/parsecreds.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package credentials
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
"github.com/nutanix-cloud-native/prism-go-client/environment/types"
8+
)
9+
10+
func ParseCredentials(credsData []byte) (*types.ApiCredentials, error) {
11+
creds := &NutanixCredentials{}
12+
err := json.Unmarshal(credsData, &creds.Credentials)
13+
if err != nil {
14+
return nil, fmt.Errorf("failed to unmarshal the credentials data. %w", err)
15+
}
16+
// TODO only single API endpoint supported
17+
for _, cred := range creds.Credentials {
18+
switch cred.Type {
19+
case BasicAuthCredentialType:
20+
basicAuthCreds := BasicAuthCredential{}
21+
if err := json.Unmarshal(cred.Data, &basicAuthCreds); err != nil {
22+
return nil, fmt.Errorf("failed to unmarshal the basic-auth data. %w", err)
23+
}
24+
pc := basicAuthCreds.PrismCentral
25+
if pc.Username == "" || pc.Password == "" {
26+
return nil, fmt.Errorf("the PrismCentral credentials data is not set")
27+
}
28+
return &types.ApiCredentials{
29+
Username: pc.Username,
30+
Password: pc.Password,
31+
}, nil
32+
default:
33+
return nil, fmt.Errorf("unsupported credentials type: %v", cred.Type)
34+
}
35+
}
36+
return nil, fmt.Errorf("no Prism credentials")
37+
}

environment/providers/kubernetes/types.go renamed to environment/credentials/types.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
package kubernetes
1+
package credentials
2+
3+
// This file defines single-key secret format by encoding entire secret
4+
// as JSON object.
25

36
import (
47
"encoding/json"
@@ -10,15 +13,20 @@ type CredentialType string
1013
const (
1114
// BasicAuthCredentialType is username/password based authentication.
1215
BasicAuthCredentialType CredentialType = "basic_auth"
16+
17+
// KeyName is secret
18+
KeyName = "credentials"
1319
)
1420

21+
// +kubebuilder:object:generate=true
1522
type Credential struct {
1623
Type CredentialType `json:"type"`
1724
Data json.RawMessage `json:"data"`
1825
}
1926

2027
// NutanixCredentials is list of credentials to be embedded in other objects like
2128
// Kubernetes secrets.
29+
// +kubebuilder:object:generate=true
2230
type NutanixCredentials struct {
2331
Credentials []Credential `json:"credentials"`
2432
}
@@ -31,15 +39,18 @@ type BasicAuthCredential struct {
3139
PrismElements []PrismElementBasicAuth `json:"prismElements"`
3240
}
3341

42+
// +kubebuilder:object:generate=true
3443
type BasicAuth struct {
3544
Username string `json:"username"`
3645
Password string `json:"password"`
3746
}
3847

48+
// +kubebuilder:object:generate=true
3949
type PrismCentralBasicAuth struct {
4050
BasicAuth `json:",inline"`
4151
}
4252

53+
// +kubebuilder:object:generate=true
4354
type PrismElementBasicAuth struct {
4455
BasicAuth `json:",inline"`
4556
// Name is the unique resource name of the Prism Element (cluster) in the Prism Central's domain
@@ -53,23 +64,36 @@ const (
5364
SecretKind = NutanixCredentialKind("Secret")
5465
)
5566

67+
// +kubebuilder:object:generate=true
5668
type NutanixCredentialReference struct {
5769
// Kind of the Nutanix credential
70+
// +kubebuilder:validation:Enum=Secret
5871
Kind NutanixCredentialKind `json:"kind"`
5972
// Name of the credential.
73+
// +kubebuilder:validation:Required
74+
// +kubebuilder:validation:MinLength=1
6075
Name string `json:"name"`
6176
// namespace of the credential.
77+
// +optional
6278
Namespace string `json:"namespace"`
6379
}
6480

6581
// NutanixPrismEndpoint defines a Nutanix API endpoint with reference to credentials.
6682
// Credentials are stored in Kubernetes secrets.
83+
// +kubebuilder:object:generate=true
6784
type NutanixPrismEndpoint struct {
6885
// address is the endpoint address (DNS name or IP address) of the Nutanix Prism Central or Element (cluster)
86+
// +kubebuilder:validation:Required
87+
// +kubebuilder:validation:MaxLength=256
6988
Address string `json:"address"`
7089
// port is the port number to access the Nutanix Prism Central or Element (cluster)
90+
// +kubebuilder:validation:Required
91+
// +kubebuilder:validation:Minimum=1
92+
// +kubebuilder:validation:Maximum=65535
93+
// +kubebuilder:default=9440
7194
Port int32 `json:"port"`
7295
// use insecure connection to Prism endpoint
96+
// +kubebuilder:default=false
7397
// +optional
7498
Insecure bool `json:"insecure"`
7599
// Pass credential information for the target Prism instance

environment/credentials/zz_generated.deepcopy.go

Lines changed: 134 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

environment/providers/kubernetes/kubernetes.go

Lines changed: 9 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
package kubernetes
66

77
import (
8-
"encoding/json"
98
"fmt"
109
"net/url"
1110

11+
"github.com/nutanix-cloud-native/prism-go-client/environment/credentials"
1212
"github.com/nutanix-cloud-native/prism-go-client/environment/types"
1313
coreinformers "k8s.io/client-go/informers/core/v1"
1414
)
1515

1616
type provider struct {
1717
secretInformer coreinformers.SecretInformer
18-
prismEndpoint NutanixPrismEndpoint
18+
prismEndpoint credentials.NutanixPrismEndpoint
1919
}
2020

2121
func (prov *provider) getCredentials(_ types.Topology) (*types.ApiCredentials, error) {
@@ -26,42 +26,16 @@ func (prov *provider) getCredentials(_ types.Topology) (*types.ApiCredentials, e
2626
}
2727

2828
// Parse credentials in secret
29-
credsData, ok := secret.Data["credentials"]
29+
credsData, ok := secret.Data[credentials.KeyName]
3030
if !ok {
31-
return nil, fmt.Errorf("no \"credentials\" data found in secret %s/%s",
32-
ref.Namespace, ref.Name)
31+
return nil, fmt.Errorf("no %q data found in secret %s/%s",
32+
credentials.KeyName, ref.Namespace, ref.Name)
3333
}
34-
creds := &NutanixCredentials{}
35-
err = json.Unmarshal(credsData, &creds.Credentials)
36-
if err != nil {
37-
return nil, fmt.Errorf("failed to unmarshal the credentials data. %w", err)
38-
}
39-
// TODO only single API endpoint supported
40-
for _, cred := range creds.Credentials {
41-
switch cred.Type {
42-
case BasicAuthCredentialType:
43-
basicAuthCreds := BasicAuthCredential{}
44-
if err := json.Unmarshal(cred.Data, &basicAuthCreds); err != nil {
45-
return nil, fmt.Errorf("failed to unmarshal the basic-auth data. %w", err)
46-
}
47-
pc := basicAuthCreds.PrismCentral
48-
if pc.Username == "" || pc.Password == "" {
49-
return nil, fmt.Errorf("the PrismCentral credentials data is not set for secret %s/%s",
50-
ref.Namespace, ref.Name)
51-
}
52-
return &types.ApiCredentials{
53-
Username: pc.Username,
54-
Password: pc.Password,
55-
}, nil
56-
default:
57-
return nil, fmt.Errorf("unsupported credentials type in secret %s/%s: %v",
58-
ref.Namespace, ref.Name, cred.Type)
59-
}
60-
}
61-
return nil, fmt.Errorf("no Prism credentials in secret %s/%s", ref.Namespace, ref.Name)
34+
35+
return credentials.ParseCredentials(credsData)
6236
}
6337

64-
// GetManagementEndpoint retrieves managment endpoint
38+
// GetManagementEndpoint retrieves management endpoint
6539
func (prov *provider) GetManagementEndpoint(
6640
topology types.Topology,
6741
) (*types.ManagementEndpoint, error) {
@@ -96,7 +70,7 @@ func (prov *provider) Get(topology types.Topology, key string) (
9670
// Prism endpoint and a secretes informer as input.
9771
// It's assumed secrets informer is already running and its cache has been synced.
9872
func NewProvider(
99-
prismEndpoint NutanixPrismEndpoint,
73+
prismEndpoint credentials.NutanixPrismEndpoint,
10074
secretInformer coreinformers.SecretInformer,
10175
) types.Provider {
10276
return &provider{

environment/providers/kubernetes/kubernetes_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"k8s.io/client-go/kubernetes/fake"
1919
"k8s.io/client-go/tools/cache"
2020

21+
"github.com/nutanix-cloud-native/prism-go-client/environment/credentials"
2122
"github.com/nutanix-cloud-native/prism-go-client/environment/types"
2223
)
2324

@@ -67,12 +68,12 @@ var _ = Describe("Kubernetes Environment Provider", Ordered, func() {
6768
`, username, password)),
6869
},
6970
})
70-
prismEndpoint = NutanixPrismEndpoint{
71+
prismEndpoint = credentials.NutanixPrismEndpoint{
7172
Address: ip,
7273
Port: 9440,
7374
Insecure: true,
74-
CredentialRef: &NutanixCredentialReference{
75-
Kind: SecretKind,
75+
CredentialRef: &credentials.NutanixCredentialReference{
76+
Kind: credentials.SecretKind,
7677
Name: secretName,
7778
Namespace: secretNamespace,
7879
},

0 commit comments

Comments
 (0)