Code Monkey home page Code Monkey logo

harness-go-sdk's Introduction

Harness SDK for Go

This project is a Harness SDK for the go programming language. It provides go client for interacting with the current gen GraphQL and Config-as-Code API's.

Disclaimer

This product is not supported by the Harness Customer support team. If you have any questions please open a new issue or join our slack channel.

Getting Started

Installing

Use go get to retrieve the SDK to add it to your GOPATH workspace, or project's Go module dependencies.

go get github.com/harness/harness-go-sdk

To update the SDK use go get -u to retrieve the latest version of the SDK.

go get -u github.com/harness/harness-go-sdk

Dependencies

The metadata of the SDK's dependencies can be found in the Go module file go.mod.

Go Modules

If you are using Go modules, your go get will default to the latest tagged release version of the SDK. To get a specific release version of the SDK use @<tag> in your go get command.

go get github.com/harness/[email protected]

To get the latest SDK repository change use @latest.

go get github.com/harness/harness-go-sdk@latest

Quick Examples

Get an application by name

client := NewClient()
app, err := client.ApplicationClient.GetApplicationByName("my-app)

Create a Service

svc, _ := ServiceFactory(app.Id, serviceName, cac.DeploymentTypes.Kubernetes, cac.ArtifactTypes.Docker)
svc.ApplicationId = app.Id

newService, err := client.Services().UpsertService(svc)

Configuration

There are a few environment variables you can set to configure the api client.

  • HARNESS_ACCOUNT_ID: (required) The ID of the harness account you are connecting to.
  • HARNESS_API_KEY: (required) The API Key used for authentication.
  • HARNESS_BEARER_TOKEN: (optional) The authentication bearer token. This is needed for certain API calls to the config-as-code API's. This will be deprecated in the near future once those endpoints are updated.
  • HARNESS_ENDPOINT: (optional) The FQDN for contacting the Harness managers. Defaults to https://app.harness.io.

If you need to provide additional configuration you can create a client object from scratch.

client := &Client{
    UserAgent:   getUserAgentString(),
    Endpoint:    utils.GetEnv(envvar.Endpoint, utils.DefaultApiUrl),
    AccountId:   os.Getenv(envvar.AccountId),
    APIKey:      os.Getenv(envvar.ApiKey),
    BearerToken: os.Getenv(envvar.BearerToken),
    HTTPClient: &retryablehttp.Client{
        RetryMax:     10,
        RetryWaitMin: 5 * time.Second,
        RetryWaitMax: 10 * time.Second,
        HTTPClient: &http.Client{
            Timeout: 10 * time.Second,
        },
        Backoff:    retryablehttp.DefaultBackoff,
        CheckRetry: retryablehttp.DefaultRetryPolicy,
    },
}

The github.com/hashicorp/go-retryablehttp is essentially a drop-in replacement for the http package and is used to handle retries when getting rate limited.

harness-go-sdk's People

Contributors

abhinav-harness avatar abhinavsingh1196 avatar adiyaar24 avatar akash-nagarajan avatar arvind-choudhary-h avatar deepak-harness avatar dependabot[bot] avatar harness-ci-automation avatar iamtcreddy avatar ivan-83 avatar lasdox avatar lovish1999 avatar manavjot-harness avatar mankrit-singh avatar micahlmartin avatar mteodor avatar n00bitax avatar naman-goenka avatar namantalaycha10 avatar rajbaviskar avatar rathodmeetsatish avatar rijajoo avatar rishabhgupta34 avatar sahithibanda01 avatar sarthak-harnessio avatar sathish-soundarapandian avatar shalinlk avatar tchaurasiya avatar vivekkarnatiharness avatar y0709 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

harness-go-sdk's Issues

GetEnvironmentById - error

Hi,
I'm passing existing applicationId and environmentId to:

env, err := client.ConfigAsCodeClient.GetEnvironmentById(applicationId, environmentId)

and getting below error:

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x2c pc=0x6b9366]
goroutine 6 [running]:
testing.tRunner.func1.1(0x754ec0, 0xa6ab70)
/usr/local/go/src/testing/testing.go:988 +0x30d
testing.tRunner.func1(0xc00009c900)
/usr/local/go/src/testing/testing.go:991 +0x3f9
panic(0x754ec0, 0xa6ab70)
/usr/local/go/src/runtime/panic.go:969 +0x166
github.com/sirupsen/logrus.(*Logger).level(...)
/home/lf/go/pkg/mod/github.com/sirupsen/[email protected]/logger.go:352
github.com/sirupsen/logrus.(*Logger).IsLevelEnabled(...)
/home/lf/go/pkg/mod/github.com/sirupsen/[email protected]/logger.go:374
github.com/sirupsen/logrus.(*Logger).Logf(0x0, 0x5, 0x7c1ce4, 0x14, 0xc0001abcd8, 0x1, 0x1)
/home/lf/go/pkg/mod/github.com/sirupsen/[email protected]/logger.go:149 +0x26
github.com/sirupsen/logrus.(*Logger).Debugf(...)
/home/lf/go/pkg/mod/github.com/sirupsen/[email protected]/logger.go:161
github.com/harness/harness-go-sdk/harness/cd.(*ConfigAsCodeClient).FindObjectById(0xc0000c2400, 0x7c29a5, 0x16, 0x7c29fd, 0x16, 0x757060, 0xc00014eb40, 0x73a400, 0x530000c0001d80f0)
/home/lf/go/pkg/mod/github.com/harness/[email protected]/harness/cd/cac.go:371 +0xd2
github.com/harness/harness-go-sdk/harness/cd.(*ConfigAsCodeClient).GetEnvironmentById(0xc0000c2400, 0x7c29a5, 0x16, 0x7c29fd, 0x16, 0xc0001d8100, 0xc0001abe00, 0x1)
/home/lf/go/pkg/mod/github.com/harness/[email protected]/harness/cd/cac_environment.go:75 +0x115

