Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic registry support #2940

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
28d0ce3
Draft PR for dynamic registry support
GeekArthur Apr 20, 2020
04c4d07
Handle migration
GeekArthur Apr 21, 2020
1f2a4b3
Handle migration with experimental
GeekArthur Apr 21, 2020
9cf7c36
Improve error handling
GeekArthur Apr 22, 2020
a40281b
Add unit tests
GeekArthur Apr 22, 2020
e2d130f
Merge branch 'master' of github.com:openshift/odo into issue-2635-dyn…
GeekArthur Apr 23, 2020
a71b709
Fix unit tests
GeekArthur Apr 23, 2020
ec63b1f
Fix unit tests
GeekArthur Apr 23, 2020
e3c008d
Add integration tests
GeekArthur Apr 24, 2020
961f892
Merge branch 'master' of github.com:openshift/odo into issue-2635-dyn…
GeekArthur Apr 24, 2020
0103686
Merge branch 'master' of github.com:openshift/odo into issue-2635-dyn…
GeekArthur Apr 28, 2020
6e95e77
Update "odo delete" and display registry name
GeekArthur Apr 28, 2020
23a3ac6
Add confirmation dialog for update and delete
GeekArthur Apr 28, 2020
4d3b9bd
Fix catalog test
GeekArthur Apr 28, 2020
d6814d4
Update help page and delete functions
GeekArthur Apr 29, 2020
7562684
Help page cleanup
GeekArthur Apr 29, 2020
cf89ee6
update confirmation page
GeekArthur Apr 29, 2020
ad4fe22
Add URL validation
GeekArthur Apr 29, 2020
cd66e5c
Fix unit test
GeekArthur Apr 29, 2020
0e34086
Use built-in library for URL parsing
GeekArthur Apr 30, 2020
6eb07c2
Merge branch 'master' of github.com:openshift/odo into issue-2635-dyn…
GeekArthur May 4, 2020
9a8be3f
Update message
GeekArthur May 4, 2020
f2cd807
Update help page and use const default registry
GeekArthur May 6, 2020
af8538d
Update registry URL
GeekArthur May 6, 2020
be57e72
Update help page
GeekArthur May 6, 2020
cc942de
Update registry tests
GeekArthur May 6, 2020
0497d50
Add github registry example
GeekArthur May 6, 2020
62febdb
Update template
GeekArthur May 6, 2020
ec4f95c
Fix typo
GeekArthur May 6, 2020
a573c7f
Merge branch 'master' of github.com:openshift/odo into issue-2635-dyn…
GeekArthur May 6, 2020
4d1d229
Update k8s packages
GeekArthur May 6, 2020
0fc8488
Fix registry test
GeekArthur May 7, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ jobs:
# scenario of docker devfile url testing needs only Kube config file. So the test has been
# added here just to make sure docker devfile url command test gets a proper kube config file.
# without creating a separate OpenShift cluster.
name: "devfile catalog, create, push, delete and docker devfile url command integration tests"
name: "devfile catalog, create, push, delete, registry and docker devfile url command integration tests"
GeekArthur marked this conversation as resolved.
Show resolved Hide resolved
script:
- ./scripts/oc-cluster.sh
- make bin
Expand All @@ -143,6 +143,7 @@ jobs:
- travis_wait make test-cmd-devfile-push
- travis_wait make test-cmd-devfile-watch
- travis_wait make test-cmd-devfile-delete
- travis_wait make test-cmd-devfile-registry
- odo logout

- <<: *base-test
Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ test-cmd-devfile-watch:
.PHONY: test-cmd-devfile-delete
test-cmd-devfile-delete:
ginkgo $(GINKGO_FLAGS) -focus="odo devfile delete command tests" tests/integration/devfile/

# Run odo devfile registry command tests
.PHONY: test-cmd-devfile-registry
test-cmd-devfile-registry:
ginkgo $(GINKGO_FLAGS) -focus="odo devfile registry command tests" tests/integration/devfile/

# Run odo storage command tests
.PHONY: test-cmd-storage
Expand Down
64 changes: 51 additions & 13 deletions pkg/catalog/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,42 @@ import (
"strings"

imagev1 "github.com/openshift/api/image/v1"
"github.com/openshift/odo/pkg/log"
"github.com/openshift/odo/pkg/occlient"
"github.com/openshift/odo/pkg/preference"
"github.com/openshift/odo/pkg/util"
"github.com/pkg/errors"
"gopkg.in/yaml.v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog"
)

