AMS SDK
Anbox Management SDK offers a group of Go packages and
utilities for any external Go code to be able to connect
to the AMS service through the exposed REST API to manage Anbox Cloud.
the AMS SDK consist of the following Go packages:
-
client
: The main purpose of this package is to provide a REST client object
with relevant method to manage applications, images, nodes, addons or
containers. Each method relates to a specific management operation and wraps
the REST calls and listening operations
-
api
: AMS REST API objects
-
shared
: Helper methods and tools for common tasks like system tasks,
certificates, password hashing or websocket dialing.
-
shared/rest/client
: REST client base functionality to wrap common behavior
of the various operations of the REST protocol and websocket management for
event listening.
-
shared/rest/api
: REST API basic objects, independent of any specific REST
implementation
-
shared/errors
: A simple wrapper for the most commonly-used error implementation
in the return of REST API
-
examples
: A set of examples to demonstrate how the client
package can be used.
Install
There are no special instructions to install the AMS SDK. You can simply add the
content of the provided SDK zip file into your projects vendor/
directory or
your GOPATH
and start using it.
Examples
The SDK comes with a set of examples demonstrating the capabilities of the SDK.
Authentication setup
Go clients using the SDK must authenticate to an AMS instance by using two way SSL
Authentication. This means that server requires a trusted client certificate to be
sent in every request and that the client must add a certificate he desires to use
to the server before sending the first request.
Assuming that you already have generated a
client certificate and it is stored in a file
called client.crt
, you can easily add it to the list of server trusted certificates
using juju on an already deployed environment:
$ juju run-action ams/0 add-certificate cert="$(cat client.crt | grep -v ^-- | tr -d '\n')" --wait
Once the execution completes, the certificate is trusted and can be used along with
the SDK libraries and tools to connect to the AMS instance or AMS cluster.
!!!Note:
ams/0
is the name of the unit on which AMS has been deployed. Its number can
be different than 0
.
Generating a client certificate
Self signed
The easiest way of generating a client certificate is using the certificate as
CA of itself. That is what a self-signed certificate is. This is generally intended
for testing purposes because the CA is not a well-known trusted one, though in the
case of AMS it really does not matter at all because the service trust in individual
certificates regardless of the CA signing them. So, in the end a certificate provided
this way is as valid as one signed by a CA.
You can easily create it using OpenSSL:
$ openssl req -x509 -newkey rsa:4096 -keyout client.key -out client.crt -days 365
You will be asked for a password and certificate information interactively. Answer the
questions until completing all the process and the certificate and key will be generated:
Generating a 4096 bit RSA private key
............................................++
...................................................................++
writing new private key to 'client.key'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:
Signed by a CA
If you prefer, you can provide a certificate signed by a CA. The authority singing the
certificate can be a well-known one or a customer.
Creating a CA
You can create a custom CA key to sign your own certificates with:
$ openssl genrsa -out MyCompanyCA.key 2048
That will generate the CA key in a file named MyCompanyCA.key
. You can now create
the certificate with
$ openssl req -x509 -new -nodes -key MyCompanyCA.key -sha256 -days 1024 -out MyCompanyCA.crt
Again, you have to fill all interactively requested data until completing the process
of certificate creation. The result is a file named MyCompanyCA.crt
Generating certificates signed by a custom CA
Once you have a custom CA, to sign a certificate you first need to create the
certificate key and a request to be signed:
$ openssl genrsa -out client.key 2048
$ openssl req -new -key client.key -out client.csr
The file client.csr
needs to be signed by the CA in order to get the
final certificate:
$ openssl x509 -req -in client.csr -CA MyCompanyCA.crt -CAkey MyCompanyCA.key -CAcreateserial -out client.crt -days 1024 -sha256
you obtain as result client.crt
signed by MyCompanyCA certificate authority.
!!!Note:
Check the OpenSSL website for more information about
the specific parameters for every OpenSSL operation.
Custom Client Code
Connection
Main steps for custom code to connect to the server start with the creation of
a REST client object. Such object needs a TLS configuration including the client
certificate to be sent to AMS and the server certificate the client trusts. There
are many ways of creating a TLS configuration in go. AMS-SDK provides an easy
solution involving a few lines of code:
import (
"flag"
"net/url"
"os"
"github.com/anbox-cloud/ams-sdk/client"
"github.com/anbox-cloud/ams-sdk/shared"
)
func main() {
flag.Parse()
if flag.NArg() == 0 {
fmt.Println("Please provide AMS service URL")
os.Exit(1)
}
serviceURL := flag.Arg(0)
u, err := url.Parse(serviceURL)
if err != nil {
fmt.Println("Failed to parse AMS service URL")
os.Exit(1)
}
serverCert, err := shared.GetRemoteCertificate(serviceURL)
if err != nil {
fmt.Println("Failed to get remote certificates")
os.Exit(1)
}
tlsConfig, err := shared.GetTLSConfig(clientCert, clientKey, "", serverCert)
if err != nil {
fmt.Println("Failed to get TLS config")
os.Exit(1)
}
...
}
!!!Note:
Here, we take any server certificate as valid. In case you want a better compromise
on the client side with the server certificate to trust, you simply have to
replace shared.GetRemoteCertificate(serviceURL)
method with code to read a
server well-known certificate from a remote or local path to a x509 object and pass
it to shared.GetTLSConfig()
method.
Once the TLS configuration is ready, the next step is to create the REST client object:
amsClient, err := client.New(u, tlsConfig)
if err != nil {
return err
}
Using the REST API
The created REST client object has a large list of methods to manage the different entities
into AMS:
-
Applications:
- Create
- Export
- Update
- List
- Show
- Publish
- Revoke
- Delete
- DeleteVersion
-
Containers:
-
Nodes:
- Add
- List
- Update
- Show
- Remove
-
Images:
- Add
- Update
- List
- Delete
- DeleteVersion
-
Addons:
- Add
- Update
- List
- Delete
- DeleteVersion
Look at the godoc generated documentation for more details of each method call.
One example of the use of the SDK client to create an application could be
either from the folder path where the application package layout is :
c.CreateApplication(".", nil)
or from the application package path
c.CreateApplication("application.tar.bz2", nil)
Asynchronous operations
All operations modifying entities on AMS are executed asynchronously to prevent
blocking the client. This means that a call, say, to c.CreateApplication(...)
won't block and will return immediately, even when the operation is still not
finished in the server.
All the asynchronous operations return an
github.com/anbox-cloud/ams-sdk/shared/rest/client/Operation
struct object
If you want your client to wait for an asynchronous operation to complete, you
can call Operation.Wait()
method, which will block current thread until the
operation finishes or an error occurs:
...
operation, err := c.CreateApplication(".", nil)
err = operation.Wait(context.Background())
if err != nil {
return err
}
You can get in your code the operation resultant resources:
operation.Get().Resources