Skip to content

Commit

Permalink
Refactor code by moving them into separate files (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
puthrayaharness authored Jan 13, 2023
1 parent f7028b6 commit 0c58c14
Show file tree
Hide file tree
Showing 16 changed files with 467 additions and 282 deletions.
88 changes: 63 additions & 25 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# Harness Upgrade
CLI to help customers, CSMs and developers with migrating their current gen harness account to next gen

## Getting Started

### Installation
## Installation
Download the latest release from GitHub releases. We support MacOS(`darwim & amd64`), Linux(`linux + (amd64/arm64)`) and Windows(`windows+amd64`). Please download the right assets. Extract the file anywhere.
We recommend that you move it to a folder that is specified in your path.

Expand All @@ -15,11 +13,12 @@ harness-upgrade help
If you are using macOS then just do
```shell
mv harness-upgrade /usr/local/bin/
harness-upgrade help
```

If the above works successfully you should see all the commands that are supported with `harness-upgrade`

### Migrating using the step-by-step guide
## Migrating using the step-by-step guide

To migrate account level entities such as secret managers, secrets & connectors
```shell
Expand All @@ -36,6 +35,11 @@ To migrate workflows
harness-upgrade workflows
```

To migrate pipelines
```shell
harness-upgrade pipelines
```

We use API keys created in NextGen to make API calls. The token can be provided in the step-by-step guide in the prompt or as below

```shell
Expand All @@ -48,41 +52,75 @@ export HARNESS_MIGRATOR_AUTH=apiKey
harness-upgrade
```

### Migrating with a single command
To migrate all account level entities
OR
```shell
harness-upgrade --api-key apiKey
```

## Migrating with a single command
Using the step-by-step guide is the recommended way to get started with upgrade, but filling the prompts everytime can be tedious. If you wish to provide all or a few inputs you can pass them using the flags. If required arguments are not provided we will prompt for the inputs.

### To migrate all account level entities

```shell
HARNESS_MIGRATOR_AUTH=apiKey harness-upgrade --project PROJECT --org ORG --account ACCOUNT_ID --secret-scope SCOPE --connector-scope SCOPE --template-scope SCOPE --env ENV
```

To migrate an application
### To migrate an application

```shell
HARNESS_MIGRATOR_AUTH=apiKey harness-upgrade app --app APP_ID --project PROJECT --org ORG --account ACCOUNT_ID --secret-scope SCOPE --connector-scope SCOPE --template-scope SCOPE --env ENV
HARNESS_MIGRATOR_AUTH=apiKey harness-upgrade --app APP_ID --project PROJECT --org ORG --account ACCOUNT_ID --secret-scope SCOPE --connector-scope SCOPE --template-scope SCOPE --env ENV app
```

To migrate workflows
### To migrate workflows

```shell
HARNESS_MIGRATOR_AUTH=apiKey harness-upgrade workflows --app APP_ID --workflows WORKFLOW_IDS --project PROJECT --org ORG --account ACCOUNT_ID --secret-scope SCOPE --connector-scope SCOPE --template-scope SCOPE --workflow-scope SCOPE --env ENV
HARNESS_MIGRATOR_AUTH=apiKey harness-upgrade --app APP_ID --workflows WORKFLOW_IDS --project PROJECT --org ORG --account ACCOUNT_ID --secret-scope SCOPE --connector-scope SCOPE --template-scope SCOPE --workflow-scope SCOPE --env ENV workflows
```

### To migrate pipelines

```shell
HARNESS_MIGRATOR_AUTH=apiKey harness-upgrade --app APP_ID --pipelines PIPELINE_IDS --project PROJECT --org ORG --account ACCOUNT_ID --secret-scope SCOPE --connector-scope SCOPE --template-scope SCOPE --workflow-scope SCOPE --env ENV pipelines
```

## Migrating by providing the flags from a file
If you wish to provide the flags from a file you can use the `--load` to load flags from a file. You can find templates for various options in the `templates/` directory.

```shell
# To migrate the account level entities
harness-upgrade --load 'templates/account.yaml'

# To migrate the app
harness-upgrade app --load 'templates/app.yaml'

# To migrate the workflows
harness-upgrade workflows --load 'templates/workflows.yaml'

# To migrate the pipelines
harness-upgrade pipelines --load 'templates/pipelines.yaml'
```

| Flag | Details |
|-------------------|----------------------------------------------------------------------------------------------------|
| --env | Your target environment. It can be either `Dev`, `QA`, `Prod` or `Prod3` |
| --account | ID of the account that you wish to migrate |
| --secret-scope | Scope at which the secret has to be created. It can be `project`, `org` or `account` |
| --connector-scope | Scope at which the connector has to be created. It can be `project`, `org` or `account` |
| --template-scope | Scope at which the templates has to be created. It can be `project`, `org` or `account` |
| --workflow-scope | Scope at which the workflow as template has to be created. It can be `project`, `org` or `account` |
| --org | Identifier of the target org |
| --project | Identifier of the target project |
| --app | Application ID from current gen |
| --workflows | Workflow Ids as comma separated values(ex. workflow1,workflow2,workflow3) |
| --debug | If debug level logs need to be printed |
| --json | Formatted the logs as JSON |
## All the Flags

| Flag | Details |
|-------------------|------------------------------------------------------------------------------------------------------------------------|
| --env | Your target environment. It can be either `Dev`, `QA`, `Prod` or `Prod3` |
| --account | `ACCOUNT_ID` of the account that you wish to migrate |
| --api-key | `API_KEY` to authenticate & authorise the migration. You may also use the `HARNESS_MIGRATOR_AUTH` env variable instead |
| --secret-scope | Scope at which the secret has to be created. It can be `project`, `org` or `account` |
| --connector-scope | Scope at which the connector has to be created. It can be `project`, `org` or `account` |
| --template-scope | Scope at which the templates has to be created. It can be `project`, `org` or `account` |
| --workflow-scope | Scope at which the workflow as template has to be created. It can be `project`, `org` or `account` |
| --org | Identifier of the target org |
| --project | Identifier of the target project |
| --app | Application ID from current gen |
| --workflows | Workflow Ids as comma separated values(ex. `workflow1,workflow2,workflow3`) |
| --pipelines | Pipeline Ids as comma separated values(ex. `pipeline1,pipeline2,pipeline3`) |
| --debug | If debug level logs need to be printed |
| --json | Formatted the logs as JSON |

If not all the required flags are provided we will fall back to prompt based technique to capture all the required details.

## Contact
If you face any issues please reach out on the maintainer(s): Deepak Parthurya, Brett Zane, Rohan Gupta
If you face any issues please reach out to us or feel free to create a GitHub issue.
49 changes: 49 additions & 0 deletions account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package main

import (
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
"os"
)

func migrateAccountLevelEntities(*cli.Context) error {
log.Info("Migrating all account level entities like secret managers, secrets, connectors.")
promptConfirm := PromptDefaultInputs()
// Based on the scopes of entities determine the destination details
promptConfirm = PromptOrgAndProject([]string{migrationReq.SecretScope, migrationReq.ConnectorScope}) || promptConfirm
logMigrationDetails()

// We confirm if they wish to proceed or not
if promptConfirm {
confirm := ConfirmInput("Do you wish to proceed importing all secret managers, secrets & connectors?")
if !confirm {
os.Exit(1)
}
}

// Finally Make the API calls to create all entities
url := GetUrl(migrationReq.Environment, "save/v2", migrationReq.Account)

// Create Secret Managers
log.Info("Importing all secret managers from CG to NG...")
CreateEntity(url, migrationReq.Auth, getReqBody(SecretManager, Filter{
Type: All,
}))
log.Info("Imported all secret managers.")

// Create Secrets
log.Info("Importing all secrets from CG to NG...")
CreateEntity(url, migrationReq.Auth, getReqBody(Secret, Filter{
Type: All,
}))
log.Info("Imported all secrets.")

// Create Connectors
log.Info("Importing all connectors from CG to NG....")
CreateEntity(url, migrationReq.Auth, getReqBody(Connector, Filter{
Type: All,
}))
log.Info("Imported all connectors.")

return nil
}
35 changes: 35 additions & 0 deletions app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)

func migrateApp(*cli.Context) error {
promptConfirm := PromptDefaultInputs()
if len(migrationReq.AppId) == 0 {
promptConfirm = true
migrationReq.AppId = TextInput("Please provide the application ID of the app that you wish to import -")
}

promptConfirm = PromptOrgAndProject([]string{migrationReq.SecretScope, migrationReq.ConnectorScope, migrationReq.TemplateScope}) || promptConfirm

logMigrationDetails()

if promptConfirm {
confirm := ConfirmInput("Do you want to proceed with app migration?")
if !confirm {
log.Fatal("Aborting...")
}
}

url := GetUrl(migrationReq.Environment, "save/v2", migrationReq.Account)
// Migrating the app
log.Info("Importing the application....")
CreateEntity(url, migrationReq.Auth, getReqBody(Application, Filter{
AppId: migrationReq.AppId,
}))
log.Info("Imported the application.")

return nil
}
2 changes: 2 additions & 0 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const (
Connector = "CONNECTOR"
Application = "APPLICATION"
Workflow = "WORKFLOW"
Pipeline = "PIPELINE"
Template = "TEMPLATE"
)

const (
Expand Down
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ require (
github.com/AlecAivazis/survey/v2 v2.3.6
github.com/sirupsen/logrus v1.9.0
github.com/urfave/cli/v2 v2.23.6
golang.org/x/exp v0.0.0-20230111222715-75897c7a292a
)

require (
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mattn/go-colorable v0.1.2 // indirect
github.com/mattn/go-isatty v0.0.8 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/sys v0.1.0 // indirect
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect
golang.org/x/text v0.3.3 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
9 changes: 8 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw=
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
Expand Down Expand Up @@ -33,16 +35,21 @@ github.com/urfave/cli/v2 v2.23.6 h1:iWmtKD+prGo1nKUtLO0Wg4z9esfBM4rAV4QRLQiEmJ4=
github.com/urfave/cli/v2 v2.23.6/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
golang.org/x/exp v0.0.0-20230111222715-75897c7a292a h1:/YWeLOBWYV5WAQORVPkZF3Pq9IppkcT72GKnWjNf5W8=
golang.org/x/exp v0.0.0-20230111222715-75897c7a292a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
11 changes: 11 additions & 0 deletions helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"github.com/AlecAivazis/survey/v2"
log "github.com/sirupsen/logrus"
"golang.org/x/exp/slices"
"io"
"net/http"
"os"
Expand Down Expand Up @@ -137,3 +138,13 @@ func getOrDefault(value string, defaultValue string) string {
}
return value
}

func ContainsAny[E comparable](source []E, values []E) bool {
for i := range values {
v := values[i]
if slices.Contains(source, v) {
return true
}
}
return false
}
Loading

0 comments on commit 0c58c14

Please sign in to comment.