Skip to content

Commit

Permalink
feat: [PLG-2651]: CLI Refactoring + Telemetry setup (#52)
Browse files Browse the repository at this point in the history
* fix: CLI Refactoring + Telemetry setup

* feat: added events for update

* fix: added account id as default

* fix: reverted drone ui

* fix: updated accounts endpoint
  • Loading branch information
devinder-harness authored Oct 11, 2023
1 parent 9c9af63 commit 5204237
Show file tree
Hide file tree
Showing 25 changed files with 946 additions and 560 deletions.
27 changes: 0 additions & 27 deletions account.go

This file was deleted.

29 changes: 29 additions & 0 deletions account/account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package account

import (
"fmt"
"github.com/urfave/cli/v2"
"harness/client"
"harness/defaults"
. "harness/shared"
"harness/utils"
)

func GetAccountDetails(ctx *cli.Context) error {
// Getting the account details
var baseURL = utils.GetNGBaseURL(ctx)
accountsEndpoint := defaults.ACCOUNTS_ENDPOINT + CliCdRequestData.Account
url := utils.GetUrlWithQueryParams("", baseURL, accountsEndpoint, map[string]string{
"accountIdentifier": CliCdRequestData.Account,
})
resp, err := client.Get(url, CliCdRequestData.AuthToken)
if err != nil {
fmt.Printf("Response status: %s \n", resp.Status)
fmt.Printf("Response code: %s \n", resp.Code)
fmt.Printf("Response resource: %s \n", resp.Resource)
fmt.Printf("Response messages: %s \n", resp.Messages)
return nil
}

return nil
}
79 changes: 79 additions & 0 deletions auth/login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package auth

import (
"encoding/json"
"fmt"
"github.com/urfave/cli/v2"
"harness/defaults"
. "harness/shared"
"harness/telemetry"
"harness/types"
. "harness/utils"
"os"
)

func Login(ctx *cli.Context) (err error) {

fmt.Println("Welcome to Harness CLI!")
PromptAccountDetails(ctx)
SaveCredentials(ctx, true)
loginError := GetAccountDetails(ctx)

if loginError != nil {
telemetry.Track(telemetry.TrackEventInfoPayload{EventName: telemetry.LOGIN_FAILED, UserId: CliCdRequestData.UserId}, map[string]interface{}{
"accountId": CliCdRequestData.Account,
"userId": CliCdRequestData.UserId,
})
return nil
}
GetUserDetails(ctx)
SaveCredentials(ctx, false)
telemetry.Track(telemetry.TrackEventInfoPayload{EventName: telemetry.LOGIN_SUCCESS, UserId: CliCdRequestData.UserId}, map[string]interface{}{
"accountId": CliCdRequestData.Account,
"userId": CliCdRequestData.UserId,
})

return nil
}

func HydrateCredsFromPersistence(params ...interface{}) {
c := params[0].(*cli.Context)
var hydrateOnlyURL = false

if len(params) > 1 {
if value, ok := params[1].(bool); ok {
hydrateOnlyURL = value
}
}
if CliCdRequestData.AuthToken != "" && CliCdRequestData.Account != "" && !hydrateOnlyURL {
return
}

exactFilePath := GetUserHomePath() + "/" + defaults.SECRETS_STORE_PATH
credsJson, err := os.ReadFile(exactFilePath)
if err != nil {
fmt.Println("Error reading creds file:", err)
return
}
var secretstore types.SecretStore
err = json.Unmarshal(credsJson, &secretstore)
if err != nil {
fmt.Println("Error:", err)
Login(c)
return
}
if hydrateOnlyURL {
baseURL := c.String("base-url")
if baseURL == "" {
CliCdRequestData.BaseUrl = secretstore.BaseURL
} else {
CliCdRequestData.BaseUrl = baseURL
}
} else {
CliCdRequestData.AuthToken = secretstore.ApiKey
CliCdRequestData.Account = secretstore.AccountId
CliCdRequestData.BaseUrl = secretstore.BaseURL
CliCdRequestData.UserId = secretstore.UserId
}
return
}
21 changes: 13 additions & 8 deletions client.go → client/client.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package main
package client

import (
"bytes"
"encoding/json"
"errors"
"harness/defaults"
"harness/shared"
. "harness/types"
"io"
"net/http"
"strconv"
Expand Down Expand Up @@ -64,8 +67,8 @@ func Get(reqUrl string, auth string) (respBodyObj ResponseBody, err error) {
if err != nil {
return
}
req.Header.Set("Content-Type", CONTENT_TYPE_JSON)
req.Header.Set(AuthHeaderKey(auth), cliCdRequestData.AuthToken)
req.Header.Set("Content-Type", defaults.CONTENT_TYPE_JSON)
req.Header.Set(AuthHeaderKey(auth), shared.CliCdRequestData.AuthToken)
return handleResp(req)
}

Expand All @@ -74,7 +77,7 @@ func Delete(reqUrl string, auth string) (respBodyObj ResponseBody, err error) {
if err != nil {
return
}
req.Header.Set("Content-Type", CONTENT_TYPE_JSON)
req.Header.Set("Content-Type", defaults.CONTENT_TYPE_JSON)
req.Header.Set(AuthHeaderKey(auth), auth)
return handleResp(req)
}
Expand All @@ -91,14 +94,16 @@ func handleResp(req *http.Request) (respBodyObj ResponseBody, err error) {
_ = Body.Close()
}(resp.Body)
respBody, err := io.ReadAll(resp.Body)

log.WithFields(log.Fields{
"body": string(respBody),
}).Debug("The response body")

if err != nil {
return
}
_ = json.Unmarshal(respBody, &respBodyObj)

err = json.Unmarshal(respBody, &respBodyObj)
if err != nil {
log.Fatalln("There was error while parsing the response from server. Exiting...", err)
}
if resp.StatusCode != 200 {
if resp.StatusCode >= 400 || resp.StatusCode < 500 {
println(respBodyObj.Message)
Expand Down
98 changes: 55 additions & 43 deletions connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ package main

import (
"fmt"
"regexp"
"strings"

"github.com/fatih/color"
"github.com/urfave/cli/v2"
"gopkg.in/yaml.v3"
"harness/client"
"harness/defaults"
. "harness/shared"
"harness/telemetry"
. "harness/utils"
"regexp"
"strings"
)

// apply(create or update) connector
Expand All @@ -21,97 +25,105 @@ func applyConnector(c *cli.Context) error {
hostIpOrFqdn := c.String("host-ip")
hostPort := c.String("port")

baseURL := getNGBaseURL(c)
baseURL := GetNGBaseURL(c)

if filePath == "" {
fmt.Println("Please enter valid filename")
return nil
}
fmt.Println("Trying to create or update connector using the yaml=",
getColoredText(filePath, color.FgCyan))
GetColoredText(filePath, color.FgCyan))

// Getting the account details
createConnectorURL := GetUrlWithQueryParams("", baseURL, CONNECTOR_ENDPOINT, map[string]string{
"accountIdentifier": cliCdRequestData.Account,
createConnectorURL := GetUrlWithQueryParams("", baseURL, defaults.CONNECTOR_ENDPOINT, map[string]string{
"accountIdentifier": CliCdRequestData.Account,
})

var content, _ = readFromFile(filePath)
var content, _ = ReadFromFile(filePath)
if isGithubConnectorYAML(content) {
if githubUsername == "" || githubUsername == GITHUB_USERNAME_PLACEHOLDER {
if githubUsername == "" || githubUsername == defaults.GITHUB_USERNAME_PLACEHOLDER {
githubUsername = TextInput("Enter valid github username:")
}
content = replacePlaceholderValues(content, GITHUB_USERNAME_PLACEHOLDER, githubUsername)
content = ReplacePlaceholderValues(content, defaults.GITHUB_USERNAME_PLACEHOLDER, githubUsername)
}
if isK8sConnectorYAML(content) {
if delegateName == "" || delegateName == DELEGATE_NAME_PLACEHOLDER {
if delegateName == "" || delegateName == defaults.DELEGATE_NAME_PLACEHOLDER {
delegateName = TextInput("Enter valid delegate name:")
}
content = replacePlaceholderValues(content, DELEGATE_NAME_PLACEHOLDER, delegateName)
content = ReplacePlaceholderValues(content, defaults.DELEGATE_NAME_PLACEHOLDER, delegateName)
}
if isAwsConnectorYAML(content) {
if awsCrossAccountRoleArn == "" || awsCrossAccountRoleArn == AWS_CROSS_ACCOUNT_ROLE_ARN {
if awsCrossAccountRoleArn == "" || awsCrossAccountRoleArn == defaults.AWS_CROSS_ACCOUNT_ROLE_ARN {
awsCrossAccountRoleArn = TextInput("Enter valid aws cross account role arn:")
}
if awsAccessKey == "" || awsAccessKey == AWS_ACCESS_KEY {
if awsAccessKey == "" || awsAccessKey == defaults.AWS_ACCESS_KEY {
awsAccessKey = TextInput("Enter valid aws access key:")
}
if awsRegion == "" || awsRegion == REGION_NAME_PLACEHOLDER {
if awsRegion == "" || awsRegion == defaults.REGION_NAME_PLACEHOLDER {
awsRegion = TextInput("Enter valid aws region:")
}
if delegateName == "" || delegateName == DELEGATE_NAME_PLACEHOLDER {
if delegateName == "" || delegateName == defaults.DELEGATE_NAME_PLACEHOLDER {
delegateName = TextInput("Enter valid delegate name:")
}

//TODO: find a better way to resolve placeholders, dont depend on fixed placeholders
content = replacePlaceholderValues(content, AWS_CROSS_ACCOUNT_ROLE_ARN, awsCrossAccountRoleArn)
content = replacePlaceholderValues(content, AWS_ACCESS_KEY, awsAccessKey)
content = replacePlaceholderValues(content, REGION_NAME_PLACEHOLDER, awsRegion)
content = replacePlaceholderValues(content, DELEGATE_NAME_PLACEHOLDER, delegateName)
content = ReplacePlaceholderValues(content, defaults.AWS_CROSS_ACCOUNT_ROLE_ARN, awsCrossAccountRoleArn)
content = ReplacePlaceholderValues(content, defaults.AWS_ACCESS_KEY, awsAccessKey)
content = ReplacePlaceholderValues(content, defaults.REGION_NAME_PLACEHOLDER, awsRegion)
content = ReplacePlaceholderValues(content, defaults.DELEGATE_NAME_PLACEHOLDER, delegateName)
}
if isPdcConnectorYAML(content) {
hasPortNumber := strings.Contains(content, HOST_PORT_PLACEHOLDER)
if hostIpOrFqdn == "" || hostIpOrFqdn == HOST_IP_PLACEHOLDER {
hasPortNumber := strings.Contains(content, defaults.HOST_PORT_PLACEHOLDER)
if hostIpOrFqdn == "" || hostIpOrFqdn == defaults.HOST_IP_PLACEHOLDER {
hostIpOrFqdn = TextInput("Enter valid host ip / fqdn:")
}
if hasPortNumber && (hostPort == "" || hostPort == HOST_PORT_PLACEHOLDER) {
if hasPortNumber && (hostPort == "" || hostPort == defaults.HOST_PORT_PLACEHOLDER) {
hostPort = TextInput("Enter valid host port:")
}
if delegateName == "" || delegateName == DELEGATE_NAME_PLACEHOLDER {
if delegateName == "" || delegateName == defaults.DELEGATE_NAME_PLACEHOLDER {
delegateName = TextInput("Enter valid delegate name:")
}
content = replacePlaceholderValues(content, HOST_IP_PLACEHOLDER, hostIpOrFqdn)
content = replacePlaceholderValues(content, DELEGATE_NAME_PLACEHOLDER, delegateName)
content = replacePlaceholderValues(content, HOST_PORT_PLACEHOLDER, hostPort)
content = ReplacePlaceholderValues(content, defaults.HOST_IP_PLACEHOLDER, hostIpOrFqdn)
content = ReplacePlaceholderValues(content, defaults.DELEGATE_NAME_PLACEHOLDER, delegateName)
content = ReplacePlaceholderValues(content, defaults.HOST_PORT_PLACEHOLDER, hostPort)
}
requestBody := make(map[string]interface{})
if err := yaml.Unmarshal([]byte(content), requestBody); err != nil {
return err
}
identifier := valueToString(GetNestedValue(requestBody, "connector", "identifier").(string))
projectIdentifier := valueToString(GetNestedValue(requestBody, "connector", "projectIdentifier").(string))
orgIdentifier := valueToString(GetNestedValue(requestBody, "connector", "orgIdentifier").(string))
entityExists := getEntity(baseURL, fmt.Sprintf("connectors/%s", identifier),
identifier := ValueToString(GetNestedValue(requestBody, "connector", "identifier").(string))
projectIdentifier := ValueToString(GetNestedValue(requestBody, "connector", "projectIdentifier").(string))
orgIdentifier := ValueToString(GetNestedValue(requestBody, "connector", "orgIdentifier").(string))
entityExists := GetEntity(baseURL, fmt.Sprintf("connectors/%s", identifier),
projectIdentifier, orgIdentifier, map[string]string{})

var err error
if !entityExists {
println("Creating connector with id: ", getColoredText(identifier, color.FgGreen))
_, err = Post(createConnectorURL, cliCdRequestData.AuthToken, requestBody, CONTENT_TYPE_JSON, nil)
println("Creating connector with id: ", GetColoredText(identifier, color.FgGreen))
_, err = client.Post(createConnectorURL, CliCdRequestData.AuthToken, requestBody, defaults.CONTENT_TYPE_JSON, nil)
if err == nil {
println(getColoredText("Successfully created connector with id= ", color.FgGreen) +
getColoredText(identifier, color.FgBlue))

println(GetColoredText("Successfully created connector with id= ", color.FgGreen) +
GetColoredText(identifier, color.FgBlue))
telemetry.Track(telemetry.TrackEventInfoPayload{EventName: telemetry.CONNECTOR_CREATED, UserId: CliCdRequestData.UserId}, map[string]interface{}{
"accountId": CliCdRequestData.Account,
"connectorType": GetTypeFromYAML(content),
})
return nil
}

} else {
println("Found connector with id=", getColoredText(identifier, color.FgCyan))
println("Updating details of connector with id=", getColoredText(identifier, color.FgBlue))
println("Found connector with id=", GetColoredText(identifier, color.FgCyan))
println("Updating details of connector with id=", GetColoredText(identifier, color.FgBlue))

_, err = Put(createConnectorURL, cliCdRequestData.AuthToken, requestBody, CONTENT_TYPE_JSON, nil)
_, err = client.Put(createConnectorURL, CliCdRequestData.AuthToken, requestBody, defaults.CONTENT_TYPE_JSON, nil)
if err == nil {
println(getColoredText("Successfully updated connector with id= ", color.FgGreen) +
getColoredText(identifier, color.FgBlue))
println(GetColoredText("Successfully updated connector with id= ", color.FgGreen) +
GetColoredText(identifier, color.FgBlue))
telemetry.Track(telemetry.TrackEventInfoPayload{EventName: telemetry.CONNECTOR_UPDATED, UserId: CliCdRequestData.UserId}, map[string]interface{}{
"accountId": CliCdRequestData.Account,
"connectorType": GetTypeFromYAML(content),
"userId": CliCdRequestData.UserId,
})
return nil
}

Expand Down Expand Up @@ -145,12 +157,12 @@ func isPdcConnectorYAML(str string) bool {

// Delete an existing connector
func deleteConnector(*cli.Context) error {
fmt.Println(NOT_IMPLEMENTED)
fmt.Println(defaults.NOT_IMPLEMENTED)
return nil
}

// Delete an existing connector
func listConnector(*cli.Context) error {
fmt.Println(NOT_IMPLEMENTED)
fmt.Println(defaults.NOT_IMPLEMENTED)
return nil
}
4 changes: 3 additions & 1 deletion constants.go → defaults/constants.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package main
package defaults

const AWS_CROSS_ACCOUNT_ROLE_ARN = "ROLE_ARN"
const AWS_ACCESS_KEY = "AWS_ACCESS_KEY"
const AWS_SECRET_IDENTIFIER = "awssecret"
const ACCOUNTS_ENDPOINT = "accounts/"
const BUCKET_NAME_PLACEHOLDER = "CLOUD_BUCKET_NAME"
const CONNECTOR_ENDPOINT = "connectors"
const CONTENT_TYPE_JSON = "application/json"
Expand Down Expand Up @@ -44,6 +45,7 @@ const SERVICES_ENDPOINT = "servicesV2"
const SECRETS_ENDPOINT = "v2/secrets"
const SECRETS_ENDPOINT_WITH_IDENTIFIER = "v2/secrets/%s"
const FILE_SECRETS_ENDPOINT = "v2/secrets/files/%s"
const USER_INFO_ENDPOINT = "user/currentUser"
const GITHUB_USERNAME_PLACEHOLDER = "GITHUB_USERNAME"
const DELEGATE_NAME_PLACEHOLDER = "DELEGATE_NAME"
const GITHUB_PAT_PLACEHOLDER = "GITHUB-PAT"
Expand Down
Loading

0 comments on commit 5204237

Please sign in to comment.