mirror of
https://github.com/argoproj/argo-cd
synced 2026-04-21 17:07:16 +00:00
Add 0.3.0 to 0.4.0 migration utility (#186)
* Add temp migrate utility * Fix errors, separate out migrate for now * Update script with suggestions from @jessesuen * Check for localhost, server address now; print with log, not fmt * Add more log lines, standardize output, fix args * Improve feedback, thanks @alexmt * Rename migration script, thanks @jessesuen * Don't run UpdateSpec unless a change has occurred * Move migrate => hack/migrate, thanks @jessesuen
This commit is contained in:
parent
2bc0dff135
commit
6b554e5f4e
1 changed files with 168 additions and 0 deletions
168
hack/migrate/migrate0.3.0to0.4.0.go
Normal file
168
hack/migrate/migrate0.3.0to0.4.0.go
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
|
||||
appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/server/application"
|
||||
"github.com/argoproj/argo-cd/server/repository"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
// origRepoURLToSecretName hashes repo URL to the secret name using a formula.
|
||||
// Part of the original repo name is incorporated for debugging purposes
|
||||
func origRepoURLToSecretName(repo string) string {
|
||||
repo = git.NormalizeGitURL(repo)
|
||||
h := fnv.New32a()
|
||||
_, _ = h.Write([]byte(repo))
|
||||
parts := strings.Split(strings.TrimSuffix(repo, ".git"), "/")
|
||||
return fmt.Sprintf("repo-%s-%v", strings.ToLower(parts[len(parts)-1]), h.Sum32())
|
||||
}
|
||||
|
||||
// repoURLToSecretName hashes repo URL to the secret name using a formula.
|
||||
// Part of the original repo name is incorporated for debugging purposes
|
||||
func repoURLToSecretName(repo string) string {
|
||||
repo = strings.ToLower(git.NormalizeGitURL(repo))
|
||||
h := fnv.New32a()
|
||||
_, _ = h.Write([]byte(repo))
|
||||
parts := strings.Split(strings.TrimSuffix(repo, ".git"), "/")
|
||||
return fmt.Sprintf("repo-%s-%v", parts[len(parts)-1], h.Sum32())
|
||||
}
|
||||
|
||||
// RenameSecret renames a Kubernetes secret in a given namespace.
|
||||
func renameSecret(namespace, oldName, newName string) {
|
||||
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
|
||||
overrides := clientcmd.ConfigOverrides{}
|
||||
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &overrides)
|
||||
|
||||
log.Printf("Renaming secret %q to %q in namespace %q\n", oldName, newName, namespace)
|
||||
|
||||
config, err := clientConfig.ClientConfig()
|
||||
if err != nil {
|
||||
log.Println("Could not retrieve client config: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
kubeclientset := kubernetes.NewForConfigOrDie(config)
|
||||
repoSecret, err := kubeclientset.CoreV1().Secrets(namespace).Get(oldName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Println("Could not retrieve old secret: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
repoSecret.ObjectMeta.Name = newName
|
||||
repoSecret.ObjectMeta.ResourceVersion = ""
|
||||
|
||||
repoSecret, err = kubeclientset.CoreV1().Secrets(namespace).Create(repoSecret)
|
||||
if err != nil {
|
||||
log.Println("Could not create new secret: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = kubeclientset.CoreV1().Secrets(namespace).Delete(oldName, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
log.Println("Could not remove old secret: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
// RenameRepositorySecrets ensures that repository secrets use the new naming format.
|
||||
func renameRepositorySecrets(clientOpts argocdclient.ClientOptions, namespace string) {
|
||||
conn, repoIf := argocdclient.NewClientOrDie(&clientOpts).NewRepoClientOrDie()
|
||||
defer util.Close(conn)
|
||||
repos, err := repoIf.List(context.Background(), &repository.RepoQuery{})
|
||||
if err != nil {
|
||||
log.Println("An error occurred, so skipping secret renaming: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("Renaming repository secrets...")
|
||||
for _, repo := range repos.Items {
|
||||
oldSecretName := origRepoURLToSecretName(repo.Repo)
|
||||
newSecretName := repoURLToSecretName(repo.Repo)
|
||||
if oldSecretName != newSecretName {
|
||||
log.Printf("Repo %q had its secret name change, so updating\n", repo.Repo)
|
||||
renameSecret(namespace, oldSecretName, newSecretName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PopulateAppDestinations ensures that apps have a Server and Namespace set explicitly.
|
||||
func populateAppDestinations(clientOpts argocdclient.ClientOptions) {
|
||||
conn, appIf := argocdclient.NewClientOrDie(&clientOpts).NewApplicationClientOrDie()
|
||||
defer util.Close(conn)
|
||||
apps, err := appIf.List(context.Background(), &application.ApplicationQuery{})
|
||||
if err != nil {
|
||||
log.Println("An error occurred, so skipping destination population: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("Populating app Destination fields")
|
||||
for _, app := range apps.Items {
|
||||
changed := false
|
||||
|
||||
log.Printf("Ensuring destination field is populated on app %q\n", app.ObjectMeta.Name)
|
||||
if app.Spec.Destination.Server == "" {
|
||||
if app.Status.ComparisonResult.Status == appv1.ComparisonStatusUnknown || app.Status.ComparisonResult.Status == appv1.ComparisonStatusError {
|
||||
log.Printf("App %q was missing Destination.Server, but could not fill it in: %s", app.ObjectMeta.Name, app.Status.ComparisonResult.Status)
|
||||
} else {
|
||||
log.Printf("App %q was missing Destination.Server, so setting to %q\n", app.ObjectMeta.Name, app.Status.ComparisonResult.Server)
|
||||
app.Spec.Destination.Server = app.Status.ComparisonResult.Server
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
if app.Spec.Destination.Namespace == "" {
|
||||
if app.Status.ComparisonResult.Status == appv1.ComparisonStatusUnknown || app.Status.ComparisonResult.Status == appv1.ComparisonStatusError {
|
||||
log.Printf("App %q was missing Destination.Namespace, but could not fill it in: %s", app.ObjectMeta.Name, app.Status.ComparisonResult.Status)
|
||||
} else {
|
||||
log.Printf("App %q was missing Destination.Namespace, so setting to %q\n", app.ObjectMeta.Name, app.Status.ComparisonResult.Namespace)
|
||||
app.Spec.Destination.Namespace = app.Status.ComparisonResult.Namespace
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
if changed {
|
||||
_, err = appIf.UpdateSpec(context.Background(), &application.ApplicationSpecRequest{
|
||||
AppName: app.Name,
|
||||
Spec: &app.Spec,
|
||||
})
|
||||
if err != nil {
|
||||
log.Println("An error occurred (but continuing anyway): ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 3 {
|
||||
log.Fatalf("USAGE: %s SERVER NAMESPACE\n", os.Args[0])
|
||||
}
|
||||
server, namespace := os.Args[1], os.Args[2]
|
||||
log.Printf("Using argocd server %q and namespace %q\n", server, namespace)
|
||||
|
||||
isLocalhost := false
|
||||
switch {
|
||||
case strings.HasPrefix(server, "localhost:"):
|
||||
isLocalhost = true
|
||||
case strings.HasPrefix(server, "127.0.0.1:"):
|
||||
isLocalhost = true
|
||||
}
|
||||
|
||||
clientOpts := argocdclient.ClientOptions{
|
||||
ServerAddr: server,
|
||||
Insecure: true,
|
||||
PlainText: isLocalhost,
|
||||
}
|
||||
renameRepositorySecrets(clientOpts, namespace)
|
||||
populateAppDestinations(clientOpts)
|
||||
}
|
||||
Loading…
Reference in a new issue