Skip to content

Commit

Permalink
2nd step toward Investigate and propose package repositories API with…
Browse files Browse the repository at this point in the history
… similar core interface to packages API. #3496  (#4476)

* attempt #2

* checkpoint #1

* 2nd checkpoint

* Michael's feedback
  • Loading branch information
gfichtenholt authored Mar 22, 2022
1 parent 2ca691c commit fd89bfe
Show file tree
Hide file tree
Showing 44 changed files with 9,753 additions and 3,958 deletions.
38 changes: 34 additions & 4 deletions cmd/kubeapps-apis/core/packages/v1alpha1/repositories.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,45 @@ func (s repositoriesServer) AddPackageRepository(ctx context.Context, request *p
return nil, status.Errorf(status.Convert(err).Code(), "Unable to add package repository %q using the plugin %q: %v", request.Name, request.Plugin.Name, err)
}

// TODO (gfichtenholt)
// Validate the plugin response
//if response.InstalledPackageRef == nil {
// return nil, status.Errorf(codes.Internal, "Invalid CreateInstalledPackage response from the plugin %v: %v", pluginWithServer.plugin.Name, err)
//}
if response.PackageRepoRef == nil {
return nil, status.Errorf(codes.Internal, "Invalid AddPackageRepository response from the plugin %v: %v", pluginWithServer.plugin.Name, err)
}

return response, nil
}

func (s repositoriesServer) GetPackageRepositoryDetail(ctx context.Context, request *packages.GetPackageRepositoryDetailRequest) (*packages.GetPackageRepositoryDetailResponse, error) {
contextMsg := fmt.Sprintf("(identifier=%q, cluster=%q, namespace=%q)", request.GetPackageRepoRef().GetIdentifier(), request.GetPackageRepoRef().GetContext().GetCluster(), request.GetPackageRepoRef().GetContext().GetNamespace())
log.Infof("+core GetPackageRepositoryDetail %s", contextMsg)

if request.GetPackageRepoRef().GetPlugin() == nil {
return nil, status.Errorf(codes.InvalidArgument, "Unable to retrieve the plugin (missing PackageRepoRef.Plugin)")
}

// Retrieve the plugin with server matching the requested plugin name
pluginWithServer := s.getPluginWithServer(request.PackageRepoRef.Plugin)
if pluginWithServer == nil {
return nil, status.Errorf(codes.Internal, "Unable to get the plugin %v", request.PackageRepoRef.Plugin)
}

// Get the response from the requested plugin
response, err := pluginWithServer.server.GetPackageRepositoryDetail(ctx, request)
if err != nil {
return nil, status.Errorf(status.Convert(err).Code(), "Unable to get the package repository detail for the repository %q using the plugin %q: %v", request.PackageRepoRef.Identifier, request.PackageRepoRef.Plugin.Name, err)
}

// Validate the plugin response
if response.GetDetail().GetPackageRepoRef() == nil {
return nil, status.Errorf(codes.Internal, "Invalid package reposirtory detail response from the plugin %v: %v", pluginWithServer.plugin.Name, err)
}

// Build the response
return &packages.GetPackageRepositoryDetailResponse{
Detail: response.Detail,
}, nil
}

