mirror of
https://github.com/argoproj/argo-cd
synced 2026-05-24 01:38:43 +00:00
Support resource import/export (#255)
* Add initial prototype for export * Add client opts to argocd-util * Make flags local * Support output to file without piping * Add comment to NewExportCommand * Vastly clean up output, thanks @alexmt @jessesuen * Nullify operation, thanks @alexmt * Add additional error check * Rm extraneous fmt.Sprint * Clone export command to import * Flesh out import feature * Use const string for YAML separator * Don't export enclosing lists * Almost finished prototyping import * Create settings now, too * Create all resources now * Nullify certificate before export * Add JSON annotations, update comment * Warn, don't fail, if cluster/repo already exist, thanks @alexmt * Use minus instead of stdin/stdout, thanks @jessesuen
This commit is contained in:
parent
44a33b0a5f
commit
0818f698e6
2 changed files with 178 additions and 9 deletions
|
|
@ -6,14 +6,20 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"github.com/argoproj/argo-cd/util/cli"
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
"github.com/argoproj/argo-cd/util/dex"
|
||||
"github.com/argoproj/argo-cd/util/settings"
|
||||
"github.com/ghodss/yaml"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
|
|
@ -26,6 +32,9 @@ import (
|
|||
const (
|
||||
// CLIName is the name of the CLI
|
||||
cliName = "argocd-util"
|
||||
|
||||
// YamlSeparator separates sections of a YAML file
|
||||
yamlSeparator = "\n---\n"
|
||||
)
|
||||
|
||||
// NewCommand returns a new instance of an argocd command
|
||||
|
|
@ -45,6 +54,8 @@ func NewCommand() *cobra.Command {
|
|||
command.AddCommand(cli.NewVersionCmd(cliName))
|
||||
command.AddCommand(NewRunDexCommand())
|
||||
command.AddCommand(NewGenDexConfigCommand())
|
||||
command.AddCommand(NewImportCommand())
|
||||
command.AddCommand(NewExportCommand())
|
||||
|
||||
command.Flags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
|
||||
return command
|
||||
|
|
@ -154,6 +165,164 @@ func NewGenDexConfigCommand() *cobra.Command {
|
|||
return &command
|
||||
}
|
||||
|
||||
// NewImportCommand defines a new command for exporting Kubernetes and Argo CD resources.
|
||||
func NewImportCommand() *cobra.Command {
|
||||
var (
|
||||
clientConfig clientcmd.ClientConfig
|
||||
in string
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: "import",
|
||||
Short: "Import Argo CD data",
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
var (
|
||||
input []byte
|
||||
err error
|
||||
newSettings *settings.ArgoCDSettings
|
||||
newRepos []*v1alpha1.Repository
|
||||
newClusters []*v1alpha1.Cluster
|
||||
newApps []*v1alpha1.Application
|
||||
)
|
||||
if in == "-" {
|
||||
input, err = ioutil.ReadAll(os.Stdin)
|
||||
errors.CheckError(err)
|
||||
} else {
|
||||
input, err = ioutil.ReadFile(in)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
inputStrings := strings.Split(string(input), yamlSeparator)
|
||||
|
||||
err = yaml.Unmarshal([]byte(inputStrings[0]), &newSettings)
|
||||
errors.CheckError(err)
|
||||
|
||||
err = yaml.Unmarshal([]byte(inputStrings[1]), &newRepos)
|
||||
errors.CheckError(err)
|
||||
|
||||
err = yaml.Unmarshal([]byte(inputStrings[2]), &newClusters)
|
||||
errors.CheckError(err)
|
||||
|
||||
err = yaml.Unmarshal([]byte(inputStrings[3]), &newApps)
|
||||
errors.CheckError(err)
|
||||
|
||||
config, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
kubeClientset := kubernetes.NewForConfigOrDie(config)
|
||||
|
||||
settingsMgr := settings.NewSettingsManager(kubeClientset, namespace)
|
||||
err = settingsMgr.SaveSettings(newSettings)
|
||||
errors.CheckError(err)
|
||||
db := db.NewDB(namespace, kubeClientset)
|
||||
|
||||
for _, repo := range newRepos {
|
||||
_, err := db.CreateRepository(context.Background(), repo)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, cluster := range newClusters {
|
||||
_, err := db.CreateCluster(context.Background(), cluster)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
}
|
||||
|
||||
appClientset := appclientset.NewForConfigOrDie(config)
|
||||
for _, app := range newApps {
|
||||
out, err := appClientset.ArgoprojV1alpha1().Applications(namespace).Create(app)
|
||||
errors.CheckError(err)
|
||||
log.Println(out)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(&command)
|
||||
command.Flags().StringVarP(&in, "in", "i", "-", "Input from the specified file instead of stdin")
|
||||
|
||||
return &command
|
||||
}
|
||||
|
||||
// NewExportCommand defines a new command for exporting Kubernetes and Argo CD resources.
|
||||
func NewExportCommand() *cobra.Command {
|
||||
var (
|
||||
clientConfig clientcmd.ClientConfig
|
||||
out string
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: "export",
|
||||
Short: "Export all Argo CD data",
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
config, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
kubeClientset := kubernetes.NewForConfigOrDie(config)
|
||||
|
||||
settingsMgr := settings.NewSettingsManager(kubeClientset, namespace)
|
||||
settings, err := settingsMgr.GetSettings()
|
||||
errors.CheckError(err)
|
||||
// certificate data is included in secrets that are exported alongside
|
||||
settings.Certificate = nil
|
||||
settingsData, err := yaml.Marshal(settings)
|
||||
errors.CheckError(err)
|
||||
|
||||
db := db.NewDB(namespace, kubeClientset)
|
||||
clusters, err := db.ListClusters(context.Background())
|
||||
errors.CheckError(err)
|
||||
clusterData, err := yaml.Marshal(clusters.Items)
|
||||
errors.CheckError(err)
|
||||
|
||||
repos, err := db.ListRepositories(context.Background())
|
||||
errors.CheckError(err)
|
||||
repoData, err := yaml.Marshal(repos.Items)
|
||||
errors.CheckError(err)
|
||||
|
||||
appClientset := appclientset.NewForConfigOrDie(config)
|
||||
apps, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(metav1.ListOptions{})
|
||||
errors.CheckError(err)
|
||||
|
||||
// remove extraneous cruft from output
|
||||
for idx, app := range apps.Items {
|
||||
apps.Items[idx].ObjectMeta = metav1.ObjectMeta{
|
||||
Name: app.ObjectMeta.Name,
|
||||
Finalizers: app.ObjectMeta.Finalizers,
|
||||
}
|
||||
apps.Items[idx].Status = v1alpha1.ApplicationStatus{
|
||||
History: app.Status.History,
|
||||
}
|
||||
apps.Items[idx].Operation = nil
|
||||
}
|
||||
appsData, err := yaml.Marshal(apps.Items)
|
||||
errors.CheckError(err)
|
||||
|
||||
outputStrings := []string{
|
||||
string(settingsData),
|
||||
string(repoData),
|
||||
string(clusterData),
|
||||
string(appsData),
|
||||
}
|
||||
output := strings.Join(outputStrings, yamlSeparator)
|
||||
|
||||
if out == "-" {
|
||||
fmt.Println(output)
|
||||
} else {
|
||||
err = ioutil.WriteFile(out, []byte(output), 0644)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(&command)
|
||||
command.Flags().StringVarP(&out, "out", "o", "-", "Output to the specified file instead of stdout")
|
||||
|
||||
return &command
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := NewCommand().Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
|
|
|
|||
|
|
@ -27,24 +27,24 @@ import (
|
|||
type ArgoCDSettings struct {
|
||||
// URL is the externally facing URL users will visit to reach ArgoCD.
|
||||
// The value here is used when configuring SSO. Omitting this value will disable SSO.
|
||||
URL string
|
||||
URL string `json:"url,omitempty"`
|
||||
// DexConfig is contains portions of a dex config yaml
|
||||
DexConfig string
|
||||
DexConfig string `json:"dexConfig,omitempty"`
|
||||
// LocalUsers holds users local to (stored on) the server. This is to be distinguished from any potential alternative future login providers (LDAP, SAML, etc.) that might ever be added.
|
||||
LocalUsers map[string]string
|
||||
LocalUsers map[string]string `json:"localUsers,omitempty"`
|
||||
// ServerSignature holds the key used to generate JWT tokens.
|
||||
ServerSignature []byte
|
||||
ServerSignature []byte `json:"serverSignature,omitempty"`
|
||||
// Certificate holds the certificate/private key for the ArgoCD API server.
|
||||
// If nil, will run insecure without TLS.
|
||||
Certificate *tls.Certificate
|
||||
Certificate *tls.Certificate `json:"-"`
|
||||
// WebhookGitLabSecret holds the shared secret for authenticating GitHub webhook events
|
||||
WebhookGitHubSecret string
|
||||
WebhookGitHubSecret string `json:"webhookGitHubSecret,omitempty"`
|
||||
// WebhookGitLabSecret holds the shared secret for authenticating GitLab webhook events
|
||||
WebhookGitLabSecret string
|
||||
WebhookGitLabSecret string `json:"webhookGitLabSecret,omitempty"`
|
||||
// WebhookBitbucketUUID holds the UUID for authenticating Bitbucket webhook events
|
||||
WebhookBitbucketUUID string
|
||||
WebhookBitbucketUUID string `json:"webhookBitbucketUUID,omitempty"`
|
||||
// Secrets holds all secrets in argocd-secret as a map[string]string
|
||||
Secrets map[string]string
|
||||
Secrets map[string]string `json:"secrets,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
|||
Loading…
Reference in a new issue