• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tensorchord / openmodelz / 6689709675

30 Oct 2023 07:40AM UTC coverage: 24.968% (-1.0%) from 25.971%
6689709675

Pull #194

github

xieydd
Fix ci error

Signed-off-by: xieydd <xieydd@gmail.com>
Pull Request #194: feat: Support volume

321 of 321 new or added lines in 8 files covered. (100.0%)

969 of 3881 relevant lines covered (24.97%)

1.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/agent/pkg/k8s/secret.go
1
package k8s
2

3
import (
4
        "context"
5
        "errors"
6
        "fmt"
7
        "log"
8
        "strings"
9

10
        "github.com/tensorchord/openmodelz/agent/api/types"
11
        apiv1 "k8s.io/api/core/v1"
12
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13
        "k8s.io/client-go/kubernetes"
14
        typedv1 "k8s.io/client-go/kubernetes/typed/core/v1"
15
)
16

17
const (
18
        secretsMountPath             = "/var/modelz/secrets"
19
        secretLabel                  = "app.kubernetes.io/managed-by"
20
        secretLabelValue             = "modelz"
21
        secretsProjectVolumeNameTmpl = "projected-secrets"
22
)
23

24
// SecretsClient exposes the standardized CRUD behaviors for Kubernetes secrets.  These methods
25
// will ensure that the secrets are structured and labelled correctly for use by the modelz system.
26
type SecretsClient interface {
27
        // List returns a list of available function secrets.  Only the names are returned
28
        // to ensure we do not accidentally read or print the sensitive values during
29
        // read operations.
30
        List(namespace string) (names []string, err error)
31
        // Create adds a new secret, with the appropriate labels and structure to be
32
        // used as a function secret.
33
        Create(secret types.Secret) error
34
        // Replace updates the value of a function secret
35
        Replace(secret types.Secret) error
36
        // Delete removes a function secret
37
        Delete(name string, namespace string) error
38
        // GetSecrets queries Kubernetes for a list of secrets by name in the given k8s namespace.
39
        // This should only be used if you need access to the actual secret structure/value. Specifically,
40
        // inside the FunctionFactory.
41
        GetSecrets(namespace string, secretNames []string) (map[string]*apiv1.Secret, error)
42
}
43

44
// SecretInterfacer exposes the SecretInterface getter for the k8s client.
45
// This is implemented by the CoreV1Interface() interface in the Kubernetes client.
46
// The SecretsClient only needs this one interface, but needs to be able to set the
47
// namespaces when the interface is instantiated, meaning, we need the Getter and not the
48
// SecretInterface itself.
49
type SecretInterfacer interface {
50
        // Secrets returns a SecretInterface scoped to the specified namespace
51
        Secrets(namespace string) typedv1.SecretInterface
52
}
53

54
type SecretClient struct {
55
        kube SecretInterfacer
56
}
57

58
// NewSecretsClient constructs a new SecretsClient using the provided Kubernetes client.
59
func NewSecretClient(kube kubernetes.Interface) SecretsClient {
×
60
        return &SecretClient{
×
61
                kube: kube.CoreV1(),
×
62
        }
×
63
}
×
64

65
func (c SecretClient) List(namespace string) (names []string, err error) {
×
66
        res, err := c.kube.Secrets(namespace).List(context.TODO(), c.selector())
×
67
        if err != nil {
×
68
                log.Printf("failed to list secrets in %s: %v\n", namespace, err)
×
69
                return nil, err
×
70
        }
×
71

72
        names = make([]string, len(res.Items))
×
73
        for idx, item := range res.Items {
×
74
                // this is safe because size of names matches res.Items exactly
×
75
                names[idx] = item.Name
×
76
        }
×
77
        return names, nil
×
78
}
79

