Skip to content

Commit

Permalink
add ut for credential provider
Browse files Browse the repository at this point in the history
Signed-off-by: Kuromesi <[email protected]>
  • Loading branch information
Kuromesi committed May 18, 2024
1 parent d326724 commit 06a14f1
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ jobs:
restore-keys: ${{ runner.os }}-go-
- name: Run Unit Tests
run: |
git config core.filemode false
chmod +x pkg/daemon/criruntime/imageruntime/fake_plugin/fake-credential-plugin
make test
git status
- name: Publish Unit Test Coverage
Expand Down
Binary file not shown.
152 changes: 152 additions & 0 deletions pkg/daemon/criruntime/imageruntime/fake_plugin/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package main

import (
"bufio"
"context"
"errors"
"fmt"
"io"
"os"
"strings"

"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/component-base/logs"
"k8s.io/klog/v2"
"k8s.io/kubelet/pkg/apis/credentialprovider/install"
v1 "k8s.io/kubelet/pkg/apis/credentialprovider/v1"
)

var (
scheme = runtime.NewScheme()
codecs = serializer.NewCodecFactory(scheme)
)

func init() {
install.Install(scheme)
}

func getCredentials(ctx context.Context, image string, args []string) (*v1.CredentialProviderResponse, error) {
response := &v1.CredentialProviderResponse{
CacheKeyType: v1.RegistryPluginCacheKeyType,
Auth: map[string]v1.AuthConfig{
"registry.plugin.com/test": {
Username: "user",
Password: "password",
},
},
}
return response, nil
}

func runPlugin(ctx context.Context, r io.Reader, w io.Writer, args []string) error {
data, err := io.ReadAll(r)
if err != nil {
return err
}

_, err = json.DefaultMetaFactory.Interpret(data)
if err != nil {
return err
}

request, err := decodeRequest(data)
if err != nil {
return err
}

if request.Image == "" {
return errors.New("image in plugin request was empty")
}

// Deny all requests except for those where the image URL contains registry.plugin.com
// to test whether kruise could get expected auths if plugin fails to run
if !strings.Contains(request.Image, "registry.plugin.com") {
return errors.New("image in plugin request not supported: " + request.Image)
}

response, err := getCredentials(ctx, request.Image, args)
if err != nil {
return err
}

if response == nil {
return errors.New("CredentialProviderResponse from plugin was nil")
}

encodedResponse, err := encodeResponse(response)
if err != nil {
return err
}

writer := bufio.NewWriter(w)
defer writer.Flush()
if _, err := writer.Write(encodedResponse); err != nil {
return err
}

return nil
}

func decodeRequest(data []byte) (*v1.CredentialProviderRequest, error) {
obj, gvk, err := codecs.UniversalDecoder(v1.SchemeGroupVersion).Decode(data, nil, nil)
if err != nil {
return nil, err
}

if gvk.Kind != "CredentialProviderRequest" {
return nil, fmt.Errorf("kind was %q, expected CredentialProviderRequest", gvk.Kind)
}

if gvk.Group != v1.GroupName {
return nil, fmt.Errorf("group was %q, expected %s", gvk.Group, v1.GroupName)
}

request, ok := obj.(*v1.CredentialProviderRequest)
if !ok {
return nil, fmt.Errorf("unable to convert %T to *CredentialProviderRequest", obj)
}

return request, nil
}

func encodeResponse(response *v1.CredentialProviderResponse) ([]byte, error) {
mediaType := "application/json"
info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType)
if !ok {
return nil, fmt.Errorf("unsupported media type %q", mediaType)
}

encoder := codecs.EncoderForVersion(info.Serializer, v1.SchemeGroupVersion)
data, err := runtime.Encode(encoder, response)
if err != nil {
return nil, fmt.Errorf("failed to encode response: %v", err)
}

return data, nil
}

func main() {
logs.InitLogs()
defer logs.FlushLogs()

if err := newCredentialProviderCommand().Execute(); err != nil {
os.Exit(1)
}
}

func newCredentialProviderCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "acr-credential-provider",
Short: "ACR credential provider for kubelet",
Run: func(cmd *cobra.Command, args []string) {
if err := runPlugin(context.TODO(), os.Stdin, os.Stdout, os.Args[1:]); err != nil {
klog.Errorf("Error running credential provider plugin: %v", err)
os.Exit(1)
}
},
}
return cmd
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: kubelet.config.k8s.io/v1
kind: CredentialProviderConfig
providers:
- name: fake-credential-plugin
matchImages:
- "registry.plugin.com"
- "registry.private.com"
defaultCacheDuration: "12h"
apiVersion: credentialprovider.kubelet.k8s.io/v1
21 changes: 21 additions & 0 deletions pkg/daemon/criruntime/imageruntime/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"testing"

v1 "k8s.io/api/core/v1"
"k8s.io/klog/v2"
"k8s.io/kubernetes/pkg/credentialprovider/plugin"
"k8s.io/kubernetes/pkg/util/parsers"

"github.com/openkruise/kruise/pkg/util/secret"
Expand Down Expand Up @@ -102,7 +104,26 @@ func TestMatchRegistryAuths(t *testing.T) {
},
Expect: 0,
},
{
name: "test credential plugin if matched",
Image: "registry.plugin.com/test/echoserver:v1",
GetSecrets: func() []v1.Secret {
return []v1.Secret{}
},
Expect: 1,
},
}
pluginBinDir := "fake_plugin"
pluginConfigFile := "fake_plugin/plugin-config.yaml"
// credential plugin is configured for images with "registry.plugin.com" and "registry.private.com",
// however, only images with "registry.plugin.com" will return a fake credential,
// other images will be denied by the plugin and an error will be raised,
// this is to test whether kruise could get expected auths if plugin fails to run
err := plugin.RegisterCredentialProviderPlugins(pluginConfigFile, pluginBinDir)
if err != nil {
klog.Errorf("Failed to register credential provider plugins: %v", err)
}
secret.MakeAndSetKeyring()
for _, cs := range cases {
t.Run(cs.name, func(t *testing.T) {
repoToPull, _, _, err := parsers.ParseImageName(cs.Image)
Expand Down

0 comments on commit 06a14f1

Please sign in to comment.