// DevfileRegistries contains the links of all devfile registries
var DevfileRegistries = []string{
"https://raw.githubusercontent.com/elsony/devfile-registry/master",
"https://che-devfile-registry.openshift.io/",
// GetDevfileRegistries gets devfile registries from preference file,
// if registry name is specified return the specific registry, otherwise return all registries
func GetDevfileRegistries(registryName string) (map[string]string, error) {
devfileRegistries := make(map[string]string)

cfg, err := preference.New()
if err != nil {
return nil, err
}

if cfg.OdoSettings.RegistryList != nil {
for _, registry := range *cfg.OdoSettings.RegistryList {
if len(registryName) != 0 {
if registryName == registry.Name {
devfileRegistries[registry.Name] = registry.URL
return devfileRegistries, nil
}
} else {
devfileRegistries[registry.Name] = registry.URL
}
}
} else {
return nil, nil
}

return devfileRegistries, nil
}

// GetDevfileIndex loads the devfile registry index.json
Expand Down Expand Up @@ -103,16 +127,26 @@ func IsDevfileComponentSupported(devfile Devfile) bool {
}

// ListDevfileComponents lists all the available devfile components
func ListDevfileComponents() (DevfileComponentTypeList, error) {
func ListDevfileComponents(registryName string) (DevfileComponentTypeList, error) {
var catalogDevfileList DevfileComponentTypeList
catalogDevfileList.DevfileRegistries = DevfileRegistries
var err error

// Get devfile registries
catalogDevfileList.DevfileRegistries, err = GetDevfileRegistries(registryName)
if err != nil {
return catalogDevfileList, err
}
if catalogDevfileList.DevfileRegistries == nil {
return catalogDevfileList, nil
}

for _, devfileRegistry := range DevfileRegistries {
for registryName, registryURL := range catalogDevfileList.DevfileRegistries {
// Load the devfile registry index.json
devfileIndexLink := devfileRegistry + "/devfiles/index.json"
devfileIndexLink := registryURL + "/devfiles/index.json"
devfileIndex, err := GetDevfileIndex(devfileIndexLink)
if err != nil {
return DevfileComponentTypeList{}, err
log.Warningf("Registry %s is not set up properly with error: %v", registryName, err)
break
}

// 1. Load devfiles that indexed in devfile registry index.json
Expand All @@ -122,14 +156,15 @@ func ListDevfileComponents() (DevfileComponentTypeList, error) {
devfileIndexEntryLink := devfileIndexEntry.Links.Link

// Load the devfile
devfileLink := devfileRegistry + devfileIndexEntryLink
// TODO: We send http get resquest in this function mutiple times
devfileLink := registryURL + devfileIndexEntryLink
// TODO: We send http get resquest in this function multiple times
// since devfile registry uses different links to host different devfiles,
// this can reduce the performance especially when we load devfiles from
// big registry. We may need to rethink and optimize this in the future
devfile, err := GetDevfile(devfileLink)
if err != nil {
return DevfileComponentTypeList{}, err
log.Warningf("Registry %s is not set up properly with error: %v", registryName, err)
break
}

// Populate devfile component with devfile data and form devfile component list
Expand All @@ -139,7 +174,10 @@ func ListDevfileComponents() (DevfileComponentTypeList, error) {
Description: devfileIndexEntry.Description,
Link: devfileIndexEntryLink,
Support: IsDevfileComponentSupported(devfile),
Registry: devfileRegistry,
Registry: Registry{
Name: registryName,
URL: registryURL,
},
}

catalogDevfileList.Items = append(catalogDevfileList.Items, catalogDevfile)
Expand Down
64 changes: 64 additions & 0 deletions pkg/catalog/catalog_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package catalog

import (
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"reflect"
"testing"

imagev1 "github.com/openshift/api/image/v1"
"github.com/openshift/odo/pkg/occlient"
"github.com/openshift/odo/pkg/preference"
"github.com/openshift/odo/pkg/testingutil"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -168,6 +171,67 @@ func TestSliceSupportedTags(t *testing.T) {
}
}

func TestGetDevfileRegistries(t *testing.T) {
tempConfigFile, err := ioutil.TempFile("", "odoconfig")
if err != nil {
t.Fatal("Fail to create temporary config file")
}
defer os.Remove(tempConfigFile.Name())
defer tempConfigFile.Close()
_, err = tempConfigFile.Write([]byte(
`kind: Preference
apiversion: odo.openshift.io/v1alpha1
OdoSettings:
Experimental: true
RegistryList:
- Name: CheDevfileRegistry
URL: https://che-devfile-registry.openshift.io/
- Name: DefaultDevfileRegistry
URL: https://raw.githubusercontent.com/elsony/devfile-registry/master`,
))
if err != nil {
t.Error(err)
}

os.Setenv(preference.GlobalConfigEnvName, tempConfigFile.Name())
defer os.Unsetenv(preference.GlobalConfigEnvName)

tests := []struct {
name string
registryName string
want map[string]string
}{
{
name: "Case 1: Test get all devfile registries",
registryName: "",
want: map[string]string{
"CheDevfileRegistry": "https://che-devfile-registry.openshift.io/",
"DefaultDevfileRegistry": "https://raw.githubusercontent.com/elsony/devfile-registry/master",
},
},
{
name: "Case 2: Test get specific devfile registry",
registryName: "CheDevfileRegistry",
want: map[string]string{
"CheDevfileRegistry": "https://che-devfile-registry.openshift.io/",
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetDevfileRegistries(tt.registryName)
if err != nil {
t.Errorf("Error message is %v", err)
}

if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Got: %v, want: %v", got, tt.want)
}
})
}
}

func TestGetDevfileIndex(t *testing.T) {
// Start a local HTTP server
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
Expand Down
10 changes: 8 additions & 2 deletions pkg/catalog/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,20 @@ type ComponentType struct {
Spec ComponentSpec `json:"spec,omitempty"`
}

// Registry is the main struct of devfile registry
type Registry struct {
Name string
URL string
}

// DevfileComponentType is the main struct for devfile catalog components
type DevfileComponentType struct {
Name string
DisplayName string
Description string
Link string
Support bool
Registry string
Registry Registry
}

// DevfileIndexEntry is the main struct of index.json from devfile registry
Expand Down Expand Up @@ -66,7 +72,7 @@ type ComponentTypeList struct {

// DevfileComponentTypeList lists all the DevfileComponentType's
type DevfileComponentTypeList struct {
DevfileRegistries []string
DevfileRegistries map[string]string
Items []DevfileComponentType
}

Expand Down
10 changes: 7 additions & 3 deletions pkg/odo/cli/catalog/list/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,14 @@ func (o *ListComponentsOptions) Complete(name string, cmd *cobra.Command, args [
}

if experimental.IsExperimentalModeEnabled() {
o.catalogDevfileList, err = catalog.ListDevfileComponents()
o.catalogDevfileList, err = catalog.ListDevfileComponents("")
GeekArthur marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}

if o.catalogDevfileList.DevfileRegistries == nil {
log.Warning("Please run 'odo registry add <registry name> <registry URL>' to add registry for listing devfile components\n")
cdrage marked this conversation as resolved.
Show resolved Hide resolved
}
}

return
Expand Down Expand Up @@ -130,7 +134,7 @@ func (o *ListComponentsOptions) Run() (err error) {

if len(supDevfileCatalogList) != 0 || (o.listAllDevfileComponents && len(unsupDevfileCatalogList) != 0) {
fmt.Fprintln(w, "Odo Devfile Components:")
fmt.Fprintln(w, "NAME", "\t", "DESCRIPTION", "\t", "SUPPORTED")
fmt.Fprintln(w, "NAME", "\t", "DESCRIPTION", "\t", "REGISTRY", "\t", "SUPPORTED")

if len(supDevfileCatalogList) != 0 {
supported = "YES"
Expand Down Expand Up @@ -192,6 +196,6 @@ func (o *ListComponentsOptions) printCatalogList(w io.Writer, catalogList []cata

func (o *ListComponentsOptions) printDevfileCatalogList(w io.Writer, catalogDevfileList []catalog.DevfileComponentType, supported string) {
for _, devfileComponent := range catalogDevfileList {
fmt.Fprintln(w, devfileComponent.Name, "\t", devfileComponent.Description, "\t", supported)
fmt.Fprintln(w, devfileComponent.Name, "\t", devfileComponent.Description, "\t", devfileComponent.Registry.Name, "\t", supported)
}
}
8 changes: 8 additions & 0 deletions pkg/odo/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ import (
"github.com/openshift/odo/pkg/odo/cli/plugins"
"github.com/openshift/odo/pkg/odo/cli/preference"
"github.com/openshift/odo/pkg/odo/cli/project"
"github.com/openshift/odo/pkg/odo/cli/registry"
"github.com/openshift/odo/pkg/odo/cli/service"
"github.com/openshift/odo/pkg/odo/cli/storage"
"github.com/openshift/odo/pkg/odo/cli/url"
"github.com/openshift/odo/pkg/odo/cli/utils"
"github.com/openshift/odo/pkg/odo/cli/version"
"github.com/openshift/odo/pkg/odo/util"
odoutil "github.com/openshift/odo/pkg/odo/util"
"github.com/openshift/odo/pkg/odo/util/experimental"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
Expand Down Expand Up @@ -197,6 +199,12 @@ func odoRootCmd(name, fullName string) *cobra.Command {
debug.NewCmdDebug(debug.RecommendedCommandName, util.GetFullName(fullName, debug.RecommendedCommandName)),
)

if experimental.IsExperimentalModeEnabled() {
rootCmd.AddCommand(
registry.NewCmdRegistry(registry.RecommendedCommandName, util.GetFullName(fullName, registry.RecommendedCommandName)),
)
}

odoutil.VisitCommands(rootCmd, reconfigureCmdWithSubcmd)

return rootCmd
Expand Down
16 changes: 12 additions & 4 deletions pkg/odo/cli/component/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ type DevfileMetadata struct {
componentNamespace string
devfileSupport bool
devfileLink string
devfileRegistry string
devfileRegistry catalog.Registry
downloadSource bool
}

Expand Down Expand Up @@ -329,10 +329,13 @@ func (co *CreateOptions) Complete(name string, cmd *cobra.Command, args []string
co.CommonPushOptions.componentContext = co.componentContext
}

catalogDevfileList, err := catalog.ListDevfileComponents()
catalogDevfileList, err := catalog.ListDevfileComponents(co.devfileMetadata.devfileRegistry.Name)
if err != nil {
return err
}
if catalogDevfileList.DevfileRegistries == nil {
log.Warning("Please run `odo registry add <registry name> <registry URL>` to add a registry then create a devfile components\n")
}

var componentType string
var componentName string
Expand Down Expand Up @@ -437,18 +440,22 @@ func (co *CreateOptions) Complete(name string, cmd *cobra.Command, args []string
}
}

registrySpinner := log.Spinnerf("Creating a devfile component from registry: %s", co.devfileMetadata.devfileRegistry.Name)

if co.devfileMetadata.devfileSupport {
err = co.InitEnvInfoFromContext()
if err != nil {
return err
}

spinner.End(true)
registrySpinner.End(true)
return nil
}

spinner.End(false)
log.Italic("\nPlease run 'odo catalog list components' for a list of supported devfile component types")
registrySpinner.End(false)
log.Italic("\nPlease run `odo catalog list components` for a list of supported devfile component types")
}

if len(args) == 0 || !cmd.HasFlags() {
Expand Down Expand Up @@ -773,7 +780,7 @@ func (co *CreateOptions) Run() (err error) {
// Download devfile.yaml file and create env.yaml file
if co.devfileMetadata.devfileSupport {
if !util.CheckPathExists(DevfilePath) {
err := util.DownloadFile(co.devfileMetadata.devfileRegistry+co.devfileMetadata.devfileLink, DevfilePath)
err := util.DownloadFile(co.devfileMetadata.devfileRegistry.URL+co.devfileMetadata.devfileLink, DevfilePath)
if err != nil {
return errors.Wrap(err, "Faile to download devfile.yaml for devfile component")
}
Expand Down Expand Up @@ -899,6 +906,7 @@ func NewCmdCreate(name, fullName string) *cobra.Command {
componentCreateCmd.Flags().StringSliceVar(&co.componentEnvVars, "env", []string{}, "Environmental variables for the component. For example --env VariableName=Value")

if experimental.IsExperimentalModeEnabled() {
componentCreateCmd.Flags().StringVar(&co.devfileMetadata.devfileRegistry.Name, "registry", "", "Create devfile component from specific registry")
componentCreateCmd.Flags().BoolVar(&co.devfileMetadata.downloadSource, "downloadSource", false, "Download sample project from devfile. (ex. odo component create <component_type> [component_name] --downloadSource")
}

Expand Down
Loading