Skip to content

Commit

Permalink
[TEP-0079] Add Support Tier in tkn hub install command
Browse files Browse the repository at this point in the history
Part of tektoncd#691. Prior to this change, no support tier, catalog or org information was added to the resource annotation when installing from Hub.

This commit adds `artifacthub.io/catalog`, "artifacthub.io/org" and "artifacthub.io/support-tier" labels to the resource being installed to indicate the source and support tier of the catalog. The 3 labels will only be added when installing with `--type artifact` flag.

Details can be found in https://github.com/tektoncd/community/blob/main/teps/0079-tekton-catalog-support-tiers.md#cli
  • Loading branch information
QuanZhang-William committed Jan 24, 2023
1 parent 22555e2 commit 10b3a62
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 33 deletions.
8 changes: 7 additions & 1 deletion api/pkg/cli/cmd/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,14 @@ func (opts *options) run() error {

resourceInstaller := installer.New(opts.cs)

org, err := opts.hubRes.Org()
if err != nil {
return err
}
hubType := opts.cli.Hub().GetType()

var errors []error
opts.resource, errors = resourceInstaller.Install([]byte(manifest), opts.from, opts.cs.Namespace())
opts.resource, errors = resourceInstaller.Install([]byte(manifest), hubType, org, opts.from, opts.cs.Namespace())

if len(errors) != 0 {
resourcePipelineMinVersion, err := opts.hubRes.MinPipelinesVersion()
Expand Down
4 changes: 2 additions & 2 deletions api/pkg/cli/hub/get_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type artifactHubCatalogResponse struct {
Name string `json:"name,omitempty"`
}

func (c *tektonHubclient) GetAllCatalogs() CatalogResult {
func (c *tektonHubClient) GetAllCatalogs() CatalogResult {
data, status, err := c.Get(tektonHubCatEndpoint)
if status == http.StatusNotFound {
err = nil
Expand Down Expand Up @@ -76,7 +76,7 @@ func (a *artifactHubClient) GetCatalogsList() ([]string, error) {
return cat, nil
}

func (t *tektonHubclient) GetCatalogsList() ([]string, error) {
func (t *tektonHubClient) GetCatalogsList() ([]string, error) {
// Get all catalogs
c := t.GetAllCatalogs()

Expand Down
32 changes: 28 additions & 4 deletions api/pkg/cli/hub/get_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type ResourceResult interface {
ResourceYaml() (string, error)
ResourceVersion() (string, error)
MinPipelinesVersion() (string, error)
Org() (string, error)
UnmarshalData() error
}

Expand Down Expand Up @@ -96,6 +97,11 @@ type ArtifactHubPkgResponse struct {
Name string `json:"name,omitempty"`
Data ArtifactHubPkgData `json:"data,omitempty"`
AvailableVersions []ArtifactHubVersion `json:"available_versions,omitempty"`
Repository ArtifactHubRepo `json:"repository,omitempty"`
}

type ArtifactHubRepo struct {
Org string `json:"organization_name,omitempty"`
}

type ArtifactHubPkgData struct {
Expand All @@ -114,7 +120,7 @@ func (a *artifactHubClient) GetResource(opt ResourceOption) ResourceResult {
}

// GetResource queries the data using Tekton Hub Endpoint
func (t *tektonHubclient) GetResource(opt ResourceOption) ResourceResult {
func (t *tektonHubClient) GetResource(opt ResourceOption) ResourceResult {
data, status, err := t.Get(opt.Endpoint())

return &TektonHubResourceResult{
Expand All @@ -140,7 +146,7 @@ func (a *artifactHubClient) GetResourceYaml(opt ResourceOption) ResourceResult {
}

// GetResourceYaml queries the resource yaml using Tekton Hub Endpoint
func (t *tektonHubclient) GetResourceYaml(opt ResourceOption) ResourceResult {
func (t *tektonHubClient) GetResourceYaml(opt ResourceOption) ResourceResult {

yaml, yamlStatus, yamlErr := t.Get(fmt.Sprintf("/v1/resource/%s/%s/%s/%s/yaml", opt.Catalog, opt.Kind, opt.Name, opt.Version))
data, status, err := t.Get(opt.Endpoint())
Expand All @@ -163,7 +169,7 @@ func (a *artifactHubClient) GetResourcesList(so SearchOption) ([]string, error)
}

// GetResourcesList queries the resources in the catalog using Tekton Hub Endpoint
func (t *tektonHubclient) GetResourcesList(so SearchOption) ([]string, error) {
func (t *tektonHubClient) GetResourcesList(so SearchOption) ([]string, error) {
// Get all resources
result := t.Search(SearchOption{
Kinds: so.Kinds,
Expand Down Expand Up @@ -206,7 +212,7 @@ func (a *artifactHubClient) GetResourceVersionslist(r ResourceOption) ([]string,
}

// GetResourceVersionslist queries the versions of a resource using Tekton Hub Endpoint
func (t *tektonHubclient) GetResourceVersionslist(r ResourceOption) ([]string, error) {
func (t *tektonHubClient) GetResourceVersionslist(r ResourceOption) ([]string, error) {
opts := &ResourceVersionOptions{}
// Get the resource versions
opts.hubResVersionsRes = t.GetResourceVersions(ResourceOption{
Expand Down Expand Up @@ -433,6 +439,24 @@ func (rr *ArtifactHubResourceResult) MinPipelinesVersion() (string, error) {
return resp.Data.PipelineMinVer, nil
}

// Org returns the organization of the catalog from Artifact Hub
func (rr *ArtifactHubResourceResult) Org() (string, error) {
if err := rr.validateData(); err != nil {
return "", err
}
res := ArtifactHubPkgResponse{}
if err := json.Unmarshal(rr.data, &res); err != nil {
return "", err
}
return res.Repository.Org, nil
}

// Org returns the organization of the catalog from Tekton Hub
func (rr *TektonHubResourceResult) Org() (string, error) {
// TODO: implement org() for Tekton Hub
return "", nil
}

func (rr *ArtifactHubResourceResult) validateData() error {
if rr.err != nil {
return rr.err
Expand Down
2 changes: 1 addition & 1 deletion api/pkg/cli/hub/get_resource_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (a *artifactHubClient) GetResourceVersions(opt ResourceOption) ResourceVers
}

// GetResourceVersions queries the data using Tekton Hub Endpoint
func (t *tektonHubclient) GetResourceVersions(opt ResourceOption) ResourceVersionResult {
func (t *tektonHubClient) GetResourceVersions(opt ResourceOption) ResourceVersionResult {

rvr := TektonHubResourceVersionResult{set: false}

Expand Down
14 changes: 7 additions & 7 deletions api/pkg/cli/hub/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,19 @@ type Client interface {
GetResourceVersionslist(opt ResourceOption) ([]string, error)
}

type tektonHubclient struct {
type tektonHubClient struct {
apiURL string
}

type artifactHubClient struct {
apiURL string
}

var _ Client = (*tektonHubclient)(nil)
var _ Client = (*tektonHubClient)(nil)
var _ Client = (*artifactHubClient)(nil)

func NewTektonHubClient() *tektonHubclient {
return &tektonHubclient{apiURL: tektonHubURL}
func NewTektonHubClient() *tektonHubClient {
return &tektonHubClient{apiURL: tektonHubURL}
}

func NewArtifactHubClient() *artifactHubClient {
Expand All @@ -84,7 +84,7 @@ func (a *artifactHubClient) GetType() string {
}

// GetType returns the type of the Hub Client
func (t *tektonHubclient) GetType() string {
func (t *tektonHubClient) GetType() string {
return TektonHubType
}

Expand All @@ -104,7 +104,7 @@ func (a *artifactHubClient) SetURL(apiURL string) error {
// SetURL validates and sets the Tekton Hub apiURL server URL
// URL passed through flag will take precedence over the Tekton Hub API URL
// in config file and default URL
func (t *tektonHubclient) SetURL(apiURL string) error {
func (t *tektonHubClient) SetURL(apiURL string) error {
resUrl, err := resolveUrl(apiURL, "TEKTON_HUB_API_SERVER", tektonHubURL)
if err != nil {
return err
Expand All @@ -120,7 +120,7 @@ func (a *artifactHubClient) Get(endpoint string) ([]byte, int, error) {
}

// Get gets data from Tekton Hub
func (t *tektonHubclient) Get(endpoint string) ([]byte, int, error) {
func (t *tektonHubClient) Get(endpoint string) ([]byte, int, error) {
return get(t.apiURL + endpoint)
}

Expand Down
4 changes: 2 additions & 2 deletions api/pkg/cli/hub/hub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func TestSetURL_TektonHub(t *testing.T) {
tHub := &tektonHubclient{}
tHub := &tektonHubClient{}
err := tHub.SetURL("http://localhost:80000")
assert.NoError(t, err)

Expand Down Expand Up @@ -42,7 +42,7 @@ func TestSetURL_ArtifactHub(t *testing.T) {

func TestSetURL_InvalidCase(t *testing.T) {

hub := &tektonHubclient{}
hub := &tektonHubClient{}
err := hub.SetURL("abc")
assert.Error(t, err)
assert.EqualError(t, err, "parse \"abc\": invalid URI for request")
Expand Down
2 changes: 1 addition & 1 deletion api/pkg/cli/hub/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (a *artifactHubClient) Search(so SearchOption) SearchResult {
}

// Search queries the data using TektonHub Endpoint
func (t *tektonHubclient) Search(so SearchOption) SearchResult {
func (t *tektonHubClient) Search(so SearchOption) SearchResult {
data, status, err := t.Get(so.Endpoint())
if status == http.StatusNotFound {
err = nil
Expand Down
49 changes: 39 additions & 10 deletions api/pkg/cli/installer/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"errors"
"fmt"

"github.com/tektoncd/hub/api/pkg/cli/hub"
tknVer "github.com/tektoncd/hub/api/pkg/cli/version"
kErr "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -27,8 +28,14 @@ import (
)

const (
catalogLabel = "hub.tekton.dev/catalog"
versionLabel = "app.kubernetes.io/version"
versionLabel = "app.kubernetes.io/version"
tektonHubCatalogLabel = "hub.tekton.dev/catalog"
artifactHubCatalogLabel = "artifacthub.io/catalog"
artifactHubOrgLabel = "artifacthub.io/org"
supportTierLabel = "artifacthub.io/support-tier"
communitySupportTier = "Community"
verifiedSupportTier = "Verified"
verifiedCatOrg = "tektoncd"
)

// Errors
Expand Down Expand Up @@ -82,7 +89,7 @@ func (i *Installer) checkVersion(resPipMinVersion string) error {
}

// Install a resource
func (i *Installer) Install(data []byte, catalog, namespace string) (*unstructured.Unstructured, []error) {
func (i *Installer) Install(data []byte, hubType, org, catalog, namespace string) (*unstructured.Unstructured, []error) {

errors := make([]error, 0)

Expand Down Expand Up @@ -110,7 +117,7 @@ func (i *Installer) Install(data []byte, catalog, namespace string) (*unstructur
if err != nil {
// If error is notFoundError then create the resource
if kErr.IsNotFound(err) {
resp, err := i.createRes(newRes, catalog, namespace)
resp, err := i.createRes(newRes, hubType, org, catalog, namespace)
if err != nil {
errors = append(errors, err)
}
Expand Down Expand Up @@ -259,7 +266,7 @@ func checkLabels(res *unstructured.Unstructured) error {
}

_, versionOk := labels[versionLabel]
_, catalogOk := labels[catalogLabel]
_, catalogOk := labels[tektonHubCatalogLabel]

// If both label exist then return nil
if versionOk == catalogOk && versionOk {
Expand All @@ -277,9 +284,11 @@ func checkLabels(res *unstructured.Unstructured) error {
return nil
}

func (i *Installer) createRes(obj *unstructured.Unstructured, catalog, namespace string) (*unstructured.Unstructured, error) {
func (i *Installer) createRes(obj *unstructured.Unstructured, hubType, org, catalog, namespace string) (*unstructured.Unstructured, error) {

addCatalogLabel(obj, catalog)
if err := addCatalogLabel(obj, hubType, org, catalog); err != nil {
return nil, err
}
res, err := i.create(obj, namespace, metav1.CreateOptions{})
if err != nil {
return nil, err
Expand All @@ -289,7 +298,11 @@ func (i *Installer) createRes(obj *unstructured.Unstructured, catalog, namespace

func (i *Installer) updateRes(existing, new *unstructured.Unstructured, catalog, namespace string) (*unstructured.Unstructured, error) {

addCatalogLabel(new, catalog)
// TODO: update addCatalogLabel() params when supporting upgrade/downgrade command for artifact type
if err := addCatalogLabel(new, hub.TektonHubType, "", catalog); err != nil {
return nil, err
}

// replace label, annotation and spec of old resource with new
existing.SetLabels(new.GetLabels())
existing.SetAnnotations(new.GetAnnotations())
Expand All @@ -314,11 +327,27 @@ func toUnstructured(data []byte) (*unstructured.Unstructured, error) {
return res, nil
}

func addCatalogLabel(obj *unstructured.Unstructured, catalog string) {
func addCatalogLabel(obj *unstructured.Unstructured, hubType, org, catalog string) error {
labels := obj.GetLabels()
if len(labels) == 0 {
labels = make(map[string]string)
}
labels[catalogLabel] = catalog

switch hubType {
case hub.TektonHubType:
labels[tektonHubCatalogLabel] = catalog
case hub.ArtifactHubType:
labels[artifactHubCatalogLabel] = catalog
if org == verifiedCatOrg {
labels[supportTierLabel] = verifiedSupportTier
} else {
labels[supportTierLabel] = communitySupportTier
}
labels[artifactHubOrgLabel] = org
default:
return fmt.Errorf("hub type: %s not supported in addCatalogLabel", hubType)
}

obj.SetLabels(labels)
return nil
}
63 changes: 58 additions & 5 deletions api/pkg/cli/installer/action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/tektoncd/hub/api/pkg/cli/hub"
"github.com/tektoncd/hub/api/pkg/cli/test"
cb "github.com/tektoncd/hub/api/pkg/cli/test/builder"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
Expand All @@ -43,12 +44,64 @@ spec:
`

func TestToUnstructuredAndAddLabel(t *testing.T) {
obj, err := toUnstructured([]byte(res))
assert.NoError(t, err)
assert.Equal(t, "foo", obj.GetName())
testCases := []struct {
name string
data string
hubType string
org string
catalog string
wantSupportTier string
wantCatalog string
wantOrg string
}{
{
name: "Install From Tekton Hub",
data: res,
hubType: hub.TektonHubType,
org: "",
catalog: "tekton",
wantCatalog: "tekton",
},
{
name: "Install Verified Catalog From Artifact Hub",
data: res,
hubType: hub.ArtifactHubType,
org: verifiedCatOrg,
catalog: "golang-build",
wantSupportTier: verifiedSupportTier,
wantCatalog: "golang-build",
wantOrg: "tektoncd",
},
{
name: "Install Community Catalog From Artifact Hub",
data: res,
hubType: hub.ArtifactHubType,
org: "tekton-legacy",
catalog: "tekton-catalog-tasks",
wantSupportTier: communitySupportTier,
wantCatalog: "tekton-catalog-tasks",
wantOrg: "tekton-legacy",
},
}

for _, tc := range testCases {
obj, err := toUnstructured([]byte(res))
assert.NoError(t, err)
assert.Equal(t, "foo", obj.GetName())

addCatalogLabel(obj, "tekton")
assert.Equal(t, "tekton", obj.GetLabels()[catalogLabel])
if err := addCatalogLabel(obj, tc.hubType, tc.org, tc.catalog); err != nil {
t.Errorf("%s", err.Error())
}

if tc.hubType == hub.ArtifactHubType {
assert.Equal(t, tc.wantSupportTier, obj.GetLabels()[supportTierLabel])
assert.Equal(t, tc.wantCatalog, obj.GetLabels()[artifactHubCatalogLabel])
assert.Equal(t, tc.wantOrg, obj.GetLabels()[artifactHubOrgLabel])
assert.Equal(t, "", obj.GetLabels()[tektonHubCatalogLabel])
} else {
assert.Equal(t, "tekton", obj.GetLabels()[tektonHubCatalogLabel])
}
}
}

func TestListInstalled(t *testing.T) {
Expand Down

0 comments on commit 10b3a62

Please sign in to comment.