-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Experimental: Add support to create the Tanzu Hub client (#175)
- Adds support to create authenticated Tanzu Hub client for the specified tanzu context - The Tanzu Hub client exposes a graphQL client implemented using github.com/Khan/genqlient/graphql to query the hub resources with graphQL APIs. - Also provides a Makefile to help plugin authors initialize and generate the stub for the graphQL queries.
- Loading branch information
Showing
17 changed files
with
399 additions
and
1,968 deletions.
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,42 @@ | ||
# Tanzu Hub Client | ||
|
||
This package enables the creation of authenticated Tanzu Hub clients which in turn | ||
enables the interaction with Tanzu Hub endpoint through GraphQL queries for the | ||
`tanzu` context. | ||
|
||
**Note:** The Tanzu Hub Client feature is an EXPERIMENTAL feature. The API signature | ||
and implementation are subjected to change/removal if an alternative means to provide | ||
equivalent functionality can be introduced. | ||
|
||
## Creating a Tanzu Hub Client | ||
|
||
To create a Tanzu Hub client, use the `CreateHubClient(contextName string)` API | ||
by providing the `tanzu` context name. An authenticated Tanzu Hub client for the specified tanzu context will be returned. | ||
This client includes an authenticated GraphQLClient from the `github.com/Khan/genqlient` package | ||
that can be used to do GraphQL queries. Internally it configures the client with an access token for each request. | ||
By default, it will get the Tanzu Hub endpoint from the specified context metadata. To specify any custom Tanzu Hub | ||
endpoint for testing please configure the `TANZU_HUB_GRAPHQL_ENDPOINT` environment variable. | ||
|
||
Note that the authenticated client is assured to have at least 30 min access to the GraphQL endpoint. | ||
If you want a long running client beyond this period, recommendation is to reinitialize your client. | ||
|
||
## Generating the golang stub to invoke graphQL queries | ||
|
||
There are many golang client libraries for the graphQL, however, Tanzu Plugin Runtime uses `github.com/Khan/genqlient` and | ||
also returns the corresponding graphQL client as part of the Tanzu Hub client creation. | ||
|
||
github.com/Khan/genqlient is a Go library to easily generate type-safe code to query a GraphQL API. | ||
|
||
To help plugin authors generate the stub for the Tanzu Hub endpoint, a [tanzuhub.mk](../../hack/hub/tanzuhub.mk) has been provided. | ||
This makefile provides an easy means for the plugin authors to initialize a `hub` package and also generate the stub from the graphQL queries. | ||
To use this library plugin authors can follow the below steps: | ||
|
||
1. Copy the [tanzuhub.mk](../../hack/hub/tanzuhub.mk) to your project and import it to your `Makefile` with `include ./tanzuhub.mk` | ||
2. Configure the `TANZU_HUB_SCHEMA_FILE_URL` environment variable to the `schema.graphql` of the Tanzu Hub | ||
3. Run `make tanzu-hub-stub-init` to initialize a `hub` package. This will create the following files under the `hub` package: | ||
* `genqlient.yaml`: Configuration file for generating golang code from GraphQL query with `github.com/Khan/genqlient` | ||
* `queries.graphql`: File to write all graphQL queries | ||
* `main.go`: A golang file with necessary imports to easily run `go generate` to generate stub code | ||
4. Once the initialization is done, you can add your GraphQL queries to the `queries.graphql` file | ||
5. After adding new graphQL queries or updating an existing query, run `make tanzu-hub-stub-generate` to generate a golang stub for the GraphQL queries | ||
* This will create a `generate.go` file under the `hub` package with golang APIs that can be consumed directly by other packages by passing the GraphQLClient available with TanzuHub client |
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,95 @@ | ||
// Copyright 2024 VMware, Inc. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Package hub provides functions to create Tanzu Hub client for specific context | ||
package hub | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"os" | ||
|
||
"github.com/Khan/genqlient/graphql" | ||
"github.com/pkg/errors" | ||
|
||
"github.com/vmware-tanzu/tanzu-plugin-runtime/config" | ||
) | ||
|
||
const ( | ||
EnvTanzuHubGraphQLEndpoint = "TANZU_HUB_GRAPHQL_ENDPOINT" | ||
) | ||
|
||
// HubClient client to talk to Tanzu Hub through GraphQL apis | ||
// It includes authenticated GraphQL client from github.com/Khan/genqlient | ||
// that can be used to do GraphQL queries | ||
type HubClient struct { | ||
// ContextName is Tanzu CLI context name | ||
ContextName string | ||
// GraphQLClient can be used to do graphql queries | ||
GraphQLClient graphql.Client | ||
} | ||
|
||
// CreateHubClient returns an authenticated Tanzu Hub client for the specified | ||
// tanzu context. This client includes an authenticated GraphQLClient from github.com/Khan/genqlient | ||
// that can be used to do GraphQL queries. | ||
// Internally it configures the client with CSP access token for each request | ||
// | ||
// Note that the authenticated client is assured to have at least 30 min access to the GraphQL endpoint. | ||
// If you want a long running client beyond this period, recommendation is to reinitialize your client. | ||
// | ||
// EXPERIMENTAL: Both the function's signature and implementation are subjected to change/removal | ||
// if an alternative means to provide equivalent functionality can be introduced. | ||
func CreateHubClient(contextName string) (*HubClient, error) { | ||
accessToken, err := config.GetTanzuContextAccessToken(contextName) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
tanzuHubEndpoint, err := getTanzuHubEndpointFromContext(contextName) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
httpClient := http.Client{ | ||
Transport: &authTransport{ | ||
accessToken: accessToken, | ||
wrapped: http.DefaultTransport, | ||
}, | ||
} | ||
graphqlClient := graphql.NewClient(fmt.Sprintf("%s/graphql", tanzuHubEndpoint), &httpClient) | ||
return &HubClient{ | ||
ContextName: contextName, | ||
GraphQLClient: graphqlClient, | ||
}, nil | ||
} | ||
|
||
func getTanzuHubEndpointFromContext(contextName string) (string, error) { | ||
// If `TANZU_HUB_GRAPHQL_ENDPOINT` environment variable is configured use that | ||
if endpoint := os.Getenv(EnvTanzuHubGraphQLEndpoint); endpoint != "" { | ||
return endpoint, nil | ||
} | ||
|
||
// Try to fetch the endpoint from the context metadata | ||
tzCtx, err := config.GetContext(contextName) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
tanzuHubEndpoint := tzCtx.AdditionalMetadata[config.TanzuHubEndpointKey] | ||
if tanzuHubEndpoint == "" { | ||
return "", errors.Errorf("%q has not been configured for the %q context", config.TanzuHubEndpointKey, tzCtx.Name) | ||
} | ||
return tanzuHubEndpoint.(string), nil | ||
} | ||
|
||
// Configure the auth Transport to include authorization token when invoking GraphQL requests | ||
type authTransport struct { | ||
accessToken string | ||
wrapped http.RoundTripper | ||
} | ||
|
||
// Sets authentication bearer token to each http request | ||
func (t *authTransport) RoundTrip(req *http.Request) (*http.Response, error) { | ||
req.Header.Set("authorization", "Bearer "+t.accessToken) | ||
return t.wrapped.RoundTrip(req) | ||
} |
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
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
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
Oops, something went wrong.