// getPluginWithServer returns the *pkgPluginsWithServer from a given packagesServer
// matching the plugin name
func (s repositoriesServer) getPluginWithServer(plugin *v1alpha1.Plugin) *repoPluginsWithServer {
Expand Down
115 changes: 114 additions & 1 deletion cmd/kubeapps-apis/core/packages/v1alpha1/repositories_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,47 @@ import (
"google.golang.org/grpc/status"
)

var mockedRepoPlugin1 = makeDefaultTestRepositoriesPlugin("mock1")
var mockedRepoPlugin2 = makeDefaultTestRepositoriesPlugin("mock2")
var mockedNotFoundRepoPlugin = makeOnlyStatusTestRepositoriesPlugin("bad-plugin", codes.NotFound)

var ignoreUnexportedRepoOpts = cmpopts.IgnoreUnexported(
corev1.AddPackageRepositoryRequest{},
corev1.AddPackageRepositoryResponse{},
corev1.Context{},
plugins.Plugin{},
corev1.PackageRepositoryReference{},
corev1.GetPackageRepositoryDetailRequest{},
corev1.GetPackageRepositoryDetailResponse{},
corev1.PackageRepositoryDetail{},
corev1.PackageRepositoryStatus{},
)

func makeDefaultTestRepositoriesPlugin(pluginName string) repoPluginsWithServer {
pluginDetails := &plugins.Plugin{Name: pluginName, Version: "v1alpha1"}
repositoriesPluginServer := &plugin_test.TestRepositoriesPluginServer{Plugin: pluginDetails}

repositoriesPluginServer.PackageRepositoryDetail =
plugin_test.MakePackageRepositoryDetail("repo-1", pluginDetails)

return repoPluginsWithServer{
plugin: pluginDetails,
server: repositoriesPluginServer,
}
}

func makeOnlyStatusTestRepositoriesPlugin(pluginName string, statusCode codes.Code) repoPluginsWithServer {
pluginDetails := &plugins.Plugin{Name: pluginName, Version: "v1alpha1"}
repositoriesPluginServer := &plugin_test.TestRepositoriesPluginServer{Plugin: pluginDetails}

repositoriesPluginServer.Status = statusCode

return repoPluginsWithServer{
plugin: pluginDetails,
server: repositoriesPluginServer,
}
}

func TestAddPackageRepository(t *testing.T) {
testCases := []struct {
name string
Expand All @@ -47,7 +81,16 @@ func TestAddPackageRepository(t *testing.T) {
},
Name: "repo-1",
},
expectedResponse: &corev1.AddPackageRepositoryResponse{},
expectedResponse: &corev1.AddPackageRepositoryResponse{
PackageRepoRef: &corev1.PackageRepositoryReference{
Context: &corev1.Context{
Cluster: "default",
Namespace: "my-ns",
},
Identifier: "repo-1",
Plugin: &plugins.Plugin{Name: "plugin-1", Version: "v1alpha1"},
},
},
},
{
name: "returns invalid argument if plugin not specified in request",
Expand Down Expand Up @@ -102,3 +145,73 @@ func TestAddPackageRepository(t *testing.T) {
})
}
}

func TestGetPackageRepositoryDetail(t *testing.T) {
testCases := []struct {
name string
configuredPlugins []repoPluginsWithServer
statusCode codes.Code
request *corev1.GetPackageRepositoryDetailRequest
expectedResponse *corev1.GetPackageRepositoryDetailResponse
}{
{
name: "it should successfully call the core GetPackageRepositoryDetail operation",
configuredPlugins: []repoPluginsWithServer{
mockedRepoPlugin1,
mockedRepoPlugin2,
},
request: &corev1.GetPackageRepositoryDetailRequest{
PackageRepoRef: &corev1.PackageRepositoryReference{
Context: &corev1.Context{
Cluster: plugin_test.GlobalPackagingCluster,
Namespace: plugin_test.DefaultNamespace,
},
Identifier: "repo-1",
Plugin: mockedPackagingPlugin1.plugin,
},
},
expectedResponse: &corev1.GetPackageRepositoryDetailResponse{
Detail: plugin_test.MakePackageRepositoryDetail("repo-1", mockedRepoPlugin1.plugin),
},
statusCode: codes.OK,
},
{
name: "it should fail when calling the core GetPackageRepositoryDetail operation when the package is not present in a plugin",
configuredPlugins: []repoPluginsWithServer{
mockedRepoPlugin1,
mockedNotFoundRepoPlugin,
},
request: &corev1.GetPackageRepositoryDetailRequest{
PackageRepoRef: &corev1.PackageRepositoryReference{
Context: &corev1.Context{
Cluster: plugin_test.GlobalPackagingCluster,
Namespace: plugin_test.DefaultNamespace,
},
Identifier: "repo-1",
Plugin: mockedNotFoundPackagingPlugin.plugin,
},
},
statusCode: codes.NotFound,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
server := &repositoriesServer{
pluginsWithServers: tc.configuredPlugins,
}
packageRepoDetail, err := server.GetPackageRepositoryDetail(
context.Background(), tc.request)

if got, want := status.Code(err), tc.statusCode; got != want {
t.Fatalf("got: %+v, want: %+v, err: %+v", got, want, err)
}

if tc.statusCode == codes.OK {
if got, want := packageRepoDetail, tc.expectedResponse; !cmp.Equal(got, want, ignoreUnexportedRepoOpts) {
t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(want, got, ignoreUnexportedRepoOpts))
}
}
})
}
}
Loading

0 comments on commit fd89bfe

Please sign in to comment.