Skip to content

Commit

Permalink
Add support for embedded cluster registry (#4519)
Browse files Browse the repository at this point in the history
* Add support for embedded cluster registry
  • Loading branch information
sgalsaleh committed Mar 22, 2024
1 parent 5fffd1f commit 9882c14
Show file tree
Hide file tree
Showing 9 changed files with 352 additions and 78 deletions.
12 changes: 4 additions & 8 deletions cmd/kots/cli/install.go
Expand Up @@ -760,21 +760,17 @@ func getRegistryConfig(v *viper.Viper, clientset kubernetes.Interface, appSlug s
}
}

isKurl, err := kurl.IsKurl(clientset)
if err != nil {
return nil, errors.Wrap(err, "failed to check if cluster is kurl")
}

isAirgap := false
if v.GetString("airgap-bundle") != "" || v.GetBool("airgap") {
isAirgap = true
}

if registryEndpoint == "" && isKurl && isAirgap {
registryEndpoint, registryUsername, registryPassword, err = kotsutil.GetKurlRegistryCreds()
if registryEndpoint == "" && isAirgap {
clientset, err := k8sutil.GetClientset()
if err != nil {
return nil, errors.Wrap(err, "failed to get kURL registry info")
return nil, errors.Wrap(err, "failed to get clientset")
}
registryEndpoint, registryUsername, registryPassword = kotsutil.GetEmbeddedRegistryCreds(clientset)
if registryNamespace == "" {
registryNamespace = appSlug
}
Expand Down
13 changes: 8 additions & 5 deletions pkg/handlers/airgap.go
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/pkg/errors"
"github.com/replicatedhq/kots/pkg/airgap"
"github.com/replicatedhq/kots/pkg/automation"
"github.com/replicatedhq/kots/pkg/k8sutil"
"github.com/replicatedhq/kots/pkg/kotsutil"
"github.com/replicatedhq/kots/pkg/logger"
"github.com/replicatedhq/kots/pkg/store"
Expand Down Expand Up @@ -363,16 +364,18 @@ func (h *Handler) CreateAppFromAirgap(w http.ResponseWriter, r *http.Request) {
return
}

var registryHost, namespace, username, password string
var isReadOnly bool
registryHost, username, password, err = kotsutil.GetKurlRegistryCreds()
clientset, err := k8sutil.GetClientset()
if err != nil {
logger.Error(err)
logger.Error(errors.Wrap(err, "failed to get k8s clientset"))
w.WriteHeader(http.StatusInternalServerError)
return
}

// if found kurl registry creds, use kurl registry
var namespace string
var isReadOnly bool
registryHost, username, password := kotsutil.GetEmbeddedRegistryCreds(clientset)

// if found embedded registry creds, use embedded registry
if registryHost != "" {
namespace = pendingApp.Slug
} else {
Expand Down
9 changes: 4 additions & 5 deletions pkg/handlers/app.go
Expand Up @@ -18,11 +18,11 @@ import (
"github.com/replicatedhq/kots/pkg/embeddedcluster"
"github.com/replicatedhq/kots/pkg/gitops"
"github.com/replicatedhq/kots/pkg/helm"
"github.com/replicatedhq/kots/pkg/k8sutil"
"github.com/replicatedhq/kots/pkg/kotsutil"
"github.com/replicatedhq/kots/pkg/logger"
"github.com/replicatedhq/kots/pkg/operator"
"github.com/replicatedhq/kots/pkg/rbac"
"github.com/replicatedhq/kots/pkg/registry"
"github.com/replicatedhq/kots/pkg/render"
"github.com/replicatedhq/kots/pkg/session"
"github.com/replicatedhq/kots/pkg/store"
Expand Down Expand Up @@ -73,10 +73,9 @@ func (h *Handler) GetPendingApp(w http.ResponseWriter, r *http.Request) {
}
}

// Carefully now, peek at registry credentials to see if we need to prompt for them
hasKurlRegistry, err := registry.HasKurlRegistry()
clientset, err := k8sutil.GetClientset()
if err != nil {
logger.Error(errors.Wrapf(err, "failed to check registry status for pending app %s", papp.Slug))
logger.Error(errors.Wrap(err, "failed to get clientset"))
w.WriteHeader(http.StatusInternalServerError)
return
}
Expand All @@ -87,7 +86,7 @@ func (h *Handler) GetPendingApp(w http.ResponseWriter, r *http.Request) {
Slug: papp.Slug,
Name: papp.Name,
LicenseData: papp.LicenseData,
NeedsRegistry: !hasKurlRegistry,
NeedsRegistry: !kotsutil.HasEmbeddedRegistry(clientset),
},
}
JSON(w, http.StatusOK, pendingAppResponse)
Expand Down
12 changes: 4 additions & 8 deletions pkg/handlers/license.go
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/pkg/errors"
apptypes "github.com/replicatedhq/kots/pkg/app/types"
"github.com/replicatedhq/kots/pkg/helm"
"github.com/replicatedhq/kots/pkg/k8sutil"
"github.com/replicatedhq/kots/pkg/kotsadm"
kotsadmtypes "github.com/replicatedhq/kots/pkg/kotsadm/types"
license "github.com/replicatedhq/kots/pkg/kotsadmlicense"
Expand All @@ -21,7 +22,6 @@ import (
"github.com/replicatedhq/kots/pkg/logger"
"github.com/replicatedhq/kots/pkg/online"
installationtypes "github.com/replicatedhq/kots/pkg/online/types"
"github.com/replicatedhq/kots/pkg/registry"
"github.com/replicatedhq/kots/pkg/replicatedapp"
"github.com/replicatedhq/kots/pkg/store"
"github.com/replicatedhq/kots/pkg/updatechecker"
Expand Down Expand Up @@ -457,18 +457,14 @@ func (h *Handler) UploadNewLicense(w http.ResponseWriter, r *http.Request) {
uploadLicenseResponse.IsAirgap = true
uploadLicenseResponse.Slug = a.Slug

// This is the comment from the typescript implementation \
// and i thought it should remain

// Carefully now, peek at registry credentials to see if we need to prompt for them
hasKurlRegistry, err := registry.HasKurlRegistry()
clientset, err := k8sutil.GetClientset()
if err != nil {
logger.Error(err)
uploadLicenseResponse.Error = err.Error()
JSON(w, 300, uploadLicenseRequest)
JSON(w, http.StatusInternalServerError, uploadLicenseRequest)
return
}
uploadLicenseResponse.NeedsRegistry = !hasKurlRegistry
uploadLicenseResponse.NeedsRegistry = !kotsutil.HasEmbeddedRegistry(clientset)

JSON(w, 200, uploadLicenseResponse)
}
Expand Down
9 changes: 3 additions & 6 deletions pkg/kotsadmsnapshot/backup.go
Expand Up @@ -384,12 +384,9 @@ func CreateInstanceBackup(ctx context.Context, cluster *downstreamtypes.Downstre
},
}

if isKurl {
registryHost, _, _, err := kotsutil.GetKurlRegistryCreds()
if err != nil {
return nil, errors.Wrap(err, "failed to get kurl registry host")
}
veleroBackup.ObjectMeta.Annotations["kots.io/kurl-registry"] = registryHost
embeddedRegistryHost, _, _ := kotsutil.GetEmbeddedRegistryCreds(clientset)
if embeddedRegistryHost != "" {
veleroBackup.ObjectMeta.Annotations["kots.io/embedded-registry"] = embeddedRegistryHost
}

if cluster.SnapshotTTL != "" {
Expand Down
46 changes: 37 additions & 9 deletions pkg/kotsutil/kurl.go → pkg/kotsutil/embedded.go
Expand Up @@ -9,18 +9,46 @@ import (
corev1 "k8s.io/api/core/v1"
kuberneteserrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)

func GetKurlRegistryCreds() (hostname string, username string, password string, finalErr error) {
clientset, err := k8sutil.GetClientset()
if err != nil {
finalErr = errors.Wrap(err, "failed to get k8s clientset")
return
func HasEmbeddedRegistry(clientset kubernetes.Interface) bool {
var secret *corev1.Secret
var err error

// kURL registry secret is always in the 'default' namespace
// Embedded cluster registry secret is always in the 'kotsadm' namespace

for _, ns := range []string{"default", "kotsadm"} {
secret, err = clientset.CoreV1().Secrets(ns).Get(context.TODO(), "registry-creds", metav1.GetOptions{})
if err == nil {
break
}
}

// kURL registry secret is always in default namespace
secret, err := clientset.CoreV1().Secrets("default").Get(context.TODO(), "registry-creds", metav1.GetOptions{})
if err != nil {
if secret != nil {
if secret.Type == corev1.SecretTypeDockerConfigJson {
return true
}
}

return false
}

func GetEmbeddedRegistryCreds(clientset kubernetes.Interface) (hostname string, username string, password string) {
var secret *corev1.Secret
var err error

// kURL registry secret is always in the 'default' namespace
// Embedded cluster registry secret is always in the 'kotsadm' namespace

for _, ns := range []string{"default", "kotsadm"} {
secret, err = clientset.CoreV1().Secrets(ns).Get(context.TODO(), "registry-creds", metav1.GetOptions{})
if err == nil {
break
}
}
if secret == nil {
return
}

Expand All @@ -44,7 +72,7 @@ func GetKurlRegistryCreds() (hostname string, username string, password string,
}

for host, auth := range dockerConfig.Auths {
if auth.Username == "kurl" {
if auth.Username == "kurl" || auth.Username == "embedded-cluster" {
hostname = host
username = auth.Username
password = auth.Password
Expand Down

0 comments on commit 9882c14

Please sign in to comment.