Client is able to connect to Harness.io (checked with a different method and I can retrieve ApplicationId for example.

YamlParsing Error while calling FindYamlByPath function in harness-go-sdk

Hi Team,
I am trying to update my harness-go-sdk version from 0.1.11 to 0.3.9 and in one of our terraform module its failing on the terratest.
Below are the details . Please check the details and suggest the fix/resolution for doing the backward compatibility while upgrading the harness-go-sdk version.
I have checked the arguments passed to FindYamlByPath which are 'id' and 'path' and they are getting valid values. Please let me know if you need any further information from the code to reproduce the error.

# The line which gives error
workflowYamlItem err := client.ConfigAsCodeClient.FindYamlByPath(fmt.Sprint(applicationAttributes["id"]), cac.YamlPath(path)

# Error message :
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: nvalid memory address or nil pointer dereference

# Client Configuration for Harness

client, err := cd.NewClient(&cd.Config{
AccoundId: helpers.EnvVars.AccountId.Get(),
APIKey: helpers.EnvVars.ApiKey.Get(),
Endpoint: "https://app.harness.io/gateway",
DefaultHeader: make(map[string]string),
HTTPClient: &retryablehttp.Client{
RetryMax: 10,
RetryWaitMin: 5 * time.Second,
RetryWaitMax: 10 * time.Second,
HTTPClient: &http.client{
Timeout: 10 * time.Second,
},
Backoff: retryablehttp.DefaultBackoff,
CheckRetry: retryablehttp.DefaultRetryPolicy,
}
DebugLogging: true,
})

# imports in go.mod ( go version 1.16 )

github.com/gruntwork-io/terratest v0.40.2
github.com/harness/harness-go-sdk v0.3.9
github.com/hashicorp/go-retryablehttp v0.7.1
github.com/stretchr/testify v.1.7.1
gopkg.in/yaml.v3 v3.0.1

# Terratest imports :
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/harness/harness-go-sdk/harness/cd"
"github.com/harness/harness-go-sdk/harness/helpers"
"github.com/hashicorp/go-retryablehttp"
"github.com/harness/harness-go-sdk/harness/cd/cac"
"github.com/stretchr/testify/require"
"testing"
"os"
"encoding/json"
"fmt"
"gopkg.in/yaml.v3"
"time"
"net/http"

UnmarshalJSON function on the Time class assumes no nanosecond portion in the incoming int64 value

In harness\time\time.go, the UnmarshalJSON function assumes that the incoming int64 value does not have the nanosecond portion, and creates the Time type as:

*(*time.Time)(t) = time.Unix(parsedInt, 0)

We observe that this assumption is not true, at least for the executions query, as in

query {
 executions(limit:10) {
   nodes {
    id
    startedAt
    endedAt
    status
  }
}

The startedAt and endedAt fields return values greater than "seconds from Unix epoch", causing the function to return an invalid Time object.

Feature Request: Allow the client to set a next gen api key without setting a CD api key

Currently if a user is just using next gen, and only has a next gen api key, they are still required to set a fake API key during sdk.NewSession(). This is because the current-gen client explicitly looks for an API key and returns an error if one is not set.
https://github.com/harness-io/harness-go-sdk/blob/main/harness/cd/client.go#L54

Ideally, I should be able to use a current-gen key, a next-gen key, or both without any errors being thrown.

Related to:
harness/terraform-provider-harness#75 (comment)

Workflow , Pipeline executions

Looking for a good way to do pipeline and workflow executions using the golang APIs,
and retrieve the status on each of them, including failure status and current state of the
environment it failed on.

Deserializer Issues on API calls

It is unclear in the SDK how the deserializers are to be used or which one to use. Although the
GraphQL responses do seem to have the responses, none are revealed from the SDK exported structures.

Please see the following as a small example for the issue.

Issue: GraphQL queries returned with the "data" tags are not processed

Here is a simple query .... for Application Id.
As you can see from the session below the GraphQL is returning the query
but the desrializer in the code is not handling it properly.

func HarnessAppId(name string) (string, error) {
	var buf string = ""
	var err error

	client := getClient()
	query := &cd.GraphQLQuery{
		Query: fmt.Sprintf(`query($name: String!) {
			applicationByName(name: $name) {
				id
				name
			}
		}`),
		Variables: map[string]interface{}{
			"name": name,
		},
	}
	res := &struct {
		App graphql.Application
	}{}

	err = client.ExecuteGraphQLQuery(query, &res)
	if err != nil {
		log.Fatalln(err)
		return buf, err
	}
	fmt.Println("==>", res)
	fmt.Println("==>", res.App)
	fmt.Println("> ", res.App.CommonMetadata.Id)
	fmt.Println("> ", res.App.Name)
	fmt.Println("> ", res.App.Id)
	buf = res.App.Id
	return buf, nil
}

And here is a simple session for that code with Debug turned on.

2022-02-21 22:18:28 [DEBUG] harness-go-sdk performing request%!(EXTRA string=method, string=POST, string=url, *url.URL=https://app.harness.io/gateway/api/graphql?accountId=vrst0PgwRnOIeii0a2inKg)
2022-02-21 22:18:28 [DEBUG] harness-go-sdk harness-go-sdk API Request Details:
---[ REQUEST ]---------------------------------------
POST /gateway/api/graphql?accountId=vrst0PgwRnOIeii0a2inKg HTTP/1.1
Host: app.harness.io
Content-Length: 152
Accept: application/json; charset=utf-8
Content-Type: application/json; charset=utf-8
X-Api-Key: xxx
Accept-Encoding: gzip

{
 "query": "query($name: String!) {\n\t\t\tapplicationByName(name: $name) {\n\t\t\t\tid\n\t\t\t\tname\n\t\t\t}\n\t\t}",
 "variables": {
  "name": "raider-poc"
 }
}

-----------------------------------------------------
2022-02-21 22:18:28 [DEBUG] harness-go-sdk harness-go-sdk API Response Details:
---[ RESPONSE ]--------------------------------------
HTTP/2.0 200 OK
Content-Length: 82
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Content-Type: application/json;charset=utf-8
Date: Mon, 21 Feb 2022 22:18:28 GMT
Strict-Transport-Security: max-age=15724800; includeSubDomains
Via: 1.1 google

{
 "data": {
  "applicationByName": {
   "id": "QwhnkOO9QKS6ZCxnFkLPnw",
   "name": "raider-poc"
  }
 }
}
-----------------------------------------------------
==> &{{{<nil> <nil>    []}    [] <nil> false <nil> <nil> <nil>}}
==> {{<nil> <nil>    []}    [] <nil> false <nil> <nil> <nil>}
>
>
>

GitOps API's Don't Read ApiKey from Client

Trying to debug some issues with Terraform module for Harness, and found that after trying to use the underlying SDK for Go directly myself that it suffers from the same problem I was seeing: 401 unauthorized.

Looking into the various underlying operations, such as GetClusterList we see the auth code is trying to read from the context:

	if ctx != nil {
		// API Key Authentication
		if auth, ok := ctx.Value(ContextAPIKey).(APIKey); ok {
			var key string
			if auth.Prefix != "" {
				key = auth.Prefix + " " + auth.Key
			} else {
				key = auth.Key
			}
			localVarHeaderParams["x-api-key"] = key

		}
	}

However, I'm not sure - but don't these need to also check the c.client.cfg.ApiKey? I'm passing the API key as a setup parameter to the nextgen API client, and it's being propagated into the struct for the clusters APIs etc. If I hack the code to manually set my API key from the structs API key, then it seems to work fine though. It seems like this is a pattern throughout the whole SDK.

Cross reference at: harness/terraform-provider-harness#260

Can't select application/yaml as content type

In order to pass in a yaml pipeline content this has to have a content-type: application/yaml header. There's no way to actually select it in the autogenerated code.

localVarHttpContentTypes := []string{"application/json", "application/yaml"}
// set Content-Type header
localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes)
if localVarHttpContentType != "" {
localVarHeaderParams["Content-Type"] = localVarHttpContentType
}

func selectHeaderContentType(contentTypes []string) string {
if len(contentTypes) == 0 {
return ""
}
if contains(contentTypes, "application/json") {
return "application/json"
}
return contentTypes[0] // use the first content type specified in 'consumes'
}

Models for feature flags APIs are outdated

Hi,

We are integrating with feature-flags service in go SDK and have found following issues:

  • model_feature.go is outdated w.r.t the swagger spec hosted on this page. Furthermore, the Permanent bool json:"permanent,omitempty" property has issue due to extra whitespace, so the field is not getting set in request (and the API returns Bad Request error - "request body has an error: doesn't match the schema: Error at "/permanent": property "permanent" is missing").
  • Documentation is missing for the PUT API which was recently added to feature flags service here.
  • The PATCH API in the feature flag service seems to take *interface{} in Instructions field. This is inconvenient since there models/enums for PATCH Kind & Parameters are missing in the SDK, and we have to either manually write structs/enums or generate Harness client from the OpenAPI 3.0 Spec (which is expect to be provided by SDK).
  • The status_code 400 has not been handled in the API implementation in the feature-flags service. Furthermore, if a flag is not found in Harness, the backend returns 400 Bad Request, instead it should return 404 Not Found status. (GetFeatureFlag API)

Please address these issues, and if any clarifications are needed please do reach out.

Thank you

Consistent type used for timestamps in models

Can type used for timestamps be consistent and a type that doesn't cause error with json.Marshal?

Here are two examples that I'm working with. The Delegate LastHeartBeat is in string but the value is actual int64 which I have to convert to int64 first and then to time.Time manually. The CloudProvider CreatedAt is in *time.Time that returns pointer error on json.Marshal.

Require some basic build and automation info

I want to create a new settings api so that I can use it in the terraform, but I am struggling on how to move forward with this. I did try to figure out the usage of the swagger-generator and tried related configs but I had some issues like
The incoming YAML document exceeds the limit then I tried converting the yaml to json and run it based on the issue and it ran with the swagger generator, but then it generated files and doc but with the package as swagger, but then I tried adding the api-package and model-package variable in the command, but still that did not worked as expected.

The expectation here is that can someone please provide some guideline on how to refer the harness APIs, what command to use and what are the pre-requisites to be able to contribute to this repo and use it in diff use cases.

README.md Example Should Include Imports

The code in the README.md doesn't specify the namespaces/packages to import Client or other objects from with illustrative import statements.

Given the very strange way this package has gone to lengths to make it pull all the sub-packages in the initial go get (the root package is essentially empty with nothing more than a bunch of underscored references to other sub-packages...), it's even stranger that there's no examples folder, or a hint as to what package Client refers to.

Would suggest:

  • Add imports statements to the README.md examples

  • Add an /examples folder showing a few basic scenarios.

  • Remove the underscored imports. Go will automatically lock in the sub-packages, however this approach will mean that go get / go mod vendor will always include all the subtrees for components you might not even be using (i.e. if you're not using legacy/firstgen).

Consistency in list functions

Looking at the following list functions, there are some inconsistencies in the input args. Some have filters while others not. Some filter use specific struct while another uses separate args. Most of the args start with limit and offset but then ListServicesByApplicationId starts with appId.

  • ListDelegates(limit int, offset int)
  • ListDelegatesWithFilters(limit int, offset int, name string, status graphql.DelegateStatus, delegateType graphql.DelegateType)
  • ListCloudProviders(limit int, offset int)
  • ListApplications(limit int, offset int)
  • ListServices(limit int, offset int, filters []*graphql.ServiceFilter)
  • ListServicesByApplicationId(appId string, limit int, offset int)

Like to propose the following changes.

  • ListServicesByApplicationId(limit int, offset int, appId string)
  • ListDelegatesWithFilters(limit int, offset int, filters[]*graphql.DelegateFilter)

Nil Pointer exception while trying to reach out via Harness SDK during Terratest

I am testing harness terraform module in Jenkins. I am able to perform the terraform execution part, but while reaching out to client sdk to validate few properties I am facing the following error:

**panic: runtime error: invalid memory address or nil pointer dereference [recovered]
              panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0xcef4c1]**

goroutine 19 [running]:
testing.tRunner.func1.2(0xdb4ee0, 0x1565770)
              /usr/share/go/src/testing/testing.go:1144 +0x332
testing.tRunner.func1(0xc000102d80)
              /usr/share/go/src/testing/testing.go:1147 +0x4b6
panic(0xdb4ee0, 0x1565770)
              /usr/share/go/src/runtime/panic.go:965 +0x1b9
test/unit.TestHarnessK8sCloudProvider(0xc000102d80)
              **/tmp/workspace/xxxx/provider_test.go:72** +0x661
testing.tRunner(0xc000102d80, 0xf00748)
              /usr/share/go/src/testing/testing.go:1194 +0xef
created by testing.(*T).Run
              /usr/share/go/src/testing/testing.go:1239 +0x2b3

Line# 72 in the code is the following one:
require.Equal(t, client.Configuration.AccountId, "AbcxYz1234", "FAILED: AccountID does NOT match")

The code for client config is the following. I have set env vars HARNESSS_ACCOUNT_ID and HARNESS_API_KEY:

client, _ := cd.NewClient(&cd.Config{
                             AccountId:          helpers.EnvVars.AccountId.Get(),
                             APIKey:     helpers.EnvVars.ApiKey.Get(),
                             DebugLogging: true,
              })

I would like to know if there is additional instruction to set network config to reach out to the harness sdk. Kindly help us to get the way forward here.

Thank you.
@abrahamkoshy

Add Config Variables to GraphQL Service Model

Request to add config variables to the GraphQL service model @ https://github.com/harness/harness-go-sdk/blob/main/harness/cd/graphql/model_service.go#L5. We look up service by name and so we have to call GetServiceByName and then use ConfigAsCode GetServiceById to be able to get the list of ConfigVariables.

Also, there are multiple API calls behind the scene here. 1) GetServiceByName has to list services by application and then loop thru to find the service by name. 2) ConfigAsCode GetServiceById has to get the directory tree, recursive calls to find object, and then make another API call to get service. Will there be performance issue once we have many services under an app?

CloudQuery Source Plugin?

Hi Team, hopefully this is right place to ask, if not, I'd appreciate if you can direct me.

I'm the founder of cloudquery.io, a high performance open source ELT framework.

Our users are interested in a Harness plugin, but as we cannot maintain all the plugins ourselves, I was curious if this would be an interesting collaboration, where we would help implement an initial source plugin, and you will help maintain it (Similar to terraform provider but much easier as it's just the extract part).

This will give your users the ability to sync Harness APIs to any of their datalakes/data-warehouses/databases easily using any of the growing list of CQ destination plugins.

Best,
Yevgeny

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.