80
func (c SecretClient) Create(secret types.Secret) error {
×
81
        err := c.validateSecret(secret)
×
82
        if err != nil {
×
83
                return err
×
84
        }
×
85

86
        req := &apiv1.Secret{
×
87
                Type: apiv1.SecretTypeOpaque,
×
88
                ObjectMeta: metav1.ObjectMeta{
×
89
                        Name:      secret.Name,
×
90
                        Namespace: secret.Namespace,
×
91
                        Labels: map[string]string{
×
92
                                secretLabel: secretLabelValue,
×
93
                        },
×
94
                },
×
95
        }
×
96

×
97
        if len(secret.Data) > 0 {
×
98
                req.Data = secret.Data
×
99
        }
×
100

101
        if len(secret.StringData) > 0 {
×
102
                req.StringData = secret.StringData
×
103
        }
×
104

105
        s, err := c.kube.Secrets(secret.Namespace).Get(context.Background(), secret.Name, metav1.GetOptions{})
×
106
        if err == nil && s != nil {
×
107
                log.Printf("secret %s.%s already exists\n", secret.Name, secret.Namespace)
×
108
                return nil
×
109
        }
×
110

111
        _, err = c.kube.Secrets(secret.Namespace).Create(context.TODO(), req, metav1.CreateOptions{})
×
112
        if err != nil {
×
113
                log.Printf("failed to create secret %s.%s: %v\n", secret.Name, secret.Namespace, err)
×
114
                return err
×
115
        }
×
116

117
        log.Printf("created secret %s.%s\n", secret.Name, secret.Namespace)
×
118

×
119
        return nil
×
120
}
121

122
func (c SecretClient) Replace(secret types.Secret) error {
×
123
        err := c.validateSecret(secret)
×
124
        if err != nil {
×
125
                return err
×
126
        }
×
127

128
        kube := c.kube.Secrets(secret.Namespace)
×
129
        found, err := kube.Get(context.TODO(), secret.Name, metav1.GetOptions{})
×
130
        if err != nil {
×
131
                log.Printf("can not retrieve secret for update %s.%s: %v\n", secret.Name, secret.Namespace, err)
×
132
                return err
×
133
        }
×
134

135
        _, err = kube.Update(context.TODO(), found, metav1.UpdateOptions{})
×
136
        if err != nil {
×
137
                log.Printf("can not update secret %s.%s: %v\n", secret.Name, secret.Namespace, err)
×
138
                return err
×
139
        }
×
140

141
        return nil
×
142
}
143

144
func (c SecretClient) Delete(namespace string, name string) error {
×
145
        err := c.kube.Secrets(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
×
146
        if err != nil {
×
147
                log.Printf("can not delete %s.%s: %v\n", name, namespace, err)
×
148
        }
×
149
        return err
×
150
}
151

152
func (c SecretClient) GetSecrets(namespace string, secretNames []string) (map[string]*apiv1.Secret, error) {
×
153
        kube := c.kube.Secrets(namespace)
×
154
        opts := metav1.GetOptions{}
×
155

×
156
        secrets := map[string]*apiv1.Secret{}
×
157
        for _, secretName := range secretNames {
×
158
                secret, err := kube.Get(context.TODO(), secretName, opts)
×
159
                if err != nil {
×
160
                        return nil, err
×
161
                }
×
162
                secrets[secretName] = secret
×
163
        }
164

165
        return secrets, nil
×
166
}
167

168
func (c SecretClient) selector() metav1.ListOptions {
×
169
        return metav1.ListOptions{
×
170
                LabelSelector: fmt.Sprintf("%s=%s", secretLabel, secretLabelValue),
×
171
        }
×
172
}
×
173

174
func (c SecretClient) validateSecret(secret types.Secret) error {
×
175
        if strings.TrimSpace(secret.Namespace) == "" {
×
176
                return errors.New("namespace may not be empty")
×
177
        }
×
178

179
        if strings.TrimSpace(secret.Name) == "" {
×
180
                return errors.New("name may not be empty")
×
181
        }
×
182

183
        return nil
×
184
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc