-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add tenants cli #29
Open
dlactin
wants to merge
5
commits into
main
Choose a base branch
from
add-tenants-cli
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Add tenants cli #29
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
52e7b78
initial commit of tenants cli
dlactin dc3e398
fix: adding basic error checking when writing csv header and rows
dlactin 539b57f
fix: refactored deploymentType and root commands, renamed config stru…
dlactin 30625b2
Update README.md
dlactin 0c69bbc
Update tenants/cmd/deploymentType.go
dlactin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# tenants | ||
|
||
CLI app for collecting GCPv2 tenant information from our tenant files. | ||
|
||
## Overview | ||
|
||
The `tenants` CLI app allows users to retrieve deploymentType information from | ||
our tenant files. This should be limited to "argocd", "gha", or "unknown". | ||
|
||
## Installation | ||
|
||
### Prerequisites | ||
|
||
* Go `1.21.3` or newer | ||
|
||
### Installation Steps | ||
|
||
To install the `tenants` CLI app, run the following command: | ||
|
||
```bash | ||
go install github.com/mozilla-services/rapid-release-model/tenants@latest | ||
``` | ||
|
||
## Usage | ||
|
||
### CLI Commands | ||
|
||
The main subcommand is `deploymentType`, which retrieves deploymentType information for | ||
our GCPv2 tenants. | ||
|
||
```bash | ||
tenants deploymentType -d <path-to-tenants-directory> | ||
``` | ||
|
||
Example: | ||
|
||
```bash | ||
tenants deploymentType -d ../../tenants -f json -o deployment-type.json | ||
``` | ||
|
||
This command will read tenant information for services from the tenant yaml files in `../../tenants` directory and | ||
parse the `deployment_type` from them. | ||
|
||
### CLI Options | ||
|
||
The following options are available for `ciplatforms info`: | ||
|
||
| Short Option | Long Option | Description | Default | | ||
|--------------|-----------------|--------------------------------------------------|-----------------------| | ||
| `-d` | `--directory` | Directory containing yaml tenant files | `tenants` | | ||
| `-f` | `--format` | Output format: csv or json | `csv` | | ||
| `-o` | `--output` | Output file for results | `deployment_type.csv` | | ||
|
||
## Configuration | ||
|
||
You can configure the `tenants` CLI app by passing CLI flags. | ||
|
||
### Output File Formats | ||
|
||
* **Output File** (`--output`): The output file can be specified in either JSON or CSV format. The `tenants` app will determine the output format based on the file extension (`.json` or `.csv`). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/mozilla-services/rapid-release-model/tenants/internal/io" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type DeploymentTypeOptions struct { | ||
TenantDirectory string | ||
OutputFile string | ||
Format string | ||
} | ||
|
||
func newDeploymentTypeCmd() *cobra.Command { | ||
opts := new(DeploymentTypeOptions) | ||
|
||
cmd := &cobra.Command{ | ||
Use: "deploymentType", | ||
Short: "Parse tenant files directory for deployment type", | ||
Long: `Parse a local tenant files directory for deployment type | ||
Example: | ||
./tenants deploymentType -d ../../global-platform-admin/tenants`, | ||
PreRunE: func(cmd *cobra.Command, args []string) error { | ||
// Bind the directory flag | ||
directory, err := cmd.Flags().GetString("directory") | ||
if err != nil { | ||
return fmt.Errorf("failed to get directory flag: %w", err) | ||
} | ||
opts.TenantDirectory = directory | ||
|
||
// Bind the output file flag | ||
outputFile, err := cmd.Flags().GetString("output") | ||
if err != nil { | ||
return fmt.Errorf("failed to get output flag: %w", err) | ||
} | ||
opts.OutputFile = outputFile | ||
|
||
// Bind the format flag | ||
format, err := cmd.Flags().GetString("format") | ||
if err != nil { | ||
return fmt.Errorf("failed to get format flag: %w", err) | ||
} | ||
opts.Format = format | ||
|
||
return nil | ||
}, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
return runAnalysis(opts) | ||
}, | ||
} | ||
|
||
cmd.Flags().StringP("output", "o", "deployment_type.csv", "Output file") | ||
cmd.Flags().StringP("format", "f", "csv", "Output format: csv or json") | ||
|
||
return cmd | ||
} | ||
|
||
func runAnalysis(opts *DeploymentTypeOptions) error { | ||
directory := opts.TenantDirectory | ||
outputFile := opts.OutputFile | ||
format := opts.Format | ||
|
||
files, err := io.GetYamlFiles(directory) | ||
if err != nil { | ||
return fmt.Errorf("error fetching YAML files: %v", err) | ||
} | ||
|
||
if len(files) == 0 { | ||
return fmt.Errorf("no YAML files found in the specified directory") | ||
} | ||
|
||
results := []map[string]string{} | ||
totalTenants := len(files) | ||
argocdTenants := 0 | ||
|
||
for _, file := range files { | ||
fileName := strings.TrimSuffix(filepath.Base(file), ".yaml") | ||
fmt.Printf("Checking tenant: %s\n", fileName) | ||
content, err := os.ReadFile(file) | ||
if err != nil { | ||
fmt.Printf("Skipping tenant file %s due to an error: %v\n", fileName, err) | ||
continue | ||
} | ||
deploymentType, migrationStatus := io.ParseDeploymentTypeAndMigration(string(content)) | ||
results = append(results, map[string]string{ | ||
"TenantName": fileName, | ||
"DeploymentType": deploymentType, | ||
"MigrationStatus": migrationStatus, | ||
}) | ||
|
||
if deploymentType == "argocd" { | ||
argocdTenants++ | ||
} | ||
} | ||
|
||
percentageArgocd := float64(argocdTenants) / float64(totalTenants) * 100 | ||
fmt.Printf("Total tenants: %d\n", totalTenants) | ||
fmt.Printf("Tenants on Argo CD: %d\n", argocdTenants) | ||
fmt.Printf("Percentage of tenants on argocd: %.2f%%\n", percentageArgocd) | ||
|
||
if format == "csv" { | ||
return io.WriteCSV(outputFile, results) | ||
} else if format == "json" { | ||
return io.WriteJSON(outputFile, results) | ||
} else { | ||
return fmt.Errorf("invalid format: %s, must be 'csv' or 'json'", format) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
// newRootCmd creates a new base command for the metrics CLI app | ||
func newRootCmd() *cobra.Command { | ||
rootCmd := &cobra.Command{ | ||
Use: "tenants", | ||
Short: "CLI app for parsing GCPv2 tenant files for cataloguing", | ||
Long: "CLI app for parsing GCPv2 tenant files for cataloguing", | ||
} | ||
|
||
rootCmd.PersistentFlags().StringP("directory", "d", "", "Path to the tenants directory containing YAML files") | ||
rootCmd.MarkPersistentFlagRequired("directory") | ||
|
||
rootCmd.AddCommand(newDeploymentTypeCmd()) | ||
|
||
return rootCmd | ||
} | ||
|
||
// Execute the CLI application and write errors to os.Stderr | ||
func Execute() { | ||
rootCmd := newRootCmd() | ||
if err := rootCmd.Execute(); err != nil { | ||
fmt.Fprintf(os.Stderr, "error: %v\n", err) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func init() { | ||
dlactin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// New in cobra v1.8.0. See https://github.com/spf13/cobra/pull/2044 | ||
// Run all PersistentPreRunE hooks, so we don't have to repeat factory | ||
// configuration or CLI flags parsing in sub commands. | ||
cobra.EnableTraverseRunHooks = true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module github.com/mozilla-services/rapid-release-model/tenants | ||
|
||
go 1.22.3 | ||
|
||
require ( | ||
github.com/spf13/cobra v1.8.1 | ||
gopkg.in/yaml.v2 v2.4.0 | ||
) | ||
|
||
require ( | ||
github.com/inconshreveable/mousetrap v1.1.0 // indirect | ||
github.com/spf13/pflag v1.0.5 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= | ||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= | ||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= | ||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= | ||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= | ||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= | ||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= | ||
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.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | ||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package io | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"gopkg.in/yaml.v2" | ||
) | ||
|
||
type Tenant struct { | ||
Globals struct { | ||
Deployment struct { | ||
Type string `yaml:"type"` | ||
} `yaml:"deployment"` | ||
} `yaml:"globals"` | ||
Realms struct { | ||
Nonprod struct { | ||
Deployment struct { | ||
Type string `yaml:"type"` | ||
} `yaml:"deployment"` | ||
} `yaml:"nonprod"` | ||
Prod struct { | ||
Deployment struct { | ||
Type string `yaml:"type"` | ||
} `yaml:"deployment"` | ||
} `yaml:"prod"` | ||
} `yaml:"realms"` | ||
} | ||
|
||
func GetYamlFiles(directory string) ([]string, error) { | ||
var files []string | ||
err := filepath.Walk(directory, func(path string, info os.FileInfo, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
if !info.IsDir() && strings.HasSuffix(info.Name(), ".yaml") { | ||
hackebrot marked this conversation as resolved.
Show resolved
Hide resolved
|
||
files = append(files, path) | ||
} | ||
return nil | ||
}) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return files, nil | ||
} | ||
|
||
func ParseDeploymentTypeAndMigration(fileContent string) (string, string) { | ||
var tenant Tenant | ||
|
||
err := yaml.Unmarshal([]byte(fileContent), &tenant) | ||
if err != nil { | ||
fmt.Printf("Error parsing YAML content: %v\n", err) | ||
return "Error", "Error" | ||
} | ||
|
||
deploymentTypes := make(map[string]bool) | ||
|
||
// Collect deployment types | ||
globalType := strings.Trim(tenant.Globals.Deployment.Type, "\" ") | ||
if globalType != "" { | ||
deploymentTypes[globalType] = true | ||
} | ||
|
||
nonprodType := strings.Trim(tenant.Realms.Nonprod.Deployment.Type, "\" ") | ||
if nonprodType != "" { | ||
deploymentTypes[nonprodType] = true | ||
} | ||
|
||
prodType := strings.Trim(tenant.Realms.Prod.Deployment.Type, "\" ") | ||
if prodType != "" { | ||
deploymentTypes[prodType] = true | ||
} | ||
|
||
// Determine migration status | ||
_, hasArgocd := deploymentTypes["argocd"] | ||
_, hasGha := deploymentTypes["gha"] | ||
|
||
var migrationStatus string | ||
if hasArgocd && hasGha { | ||
migrationStatus = "in_progress" | ||
} else if hasArgocd { | ||
migrationStatus = "complete" | ||
} else if hasGha { | ||
migrationStatus = "not_started" | ||
} else { | ||
migrationStatus = "unknown" | ||
} | ||
|
||
/* | ||
This is being used to track live and complete migrations to ArgoCD | ||
On average these migrations have taken less than a week to complete | ||
and the detailed progress is tracked by migrationStatus | ||
*/ | ||
deploymentType := "" | ||
dlactin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if hasArgocd { | ||
deploymentType = "argocd" | ||
} else if hasGha { | ||
deploymentType = "gha" | ||
} else { | ||
deploymentType = "none" | ||
} | ||
|
||
return deploymentType, migrationStatus | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should check this before running any of the above code.