Skip to content

Latest commit

 

History

History
104 lines (81 loc) · 2.69 KB

third-party-go-clients.md

File metadata and controls

104 lines (81 loc) · 2.69 KB

Third party Go clients

This describes an approach to allow third party Go codebases to drive Juju. At a high level it works like this.

  1. Create a connector instance, telling it how to connect to a Juju controller and how to provide authentication credentials.
  2. Use this connector instance to obtain a connection instance.
  3. Get a facade client from the connection.
  4. Use the facade client to make one or more requests.

The Connector interface

The github.com/juju/juju/api/connector package defines a Connector interface.

type Connector interface {
	Connect(...api.DialOption) (api.Connection, error)
}

Its only purpose is to create instances of api.Connection that can later be used to talk to a given Juju controller with a given set of credentials. There are currently two ways to obtain a Connector instance.

SimpleConnector

If one knows the how to contact a controller, and some juju user credentials (e.g. username and password) it is possible to obtain a connector like this.

import "github.com/juju/juju/api/connector"
connr, err := connector.NewSimple(connector.SimpleConfig{
    ControllerAddresses: []string{"10.225.205.241:17070"},
    CaCert: "...",
    Username: "jujuuser",
    Password: "password1",
})

There can be an error if the config is not valid (e.g. no controller address specified).

ClientStoreConnector

If a client store is available on the filesystem, it is possible to use it to configure the connector.

import "github.com/juju/juju/api/connector"
connr, err := connector.NewClientStore(connector.ClientStoreConfig{
    ControllerName: "overlord",
})

The above will try to find a client store in the default location. It is also possible to pass in a custom value (see clientstoreconnector.go for details).

Making requests

Once we have a connector, it's easy to make requests.

import (
    "encoding/json"
	"github.com/juju/juju/api/connector"
	"github.com/juju/juju/api/client/client"
)
    // Get a connection
	conn, err := connr.Connect()
	if err != nil {
		log.Fatalf("Error opening connection: %s", err)
	}
    defer conn.Close()

    // Get a Client facade client
	client := apiclient.NewClient(conn)

    // Call the Status endpoint of the client facade
    status, err := client.Status(nil)
    if err != nil {
        log.Fatalf("Error requesting status: %s", err)
    }

    // Print to stdout.
    b, err := json.MarshalIndent(status, "", "  ")
	if err != nil {
		log.Fatalf("Error marshalling response: %s", err)
	}
	fmt.Printf("%s\n", b)

Points to address

  • When to reuse a connection, when to create a new one?
  • How to find the useful endpoints?