├── .github ├── CODEOWNERS ├── renovate.json └── workflows │ └── release.yaml ├── go.mod ├── examples └── ams │ ├── container-list │ ├── README.md │ └── main.go │ ├── node-delete │ ├── README.md │ └── main.go │ ├── container-delete │ ├── README.md │ └── main.go │ ├── addon-delete │ ├── README.md │ └── main.go │ ├── image-delete │ ├── README.md │ └── main.go │ ├── application-revoke │ ├── README.md │ └── main.go │ ├── addon-update │ ├── README.md │ └── main.go │ ├── application-publish │ ├── README.md │ └── main.go │ ├── addon-add │ ├── README.md │ └── main.go │ ├── application-delete │ ├── README.md │ └── main.go │ ├── addon-show │ ├── README.md │ └── main.go │ ├── image-add │ ├── README.md │ └── main.go │ ├── image-update │ ├── README.md │ └── main.go │ ├── container-list-log │ ├── README.md │ └── main.go │ ├── addon-list │ ├── README.md │ └── main.go │ ├── application-export │ └── README.md │ ├── node-set │ ├── README.md │ └── main.go │ ├── image-show │ ├── README.md │ └── main.go │ ├── node-add │ ├── README.md │ └── main.go │ ├── node-show │ ├── README.md │ └── main.go │ ├── node-list │ ├── README.md │ └── main.go │ ├── container-show │ ├── README.md │ └── main.go │ ├── image-list │ ├── main.go │ └── README.md │ ├── application-list │ ├── main.go │ └── README.md │ ├── common │ └── common.go │ ├── container-launch │ └── README.md │ ├── container-show-log │ ├── README.md │ └── main.go │ ├── application-show │ └── README.md │ ├── application-update │ ├── README.md │ └── main.go │ └── application-create │ ├── README.md │ └── main.go ├── pkg ├── ams │ ├── shared │ │ ├── rest │ │ │ ├── api │ │ │ │ ├── version.go │ │ │ │ ├── swagger.go │ │ │ │ ├── certificate.go │ │ │ │ ├── oidc.go │ │ │ │ └── statuscode.go │ │ │ └── client │ │ │ │ ├── certificates.go │ │ │ │ ├── websocket.go │ │ │ │ ├── oidc_client.go │ │ │ │ └── interfaces.go │ │ ├── errors │ │ │ ├── aborted.go │ │ │ ├── failed.go │ │ │ ├── required.go │ │ │ ├── timeout.go │ │ │ ├── unknown.go │ │ │ ├── malformed.go │ │ │ ├── in_progress.go │ │ │ ├── not_supported.go │ │ │ ├── already_exists.go │ │ │ ├── not_executable.go │ │ │ ├── invalid_length.go │ │ │ ├── invalid_format.go │ │ │ ├── common.go │ │ │ ├── dont_match.go │ │ │ ├── not_found.go │ │ │ ├── not_changed.go │ │ │ ├── not_allowed.go │ │ │ └── invalid_argument.go │ │ ├── buffered_reader.go │ │ ├── locker.go │ │ ├── ask.go │ │ ├── hash.go │ │ ├── reverter.go │ │ └── atomic_file.go │ ├── constants │ │ ├── version.go │ │ ├── network.go │ │ ├── names.go │ │ ├── values.go │ │ └── regex.go │ ├── packages │ │ ├── package.go │ │ └── content.go │ └── client │ │ ├── version.go │ │ ├── tasks.go │ │ ├── oidc.go │ │ ├── config.go │ │ ├── service.go │ │ ├── operations.go │ │ ├── payload.go │ │ ├── registry.go │ │ ├── certificates.go │ │ ├── nodes.go │ │ └── addon.go ├── units │ └── units.go └── network │ ├── port.go │ └── cert.go ├── api └── ams │ ├── version.go │ ├── config.go │ ├── response.go │ ├── permission.go │ ├── service.go │ ├── registry.go │ ├── shares.go │ ├── network.go │ └── addon.go ├── go.sum └── SECURITY.md /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # The Anbox team owns all for now 2 | * @canonical/anbox 3 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/anbox-cloud/ams-sdk 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.8 6 | 7 | require ( 8 | github.com/gorilla/websocket v1.5.3 9 | golang.org/x/crypto v0.37.0 10 | gopkg.in/yaml.v2 v2.4.0 11 | ) 12 | 13 | require ( 14 | golang.org/x/sys v0.32.0 // indirect 15 | golang.org/x/term v0.31.0 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended", 5 | "helpers:pinGitHubActionDigestsToSemver", 6 | ":disableDependencyDashboard", 7 | ":ignoreUnstable", 8 | "group:allNonMajor" 9 | ], 10 | "packageRules": [ 11 | { 12 | "groupName": "GitHub actions", 13 | "matchManagers": [ 14 | "github-actions" 15 | ], 16 | "matchUpdateTypes": [ 17 | "digest", 18 | "patch", 19 | "minor", 20 | "major" 21 | ] 22 | }, 23 | { 24 | "matchManagers": [ 25 | "gomod" 26 | ], 27 | "enabled": false 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /examples/ams/container-list/README.md: -------------------------------------------------------------------------------- 1 | List Containers Example 2 | ======================= 3 | 4 | Demonstrates how to list the existing containers using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | 17 | Example: 18 | 19 | container-list -cert=./client.crt -key=./client.key -url=https://:8443 20 | 21 | Output: 22 | 23 | -------------------------------------------------------------------------------- /examples/ams/node-delete/README.md: -------------------------------------------------------------------------------- 1 | Delete Node Example 2 | =================== 3 | 4 | Demonstrates how to delete a node using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `name` | Name of the node | required | 17 | 18 | 19 | Example: 20 | 21 | node-delete -cert=./client.crt -key=./client.key -url=https://:8443 -name=lxd1 22 | 23 | Output: 24 | 25 | empty 26 | -------------------------------------------------------------------------------- /examples/ams/container-delete/README.md: -------------------------------------------------------------------------------- 1 | Delete Container Example 2 | ======================== 3 | 4 | Demonstrates how to delete a container using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | Identifier of the container to delete | required | 17 | 18 | 19 | Example: 20 | 21 | container-delete -cert=./client.crt -key=./client.key -url=https://:8443 -id=bgva3qu5nof0fqm089cg 22 | 23 | Output: 24 | 25 | empty 26 | 27 | -------------------------------------------------------------------------------- /examples/ams/addon-delete/README.md: -------------------------------------------------------------------------------- 1 | Delete Addon Example 2 | ==================== 3 | 4 | Demonstrates how to delete an addon using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `name` | Name of the addon | required | 17 | | `version` | Version of addon | optional | 18 | 19 | 20 | Example: 21 | 22 | addon-delete -cert=./client.crt -key=./client.key -url=https://:8443 -name=debugger 23 | 24 | Output: 25 | 26 | empty 27 | -------------------------------------------------------------------------------- /pkg/ams/shared/rest/api/version.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package api 20 | 21 | // Version of current exposed API 22 | const Version = "1.0" 23 | -------------------------------------------------------------------------------- /examples/ams/image-delete/README.md: -------------------------------------------------------------------------------- 1 | Delete Image Example 2 | ==================== 3 | 4 | Demonstrates how to delete an image or an image version using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | Id or name of the image to delete | required | 17 | | `version` | Version of the image to delete | optional | 18 | 19 | 20 | Example: 21 | 22 | image-delete -cert=./client.crt -key=./client.key -url=https://:8443 -id=bgvarifb9s9hpbfhgcdg 23 | 24 | Output: 25 | 26 | empty 27 | -------------------------------------------------------------------------------- /pkg/ams/constants/version.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package constants 20 | 21 | // Version is the version of AMS set from the build system 22 | var Version = "unknown" 23 | -------------------------------------------------------------------------------- /examples/ams/application-revoke/README.md: -------------------------------------------------------------------------------- 1 | Revoke Application Example 2 | ========================== 3 | 4 | Demonstrates how to revoke an application using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | Identifier of the application to revoke | required | 17 | | `version` | version of the application to revoke | required | 18 | 19 | 20 | Example: 21 | 22 | application-revoke -cert=./client.crt -key=./client.key -url=https://:8443 -id=bgutrvm5nof0fqm0894g -version=0 23 | 24 | Output: 25 | 26 | empty 27 | 28 | -------------------------------------------------------------------------------- /examples/ams/addon-update/README.md: -------------------------------------------------------------------------------- 1 | Update Addon Example 2 | ================= 3 | 4 | Demonstrates how to update an addon using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `name` | Name of the addon | required | 17 | | `path` | Path to the addon tarball | required | 18 | 19 | 20 | Example: 21 | 22 | addon-update -cert=./client.crt -key=./client.key -url=https://:8443 -name=debugger -path=./debugger-addon_0.1.tar.xz 23 | 24 | Output: 25 | 26 | { 27 | "addons": [ 28 | "debugger" 29 | ] 30 | } 31 | 32 | -------------------------------------------------------------------------------- /examples/ams/application-publish/README.md: -------------------------------------------------------------------------------- 1 | Publish Application Example 2 | =========================== 3 | 4 | Demonstrates how to publish an application using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | Identifier of the application to publish | required | 17 | | `version` | version of the application to publish | required | 18 | 19 | 20 | Example: 21 | 22 | application-publish -cert=./client.crt -key=./client.key -url=https://:8443 -id=bgutrvm5nof0fqm0894g -version=0 23 | 24 | Output: 25 | 26 | empty 27 | 28 | -------------------------------------------------------------------------------- /examples/ams/addon-add/README.md: -------------------------------------------------------------------------------- 1 | Update Addon Example 2 | ==================== 3 | 4 | Demonstrates how to update a new addon using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `name` | Name of the addon | required | 17 | | `path` | Path to the addon tarball | required | 18 | 19 | 20 | 21 | Example: 22 | 23 | addon-add -cert=./client.crt -key=./client.key -url=https://:8443 -name=debugger -path=./debugger-addon_0.1.tar.xz 24 | 25 | Output: 26 | 27 | { 28 | "addons": [ 29 | "debugger" 30 | ] 31 | } 32 | 33 | -------------------------------------------------------------------------------- /examples/ams/application-delete/README.md: -------------------------------------------------------------------------------- 1 | Delete Application Example 2 | ========================== 3 | 4 | Demonstrates how to delete an application or an application version using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | Identifier of the application to delete | required | 17 | | `version` | version of the application to delete | optional | 18 | 19 | 20 | Example: 21 | 22 | application-delete -cert=./client.crt -key=./client.key -url=https://:8443 -id=bgutrvm5nof0fqm0894g 23 | 24 | Output: 25 | 26 | empty 27 | 28 | -------------------------------------------------------------------------------- /api/ams/version.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package api 20 | 21 | // VersionGet is the JSON response from the API version request method 22 | // 23 | // swagger:model 24 | type VersionGet struct { 25 | Version string `json:"version"` 26 | } 27 | -------------------------------------------------------------------------------- /examples/ams/addon-show/README.md: -------------------------------------------------------------------------------- 1 | Show Addon Example 2 | ================== 3 | 4 | Demonstrates how to show an addon information using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `name` | Name of the addon | required | 17 | 18 | 19 | Example: 20 | 21 | addon-show -cert=./client.crt -key=./client.key -url=https://:8443 -name=debugger 22 | 23 | Output: 24 | 25 | { 26 | "name": "debugger", 27 | "versions": { 28 | "0": { 29 | "size": "238B", 30 | "created-at": "2018-09-17 11:15:44 +0000 UTC" 31 | } 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /examples/ams/image-add/README.md: -------------------------------------------------------------------------------- 1 | Add Image Example 2 | ================= 3 | 4 | Demonstrates how to add a new image using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `name` | Name of the image | required | 17 | | `package-path` | Path to the image xz tarball | required | 18 | 19 | 20 | Example: 21 | 22 | image-add -cert=./client.crt -key=./client.key -url=https://:8443 -name=default -package-path=./anbox-lxd-bionic-e0261ed-2018-09-17-0_arm64.tar.xz 23 | 24 | Output: 25 | 26 | { 27 | "images": [ 28 | "bgvarifb9s9hpbfhgcdg" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /pkg/ams/constants/network.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package constants 20 | 21 | // DefaultNodeBridgeAddress tthe IP address assigned to the default 22 | // network bridge used on all LXD nodes 23 | const DefaultNodeBridgeAddress = "192.168.100.1" 24 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= 2 | github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 3 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 4 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 5 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 6 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 7 | golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= 8 | golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= 9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 10 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 11 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 12 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 13 | -------------------------------------------------------------------------------- /pkg/ams/shared/rest/api/swagger.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | //go:build docs 19 | // +build docs 20 | 21 | package api 22 | 23 | func SwaggerModels() []string { 24 | return []string{ 25 | swaggerModelOperation, 26 | swaggerModelStatusCode, 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/ams/image-update/README.md: -------------------------------------------------------------------------------- 1 | Update Image Example 2 | ==================== 3 | 4 | Demonstrates how to upate an existing image using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `name` | Name of the image | required | 17 | | `package-path` | Path to the image xz tarball | required | 18 | 19 | 20 | Example: 21 | 22 | image-update -cert=./client.crt -key=./client.key -url=https://:8443 -name=default -package-path=./anbox-lxd-bionic-e0261ed-2018-09-17-0_arm64.tar.xz 23 | 24 | Output: 25 | 26 | { 27 | "images": [ 28 | "bgvarifb9s9hpbfhgcdg" 29 | ] 30 | } 31 | 32 | -------------------------------------------------------------------------------- /examples/ams/container-list-log/README.md: -------------------------------------------------------------------------------- 1 | List Container Logs Example 2 | ======================== 3 | 4 | Demonstrates how to list log files of a container 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | Identifier of the container | required | 17 | 18 | *NOTE*: These log files only exist when the container runs into error state. 19 | 20 | 21 | Example: 22 | 23 | container-list-log -cert=./client.crt -key=./client.key -url=https://:8443 -id=bgva3qu5nof0fqm089cg 24 | 25 | Output: 26 | 27 | [ 28 | "system.log", 29 | "container.log", 30 | "android.log", 31 | "console.log" 32 | ] 33 | -------------------------------------------------------------------------------- /pkg/units/units.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package units 20 | 21 | const ( 22 | // KB defines a single kilo-byte in bytes 23 | KB = 1024 24 | // MB defines a single mega-byte in bytes 25 | MB = KB * 1024 26 | // GB defines a single giga-byte in bytes 27 | GB = MB * 1024 28 | ) 29 | -------------------------------------------------------------------------------- /examples/ams/addon-list/README.md: -------------------------------------------------------------------------------- 1 | List Addons Example 2 | =================== 3 | 4 | Demonstrates how to list the installed addons using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | 17 | 18 | Example: 19 | 20 | addon-list -cert=./client.crt -key=./client.key -url=https://:8443 21 | 22 | Output: 23 | 24 | [ 25 | { 26 | "name": "debugger", 27 | "versions": [ 28 | { 29 | "version": 0, 30 | "fingerprint": "23b0b26f3c48a675b0fe3ab999fc0cfa3950ee051649c2bf45b7882976641eac", 31 | "size": 238, 32 | "created_at": 1547564337 33 | } 34 | ], 35 | "used_by": null 36 | } 37 | ] 38 | 39 | -------------------------------------------------------------------------------- /examples/ams/application-export/README.md: -------------------------------------------------------------------------------- 1 | Export Application Example 2 | ========================== 3 | 4 | Demonstrates how to export an existing version of an application using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | Identifier of the application to export | required | 17 | | `version` | version of the application to export | required | 18 | | `target` | Output name of Appliation package | optional | 19 | 20 | 21 | Example: 22 | 23 | application-export -cert=./client.crt -key=./client.key -url=https://:8443 -id=bgutrvm5nof0fqm0894g -version=0 24 | 25 | Output: 26 | 27 | Application exported successfully! 28 | 29 | -------------------------------------------------------------------------------- /examples/ams/node-set/README.md: -------------------------------------------------------------------------------- 1 | Set Node Property Example 2 | ========================= 3 | 4 | Demonstrates how to set a node property using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `name` | Name of the node | required | 17 | | `key` | Key of the property to set | required | 18 | | `value` | Value of the property to set | required | 19 | 20 | 21 | Available keys: 22 | 23 | - public-address 24 | - cpus 25 | - cpu-allocation-rate 26 | - memory 27 | - memory-allocation-rate 28 | 29 | Example: 30 | 31 | node-set -cert=./client.crt -key=./client.key -url=https://:8443 -name=lxd1 -key=public-address -value=174.56.55.2 32 | 33 | Output: 34 | 35 | empty 36 | -------------------------------------------------------------------------------- /pkg/ams/packages/package.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package packages 20 | 21 | // Package represents a generic interface for a package which helps for the validation 22 | type Package interface { 23 | // Validate validates a package 24 | Validate() error 25 | 26 | // Manifest returns the manifest structure of a package 27 | Manifest() interface{} 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | tag_name: 7 | description: 'Tag name for the release' 8 | required: true 9 | target_commitish: 10 | description: | 11 | Target commitish (see GH API) for tag creation. 12 | Can be empty - it will default to the head of the branch it is run from. 13 | required: false 14 | 15 | # To publish assets to on GitHub release pages 16 | permissions: 17 | contents: write 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | environment: stable 23 | steps: 24 | - name: Checkout repository 25 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 26 | 27 | - name: Release 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | run: | 31 | gh release create "${{ inputs.tag_name }}" \ 32 | --target "${{ inputs.target_commitish || github.ref }}" \ 33 | --title "${{ inputs.tag_name }}" \ 34 | --notes "See https://documentation.ubuntu.com/anbox-cloud/reference/release-notes/${{ inputs.tag_name }}/ for more information." 35 | -------------------------------------------------------------------------------- /examples/ams/image-show/README.md: -------------------------------------------------------------------------------- 1 | Show Image Example 2 | ================== 3 | 4 | Demonstrates how to show an image information using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | ID or name of the image to show | required | 17 | 18 | 19 | Example: 20 | 21 | image-show -cert=./client.crt -key=./client.key -url=https://:8443 -id=bgvarifb9s9hpbfhgcdg 22 | 23 | Output: 24 | 25 | { 26 | "id": "bgvarifb9s9hpbfhgcdg", 27 | "name": "default", 28 | "status": "active", 29 | "versions": { 30 | "0": { 31 | "size": "280.26MB", 32 | "created-at": "2019-01-16 04:06:33 +0000 UTC", 33 | "status": "active" 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /examples/ams/node-add/README.md: -------------------------------------------------------------------------------- 1 | Add Node Example 2 | ================ 3 | 4 | Demonstrates how to add a new node using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `name` | Name of the node | required | 17 | | `address` | Address where the node is accessible | required | 18 | | `trust-password` | Password for accessing to LXD server | optional | 19 | | `storage-device` | The pool or dataset used for storage | optional | 20 | | `network-bridge-mtu` | Network largest packet size | optional | 21 | 22 | 23 | Example: 24 | 25 | node-add -cert=./client.crt -key=./client.key -url=https://:8443 -name=node1 -address=192.168.0.8 26 | 27 | Output: 28 | 29 | { 30 | "nodes": [ 31 | "lxd1" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /pkg/ams/constants/names.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package constants 20 | 21 | const ( 22 | // DefaultNetworkName is the default LXD network name AMS creates 23 | DefaultNetworkName = "amsbr0" 24 | // AdminGroupName is the name of the default admin group 25 | AdminGroupName = "admin" 26 | // AdminGroupDescription is the description of the default admin group 27 | AdminGroupDescription = "Administrators" 28 | ) 29 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/aborted.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | // ErrAborted describes an error when an operation was aborted 22 | type ErrAborted struct { 23 | content 24 | } 25 | 26 | // Error returns the error string 27 | func (e ErrAborted) Error() string { 28 | return e.What 29 | } 30 | 31 | // NewErrAborted returns a new ErrAborted struct 32 | func NewErrAborted(what string) ErrAborted { 33 | return ErrAborted{content{what}} 34 | } 35 | -------------------------------------------------------------------------------- /api/ams/config.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package api 20 | 21 | // ConfigPost contains the field necessary to set or update a config item 22 | // 23 | // swagger:model 24 | type ConfigPost struct { 25 | // Example: application.auto_publish 26 | Name string `json:"name"` 27 | // Example: false 28 | Value string `json:"value"` 29 | } 30 | 31 | // ConfigGet describes a list of config items 32 | type ConfigGet struct { 33 | Config map[string]interface{} `json:"config"` 34 | } 35 | -------------------------------------------------------------------------------- /api/ams/response.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package api 20 | 21 | // Response is a standard response for AMS API operations 22 | type Response struct { 23 | Status string `json:"status"` 24 | StatusCode int `json:"status_code"` 25 | Error string `json:"error,omitempty"` 26 | } 27 | 28 | // SuccessResponse returns a default success response 29 | func SuccessResponse() Response { 30 | return Response{ 31 | Status: "success", 32 | StatusCode: 200, 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /pkg/ams/shared/buffered_reader.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package shared 20 | 21 | import "io" 22 | 23 | // BufferedReader represents a reader with buf size 24 | type BufferedReader struct { 25 | Reader io.Reader 26 | Size chan float64 27 | } 28 | 29 | // BufferedReader implements io.Reader interface 30 | func (r *BufferedReader) Read(p []byte) (int, error) { 31 | n, err := r.Reader.Read(p) 32 | if r.Size != nil { 33 | r.Size <- float64(n) 34 | } 35 | return n, err 36 | } 37 | -------------------------------------------------------------------------------- /examples/ams/node-show/README.md: -------------------------------------------------------------------------------- 1 | Show Node Example 2 | ================= 3 | 4 | Demonstrates how to show the information of a node using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `name` | Name of the node | required | 17 | 18 | 19 | Example: 20 | 21 | node-show -cert=./client.crt -key=./client.key -url=https://:8443 -name=lxd1 22 | 23 | Output: 24 | { 25 | "name": "lxd0", 26 | "status": "online", 27 | "network": { 28 | "address": "172.31.29.146", 29 | "bridge-mtu": 9001 30 | }, 31 | "config": { 32 | "public-address": "18.191.182.69", 33 | "cpus": 8, 34 | "cpu-allocation-rate": 4, 35 | "memory": "31GB", 36 | "memory-allocation-rate": 2, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ams/client/version.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | api "github.com/anbox-cloud/ams-sdk/api/ams" 23 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/client" 24 | ) 25 | 26 | // GetVersion returns the version of the AMS server (not the API version) 27 | func (c *clientImpl) GetVersion() (string, error) { 28 | v := api.VersionGet{} 29 | _, err := c.QueryStruct("GET", client.APIPath("version"), nil, nil, nil, "", &v) 30 | return v.Version, err 31 | } 32 | -------------------------------------------------------------------------------- /pkg/ams/constants/values.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package constants 20 | 21 | import ( 22 | "github.com/anbox-cloud/ams-sdk/pkg/units" 23 | ) 24 | 25 | const ( 26 | // MaxUserdataSize is the maximum size the userdata of a container can take. The size 27 | // of the userdata attached to a container has to be limited as a single element in our 28 | // data store can only have a maximum size of 1.5 MB and we store the userdata as part 29 | // of it. 30 | MaxUserdataSize = 10 * units.KB 31 | ) 32 | -------------------------------------------------------------------------------- /examples/ams/node-list/README.md: -------------------------------------------------------------------------------- 1 | List Nodes Example 2 | ================== 3 | 4 | Demonstrates how to list available nodes using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | 17 | Example: 18 | 19 | node-list -cert=./client.crt -key=./client.key -url=https://:8443 20 | 21 | Output: 22 | 23 | [ 24 | { 25 | "name": "lxd0", 26 | "address": "172.31.29.146", 27 | "public_address": "18.191.182.69", 28 | "network_bridge_mtu": 9001, 29 | "cpus": 8, 30 | "cpu_allocation_rate": 4, 31 | "memory": "31GB", 32 | "memory_allocation_rate": 2, 33 | "status_code": 4, 34 | "status": "online", 35 | "is_master": true, 36 | "disk_size": "13GB", 37 | "gpu_slots": 0 38 | } 39 | ] 40 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/failed.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrFailed describes an error when an operation has failed 26 | type ErrFailed struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrFailed) Error() string { 32 | return fmt.Sprintf("%s failed", e.What) 33 | } 34 | 35 | // NewErrFailed returns a new ErrFailed struct 36 | func NewErrFailed(what string) ErrFailed { 37 | return ErrFailed{content{what}} 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/required.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrRequired error struct for a required parameter 26 | type ErrRequired struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrRequired) Error() string { 32 | return fmt.Sprintf("%v is required", e.What) 33 | } 34 | 35 | // NewErrRequired returns a new ErrRequiredstruct 36 | func NewErrRequired(what string) ErrRequired { 37 | return ErrRequired{content{what}} 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/timeout.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrTimeout describes an error when an operation timed out 26 | type ErrTimeout struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrTimeout) Error() string { 32 | return fmt.Sprintf("%s timed out", e.What) 33 | } 34 | 35 | // NewErrTimeout returns a new ErrAborted struct 36 | func NewErrTimeout(what string) ErrTimeout { 37 | return ErrTimeout{content{what}} 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/unknown.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrUnknown describes the error which a parameter was unknown 26 | type ErrUnknown struct { 27 | content 28 | } 29 | 30 | // ErrUnknown returns the error string 31 | func (e ErrUnknown) Error() string { 32 | return fmt.Sprintf("%s is unknown", e.What) 33 | } 34 | 35 | // NewErrUnknown returns a new ErrUnknown struct 36 | func NewErrUnknown(what string) ErrUnknown { 37 | return ErrUnknown{content{what}} 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ams/client/tasks.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | api "github.com/anbox-cloud/ams-sdk/api/ams" 23 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/client" 24 | ) 25 | 26 | // ListTasks returns a list of all availables tasks 27 | func (c *clientImpl) ListTasks() ([]api.Task, error) { 28 | tasks := []api.Task{} 29 | params := client.QueryParams{ 30 | "recursion": "1", 31 | } 32 | _, err := c.QueryStruct("GET", client.APIPath("tasks"), params, nil, nil, "", &tasks) 33 | return tasks, err 34 | } 35 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/malformed.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrMalformed describes the error when a malformed content was given 26 | type ErrMalformed struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrMalformed) Error() string { 32 | return fmt.Sprintf("%s is malformed", e.What) 33 | } 34 | 35 | // NewErrMalformed returns a new ErrMalformed struct 36 | func NewErrMalformed(what string) ErrMalformed { 37 | return ErrMalformed{content{what}} 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/in_progress.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrInProgress describes an error when an operation is already in progress 26 | type ErrInProgress struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrInProgress) Error() string { 32 | return fmt.Sprintf("%s already in progress", e.What) 33 | } 34 | 35 | // NewErrInProgress returns a new ErrInProgress struct 36 | func NewErrInProgress(what string) ErrInProgress { 37 | return ErrInProgress{content{what}} 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/not_supported.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrNotSupported error struct for a not supported functionality 26 | type ErrNotSupported struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrNotSupported) Error() string { 32 | return fmt.Sprintf("%v not supported", e.What) 33 | } 34 | 35 | // NewErrNotSupported returns a new ErrNotSupported struct 36 | func NewErrNotSupported(what string) ErrNotSupported { 37 | return ErrNotSupported{content{what}} 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/already_exists.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrAlreadyExists describes an error when a resource already exists 26 | type ErrAlreadyExists struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrAlreadyExists) Error() string { 32 | return fmt.Sprintf("%s already exists", e.What) 33 | } 34 | 35 | // NewErrAlreadyExists returns a new ErrAlreadyExists struct 36 | func NewErrAlreadyExists(what string) ErrAlreadyExists { 37 | return ErrAlreadyExists{content{what}} 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/not_executable.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrNotExecutable represents a non executable file permission error structure 26 | type ErrNotExecutable struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrNotExecutable) Error() string { 32 | return fmt.Sprintf("%v not executable", e.What) 33 | } 34 | 35 | // NewErrNotExecutable returns a new ErrNotExecutable struct 36 | func NewErrNotExecutable(what string) ErrNotExecutable { 37 | return ErrNotExecutable{content{what}} 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/invalid_length.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrInvalidLength describes the error when an argument has an invalid length 26 | type ErrInvalidLength struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrInvalidLength) Error() string { 32 | return fmt.Sprintf("length of %s is invalid", e.What) 33 | } 34 | 35 | // NewErrInvalidLength returns a new ErrInvalidLength struct 36 | func NewErrInvalidLength(what string) ErrInvalidLength { 37 | return ErrInvalidLength{content{what}} 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ams/constants/regex.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package constants 20 | 21 | const ( 22 | // ApplicationNamePattern describes the regular expression to validate an 23 | // application name 24 | ApplicationNamePattern = `^([A-Za-z0-9_\-\.]*)$` 25 | 26 | // AddonNamePattern describes the regular expression to validate an 27 | // addon name 28 | AddonNamePattern = ApplicationNamePattern 29 | 30 | // AndroidPackageNamePattern describes the regular expression to validate an 31 | // Android package name 32 | AndroidPackageNamePattern = `^([A-Za-z]{1}[A-Za-z\d_]*\.){1,}[A-Za-z][A-Za-z\d_]*$` 33 | ) 34 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/invalid_format.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrInvalidFormat describes the error when an invalid format for an argument was given 26 | type ErrInvalidFormat struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrInvalidFormat) Error() string { 32 | return fmt.Sprintf("%s invalid format", e.What) 33 | } 34 | 35 | // NewErrInvalidFormat returns a new ErrInvalidFormat struct 36 | func NewErrInvalidFormat(what string) ErrInvalidFormat { 37 | return ErrInvalidFormat{content{what}} 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/common.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | var ( 26 | // ErrAlreadyRunning is returned when an object is already running when it was started again 27 | ErrAlreadyRunning = fmt.Errorf("Already running") 28 | ) 29 | 30 | type content struct { 31 | What string 32 | } 33 | 34 | // IgnoreErrNotFound returns nil when the provided error is of type ErrNotFound 35 | // and otherwise the given error 36 | func IgnoreErrNotFound(err error) error { 37 | switch err.(type) { 38 | case ErrNotFound: 39 | return nil 40 | default: 41 | return err 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/dont_match.go: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | package errors 19 | 20 | import ( 21 | "fmt" 22 | ) 23 | 24 | // ErrDontMatch error struct for a parameter whose value does not match the expected 25 | type ErrDontMatch struct { 26 | content 27 | got string 28 | expected string 29 | } 30 | 31 | // Error returns the error string 32 | func (e ErrDontMatch) Error() string { 33 | return fmt.Sprintf("%v don't match, got %v but expected %v", e.What, e.got, e.expected) 34 | } 35 | 36 | // NewErrDontMatch returns a new ErrDontMatch struct 37 | func NewErrDontMatch(what, got, expected string) ErrDontMatch { 38 | return ErrDontMatch{content{what}, got, expected} 39 | } 40 | -------------------------------------------------------------------------------- /examples/ams/container-show/README.md: -------------------------------------------------------------------------------- 1 | Show Container Example 2 | ====================== 3 | 4 | Demonstrates how to show a container information using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | Identifier of the container | required | 17 | 18 | 19 | Example: 20 | 21 | container-show -cert=./client.crt -key=./client.key -url=https://:8443 -id=bgvb70vb9s9jdk3dpujg 22 | 23 | Output: 24 | 25 | { 26 | "id": "bgvb70vb9s9jdk3dpujg", 27 | "name": "ams-bgvb70vb9s9jdk3dpujg", 28 | "status": "running", 29 | "node": "lxd0", 30 | "created_at": "1970-01-01T00:00:00Z", 31 | "application": { 32 | "id": "bgvb6u7b9s9jdk3dpuj0" 33 | }, 34 | "image": {}, 35 | "network": { 36 | "address": "192.168.100.2", 37 | "public_address": "18.191.182.69", 38 | "services": null 39 | }, 40 | "stored_logs": null, 41 | "error_message": "" 42 | } 43 | -------------------------------------------------------------------------------- /examples/ams/node-list/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "log" 23 | 24 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 25 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 26 | ) 27 | 28 | type nodeListCmd struct { 29 | common.ConnectionCmd 30 | } 31 | 32 | func main() { 33 | cmd := &nodeListCmd{} 34 | cmd.Parse() 35 | c := cmd.NewClient() 36 | 37 | if err := listNodes(c); err != nil { 38 | log.Fatal(err) 39 | } 40 | } 41 | 42 | func listNodes(c client.Client) error { 43 | nodes, err := c.ListNodes() 44 | if err != nil { 45 | return err 46 | } 47 | 48 | return common.DumpData(nodes) 49 | } 50 | -------------------------------------------------------------------------------- /examples/ams/addon-list/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "log" 23 | 24 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 25 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 26 | ) 27 | 28 | type addonListCmd struct { 29 | common.ConnectionCmd 30 | } 31 | 32 | func main() { 33 | cmd := &addonListCmd{} 34 | cmd.Parse() 35 | c := cmd.NewClient() 36 | 37 | if err := listAddons(c); err != nil { 38 | log.Fatal(err) 39 | } 40 | } 41 | 42 | func listAddons(c client.Client) error { 43 | addons, err := c.ListAddons() 44 | if err != nil { 45 | return err 46 | } 47 | 48 | return common.DumpData(addons) 49 | } 50 | -------------------------------------------------------------------------------- /examples/ams/image-list/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "log" 23 | 24 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 25 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 26 | ) 27 | 28 | type imageListCmd struct { 29 | common.ConnectionCmd 30 | } 31 | 32 | func main() { 33 | cmd := &imageListCmd{} 34 | cmd.Parse() 35 | c := cmd.NewClient() 36 | 37 | if err := listImages(c); err != nil { 38 | log.Fatal(err) 39 | } 40 | } 41 | 42 | func listImages(c client.Client) error { 43 | images, err := c.ListImages() 44 | if err != nil { 45 | return err 46 | } 47 | 48 | return common.DumpData(images) 49 | } 50 | -------------------------------------------------------------------------------- /examples/ams/application-list/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "log" 23 | 24 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 25 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 26 | ) 27 | 28 | type appListCmd struct { 29 | common.ConnectionCmd 30 | } 31 | 32 | func main() { 33 | cmd := &appListCmd{} 34 | cmd.Parse() 35 | c := cmd.NewClient() 36 | 37 | if err := listApplications(c); err != nil { 38 | log.Fatal(err) 39 | } 40 | } 41 | 42 | func listApplications(c client.Client) error { 43 | apps, err := c.ListApplications() 44 | if err != nil { 45 | return err 46 | } 47 | 48 | return common.DumpData(apps) 49 | } 50 | -------------------------------------------------------------------------------- /examples/ams/image-list/README.md: -------------------------------------------------------------------------------- 1 | List Images Example 2 | =================== 3 | 4 | Demonstrates how to list available images using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | 17 | Example: 18 | 19 | image-list -cert=./client.crt -key=./client.key -url=https://:8443 20 | 21 | Output: 22 | 23 | [ 24 | { 25 | "id": "bgvarifb9s9hpbfhgcdg", 26 | "name": "default", 27 | "versions": [ 28 | { 29 | "version": 0, 30 | "fingerprint": "8174a75351c660008c1db3ff17c4bfe78774bc020ba581397576fff349b095b1", 31 | "size": 293870712, 32 | "created_at": 1547611593, 33 | "status_code": 3, 34 | "status": "active" 35 | } 36 | ], 37 | "status_code": 3, 38 | "status": "active", 39 | "used_by": [ 40 | "bgvb6u7b9s9jdk3dpuj0" 41 | ] 42 | } 43 | ] 44 | 45 | 46 | -------------------------------------------------------------------------------- /examples/ams/container-list/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "log" 23 | 24 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 25 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 26 | ) 27 | 28 | type containerListCmd struct { 29 | common.ConnectionCmd 30 | } 31 | 32 | func main() { 33 | cmd := &containerListCmd{} 34 | cmd.Parse() 35 | c := cmd.NewClient() 36 | 37 | if err := listContainers(c); err != nil { 38 | log.Fatal(err) 39 | } 40 | } 41 | 42 | func listContainers(c client.Client) error { 43 | containers, err := c.ListContainers() 44 | if err != nil { 45 | return err 46 | } 47 | 48 | return common.DumpData(containers) 49 | } 50 | -------------------------------------------------------------------------------- /examples/ams/common/common.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package common 20 | 21 | import ( 22 | "encoding/json" 23 | "fmt" 24 | "os" 25 | "path" 26 | ) 27 | 28 | // PrintCreated prints out created resources 29 | func PrintCreated(resources map[string][]string) { 30 | for k, r := range resources { 31 | fmt.Printf("%s:\n", k) 32 | for _, j := range r { 33 | fmt.Printf(" - %s\n", path.Base(j)) 34 | } 35 | } 36 | } 37 | 38 | // DumpData prints out object in a human readable format 39 | func DumpData(data interface{}) error { 40 | b, err := json.MarshalIndent(&data, "", "\t") 41 | if err != nil { 42 | return err 43 | } 44 | fmt.Fprintf(os.Stdout, "%s", string(b)) 45 | return nil 46 | } 47 | -------------------------------------------------------------------------------- /api/ams/permission.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | package api 19 | 20 | // Permission represents a structure defining a permission within AMS. 21 | // 22 | // swagger:model 23 | type Permission struct { 24 | // Entitlement represents the type of action allowed on a resource 25 | // Example: can_edit 26 | Entitlement string `json:"entitlement" yaml:"entitlement"` 27 | 28 | // Resource represents the object on which a permission is being assigned. 29 | // The resource can be for the format `:` or `server` 30 | // `server` is a special resource used to assign permissions globally for the server. 31 | // Example: instance:foo 32 | Resource string `json:"resource" yaml:"resource"` 33 | } 34 | -------------------------------------------------------------------------------- /pkg/ams/packages/content.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package packages 20 | 21 | import ( 22 | "os" 23 | "strings" 24 | ) 25 | 26 | // ContentList represents a list of content 27 | type ContentList []string 28 | 29 | // Has checks if the given content is included in the content list 30 | func (c *ContentList) Has(content string) bool { 31 | for _, contentPath := range *c { 32 | // Dir path contains a trailing separator, which needs to be removed before comparing 33 | if strings.TrimRight(contentPath, string(os.PathSeparator)) == content { 34 | return true 35 | } 36 | } 37 | return false 38 | } 39 | 40 | // Add adds new contents into the list 41 | func (c *ContentList) Add(content ...string) { 42 | *c = append(*c, content...) 43 | } 44 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/not_found.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrNotFound error struct for a not existing resource 26 | type ErrNotFound struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrNotFound) Error() string { 32 | return fmt.Sprintf("%v not found", e.What) 33 | } 34 | 35 | // NewErrNotFound returns a new ErrNotFound struct 36 | func NewErrNotFound(what string) ErrNotFound { 37 | return ErrNotFound{content{what}} 38 | } 39 | 40 | // IsErrNotFound checks if the given error is of type ErrNotFound 41 | func IsErrNotFound(err error) bool { 42 | switch err.(type) { 43 | case ErrNotFound: 44 | return true 45 | default: 46 | return false 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/not_changed.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import "fmt" 22 | 23 | // ErrNotChanged describes an error when a value has changed 24 | type ErrNotChanged struct { 25 | content 26 | } 27 | 28 | // Error returns the error string 29 | func (e ErrNotChanged) Error() string { 30 | return fmt.Sprintf("%s not changed", e.What) 31 | } 32 | 33 | // NewErrNotChanged returns a new ErrNotChanged struct 34 | func NewErrNotChanged(what string) ErrNotChanged { 35 | return ErrNotChanged{content{what}} 36 | } 37 | 38 | // IsErrNotChanged checks if the given error is of type ErrNotChanged 39 | func IsErrNotChanged(err error) bool { 40 | switch err.(type) { 41 | case ErrNotChanged: 42 | return true 43 | default: 44 | return false 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Anbox Cloud security policy 2 | 3 | Learn about our [release and support policy](https://documentation.ubuntu.com/anbox-cloud/en/latest/reference/release-notes/release-notes/#release-and-support-policy) for the nature of our releases and versions. 4 | 5 | ## Reporting a vulnerability 6 | 7 | If you discover a security vulnerability, follow the steps outlined below to report it: 8 | 9 | 1. Do not publicly disclose the vulnerability before discussing it with us. 10 | 2. Report a bug at https://bugs.launchpad.net/anbox-cloud 11 | 12 | **Important**: Remember to set the information type to *Private Security*. You will see a field with the text *This bug contains information that is:* 13 | 3. Provide detailed information about the vulnerability, including: 14 | - A description of the vulnerability 15 | - Steps to reproduce the issue 16 | - Potential impact and affected versions 17 | - Suggested mitigation, if possible 18 | 19 | The [Ubuntu Security disclosure and embargo policy](https://ubuntu.com/security/disclosure-policy) contains more information about what you can expect when you contact us and what we expect from you. 20 | 21 | The Anbox Cloud team will be notified of the issue and review the vulnerability. We may reach out to you for further information or clarification if needed. 22 | If the issue is confirmed as a valid security vulnerability, we will assign a CVE and coordinate the release of the fix. We also document them as [security notices](https://documentation.ubuntu.com/anbox-cloud/en/latest/reference/security-notices/). 23 | -------------------------------------------------------------------------------- /examples/ams/container-launch/README.md: -------------------------------------------------------------------------------- 1 | Launch Container Example 2 | ======================== 3 | 4 | Demonstrates how to launch a new container using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | Identifier of the application | required | 17 | | `version` | Version of the application | optional | 18 | | `node` | In which node to launch the container | optional | 19 | | `raw` | Launched a container from a specific image instead of an application if it's set to true | optional | 20 | | `instance-type` | Instance type to use when launching a container from an image instead of an application | optional | 21 | 22 | *NOTE*: If the optional parameter `raw` is set to true, this parameter `id` will accept an image id 23 | or image name instead. As a result, a container will be launched from a specific image instead of 24 | an application 25 | 26 | 27 | Example: 28 | 29 | container-launch -cert=./client.crt -key=./client.key -url=https://:8443 id=bgutrvm5nof0fqm0894g 30 | 31 | Output: 32 | 33 | { 34 | "containers": [ 35 | "bgv0afe5nof0fqm089b0" 36 | ] 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /examples/ams/container-show-log/README.md: -------------------------------------------------------------------------------- 1 | Show Container Log Example 2 | ======================== 3 | 4 | Demonstrates how to show the specified log file of a container 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | Identifier of the container | required | 17 | | `log-name`| Name of the container log | required | 18 | 19 | 20 | Example: 21 | 22 | container-log -cert=./client.crt -key=./client.key -url=https://:8443 -id=bgvb70vb9s9jdk3dpujg -log-name=container.log 23 | 24 | Output: 25 | .... 26 | .... 27 | lxc 20190114075135.363 DEBUG lxc_start - start.c:__lxc_start:1402 - Tearing down virtual network devices used by container "default". 28 | lxc 20190114075135.363 INFO lxc_conf - conf.c:lxc_delete_network:3072 - Interface "(null)" with index 114 already deleted or existing in different network namespace. 29 | lxc 20190114075135.423 INFO lxc_conf - conf.c:lxc_delete_network:3105 - Removed interface "vethR8S81A" from host. 30 | lxc 20190114075135.463 INFO lxc_conf - conf.c:run_script_argv:435 - Executing script "/usr/share/lxcfs/lxc.reboot.hook" for container "default", config section "lxc". 31 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/not_allowed.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrNotAllowed error struct when an operation is not allowed 26 | type ErrNotAllowed struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrNotAllowed) Error() string { 32 | return fmt.Sprintf("%v not allowed", e.What) 33 | } 34 | 35 | // NewErrNotAllowed returns a new ErrNotAllowed struct 36 | func NewErrNotAllowed(what string) ErrNotAllowed { 37 | return ErrNotAllowed{content{what}} 38 | } 39 | 40 | // IsErrNotAllowed checks if the given error is of type ErrNotAllowed 41 | func IsErrNotAllowed(err error) bool { 42 | switch err.(type) { 43 | case ErrNotAllowed: 44 | return true 45 | default: 46 | return false 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pkg/ams/shared/errors/invalid_argument.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package errors 20 | 21 | import ( 22 | "fmt" 23 | ) 24 | 25 | // ErrInvalidArgument describes the error when an invalid argument was given 26 | type ErrInvalidArgument struct { 27 | content 28 | } 29 | 30 | // Error returns the error string 31 | func (e ErrInvalidArgument) Error() string { 32 | return fmt.Sprintf("argument %s is invalid", e.What) 33 | } 34 | 35 | // NewInvalidArgument returns a new ErrInvalidArgument struct 36 | func NewInvalidArgument(what string) ErrInvalidArgument { 37 | return ErrInvalidArgument{content{what}} 38 | } 39 | 40 | // IsErrInvalidArgument checks if the given error is of type ErrInvalidArgument 41 | func IsErrInvalidArgument(err error) bool { 42 | switch err.(type) { 43 | case ErrInvalidArgument: 44 | return true 45 | default: 46 | return false 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pkg/ams/client/oidc.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | errs "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/errors" 23 | restapi "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/api" 24 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/client" 25 | ) 26 | 27 | // GetOIDCConfig returns the OIDC configuration of the AMS service 28 | func (c *clientImpl) GetOIDCConfig(grantType string) (*restapi.OIDCResponse, string, error) { 29 | hasOIDCSupport, err := c.HasExtension("oidc_support") 30 | if err != nil { 31 | return nil, "", err 32 | } 33 | if !hasOIDCSupport { 34 | return nil, "", errs.NewErrNotSupported("OIDC Authentication") 35 | } 36 | config := &restapi.OIDCResponse{} 37 | params := client.QueryParams{} 38 | if grantType == "device_code" { 39 | params["grant_type"] = grantType 40 | } 41 | etag, err := c.QueryStruct("GET", client.APIPath("auth/oidc"), params, nil, nil, "", config) 42 | return config, etag, err 43 | } 44 | -------------------------------------------------------------------------------- /pkg/ams/shared/locker.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package shared 20 | 21 | import "sync/atomic" 22 | 23 | const ( 24 | stateUnlocked uint32 = iota 25 | stateLocked 26 | ) 27 | 28 | // Locker represents a locker which acquires the lock only if it is 29 | // not held by another goroutine at the time of invocation. 30 | type Locker struct { 31 | val uint32 32 | } 33 | 34 | // NewLocker returns a new Locker which can be used by a goroutine to 35 | // hold the internal lock and perform task which can not be invoked 36 | // by other goroutine 37 | func NewLocker() *Locker { 38 | return &Locker{val: stateUnlocked} 39 | } 40 | 41 | // TryLock attempts to acquire the lock immediately, return true if locking succeeds 42 | // otherwise return false. 43 | func (l *Locker) TryLock() bool { 44 | return atomic.CompareAndSwapUint32(&l.val, stateUnlocked, stateLocked) 45 | } 46 | 47 | // UnLock attempts to release the lock immediately. 48 | func (l *Locker) UnLock() { 49 | atomic.StoreUint32(&l.val, stateUnlocked) 50 | } 51 | -------------------------------------------------------------------------------- /examples/ams/node-delete/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | 27 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 28 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 29 | ) 30 | 31 | type nodeDeleteCmd struct { 32 | common.ConnectionCmd 33 | name string 34 | } 35 | 36 | func (command *nodeDeleteCmd) Parse() { 37 | flag.StringVar(&command.name, "name", "", "Name of the node") 38 | 39 | command.ConnectionCmd.Parse() 40 | 41 | if len(command.name) == 0 { 42 | flag.Usage() 43 | os.Exit(1) 44 | } 45 | } 46 | 47 | func main() { 48 | cmd := &nodeDeleteCmd{} 49 | cmd.Parse() 50 | c := cmd.NewClient() 51 | 52 | if err := deleteNode(c, cmd.name); err != nil { 53 | log.Fatal(err) 54 | } 55 | } 56 | 57 | func deleteNode(c client.Client, name string) error { 58 | operation, err := c.RemoveNode(name, false, false) 59 | if err != nil { 60 | return err 61 | } 62 | 63 | // Wait for delete operation to finish 64 | return operation.Wait(context.Background()) 65 | } 66 | -------------------------------------------------------------------------------- /examples/ams/container-list-log/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "flag" 23 | "fmt" 24 | "log" 25 | "os" 26 | 27 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 28 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 29 | ) 30 | 31 | type containerListLogCmd struct { 32 | common.ConnectionCmd 33 | containerID string 34 | } 35 | 36 | func (command *containerListLogCmd) Parse() { 37 | command.ConnectionCmd.Parse() 38 | 39 | if flag.NArg() != 1 { 40 | flag.Usage() 41 | fmt.Println(" string") 42 | os.Exit(1) 43 | } 44 | 45 | command.containerID = flag.Args()[0] 46 | } 47 | 48 | func main() { 49 | cmd := &containerListLogCmd{} 50 | cmd.Parse() 51 | c := cmd.NewClient() 52 | 53 | if err := listContainerLogs(c, cmd.containerID); err != nil { 54 | log.Fatal(err) 55 | } 56 | } 57 | 58 | func listContainerLogs(c client.Client, id string) error { 59 | container, _, err := c.RetrieveContainerByID(id) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | common.DumpData(container.StoredLogs) 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /pkg/ams/client/config.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | "bytes" 23 | "context" 24 | "encoding/json" 25 | 26 | api "github.com/anbox-cloud/ams-sdk/api/ams" 27 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/client" 28 | ) 29 | 30 | // SetConfigItem sets the specified config item to the given value 31 | func (c *clientImpl) SetConfigItem(name, value string) error { 32 | req := api.ConfigPost{ 33 | Name: name, 34 | Value: value, 35 | } 36 | 37 | b, err := json.Marshal(req) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | op, _, err := c.QueryOperation("PATCH", client.APIPath("config"), nil, nil, bytes.NewReader(b), "") 43 | if err != nil { 44 | return err 45 | } 46 | return op.Wait(context.Background()) 47 | } 48 | 49 | // RetrieveConfigItems returns a list of configuration items available on the AMS service 50 | func (c *clientImpl) RetrieveConfigItems() (map[string]interface{}, error) { 51 | resp := api.ConfigGet{} 52 | _, err := c.QueryStruct("GET", client.APIPath("config"), nil, nil, nil, "", &resp) 53 | return resp.Config, err 54 | } 55 | -------------------------------------------------------------------------------- /pkg/ams/shared/rest/api/certificate.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package api 20 | 21 | // CertificatesPost represents the fields of a new auth provided certificate 22 | // 23 | // swagger:model 24 | type CertificatesPost struct { 25 | // Base64 encoded certificate content without the header or the footer 26 | // Example: MIIFUTCCAzmgAw...xjKoUEEQOzJ9 27 | Certificate string `json:"certificate" yaml:"certificate"` 28 | // TrustPassword is used to register a new client with the service 29 | // Example: sUp3rs3cr3t 30 | TrustPassword string `json:"trust-password,omitempty" yaml:"trust-password,omitempty"` 31 | } 32 | 33 | // Certificate represents an available client certificate 34 | // 35 | // swagger:model 36 | type Certificate struct { 37 | // Base64 encoded certificate content without the header or the footer 38 | // Example: MIIFUTCCAzmgAw...xjKoUEEQOzJ9 39 | Certificate string `json:"certificate" yaml:"certificate"` 40 | // SHA-256 fingerprint of the certificate 41 | // Example: b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 42 | Fingerprint string `json:"fingerprint" yaml:"fingerprint"` 43 | } 44 | -------------------------------------------------------------------------------- /pkg/ams/client/service.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | api "github.com/anbox-cloud/ams-sdk/api/ams" 23 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/client" 24 | ) 25 | 26 | // RetrieveServiceStatus returns the status of the AMS service 27 | func (c *clientImpl) RetrieveServiceStatus() (*api.ServiceStatus, string, error) { 28 | status := &api.ServiceStatus{} 29 | etag, err := c.QueryStruct("GET", client.APIPath(""), nil, nil, nil, "", status) 30 | return status, etag, err 31 | } 32 | 33 | // HasExtension checks if the AMS service the client is connected to supports 34 | // the given API extension. Returns true if the API extension is supported and 35 | // false otherwise. 36 | func (c *clientImpl) HasExtension(name string) (bool, error) { 37 | if c.serviceStatus == nil { 38 | status, _, err := c.RetrieveServiceStatus() 39 | if err != nil { 40 | return false, err 41 | } 42 | c.serviceStatus = status 43 | } 44 | 45 | for _, ext := range c.serviceStatus.APIExtensions { 46 | if ext == name { 47 | return true, nil 48 | } 49 | } 50 | 51 | return false, nil 52 | } 53 | -------------------------------------------------------------------------------- /examples/ams/application-show/README.md: -------------------------------------------------------------------------------- 1 | Show Application Example 2 | ======================== 3 | 4 | Demonstrates how to show the information of an existing application using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | Identifier of the application to show | required | 17 | 18 | 19 | Example: 20 | 21 | application-show -cert=./client.crt -key=./client.key -url=https://:8443 -id=bgutrvm5nof0fqm0894g 22 | 23 | Output: 24 | 25 | { 26 | "id": "bgutrvm5nof0fqm0894g", 27 | "name": "clash of clans", 28 | "status": "ready", 29 | "published": true, 30 | "immutable": false, 31 | "Config": { 32 | "instance-type": "a2.3", 33 | "boot-package": "com.supercell.clashofclans" 34 | }, 35 | "versions": { 36 | "0": { 37 | "image": "bguqesm5nof675ard8b0 (version 0)", 38 | "published": true, 39 | "status": "active", 40 | "required-permissions": [ 41 | "android.permission.WRITE_EXTERNAL_STORAGE", 42 | "android.permission.READ_EXTERNAL_STORAGE" 43 | ], 44 | "extra-data": { 45 | "com.supercell.clashofclans.obb": { 46 | "target": "/data/app/com.supercell.clashofclans-1/lib" 47 | }, 48 | "game-data-folder": { 49 | "target": "/sdcard/Android/data/com.supercell.clashofclans/" 50 | } 51 | } 52 | } 53 | } 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /pkg/ams/client/operations.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/api" 23 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/client" 24 | ) 25 | 26 | // ListOperations lists all operations arranged by their status 27 | func (c *clientImpl) ListOperations() (map[string][]*api.Operation, error) { 28 | params := client.QueryParams{ 29 | "recursion": "1", 30 | } 31 | var operations map[string][]*api.Operation 32 | _, err := c.QueryStruct("GET", client.APIPath("operations"), params, nil, nil, "", &operations) 33 | return operations, err 34 | } 35 | 36 | // ShowOperation shows details about a single operation 37 | func (c *clientImpl) ShowOperation(id string) (*api.Operation, error) { 38 | var operation *api.Operation 39 | _, err := c.QueryStruct("GET", client.APIPath("operations", id), nil, nil, nil, "", &operation) 40 | return operation, err 41 | } 42 | 43 | // CancelOperation cancels an operation if it supports it 44 | func (c *clientImpl) CancelOperation(id string) error { 45 | _, _, err := c.CallAPI("DELETE", client.APIPath("operations", id), nil, nil, nil, "") 46 | return err 47 | } 48 | -------------------------------------------------------------------------------- /examples/ams/container-delete/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | 27 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 28 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 29 | ) 30 | 31 | type containerDeleteCmd struct { 32 | common.ConnectionCmd 33 | id string 34 | force bool 35 | } 36 | 37 | func (command *containerDeleteCmd) Parse() { 38 | flag.StringVar(&command.id, "id", "", "Container id") 39 | flag.BoolVar(&command.force, "force", false, "Force the removal of the container") 40 | 41 | command.ConnectionCmd.Parse() 42 | 43 | if len(command.id) == 0 { 44 | flag.Usage() 45 | os.Exit(1) 46 | } 47 | } 48 | 49 | func main() { 50 | cmd := &containerDeleteCmd{} 51 | cmd.Parse() 52 | c := cmd.NewClient() 53 | 54 | if err := deleteContainer(c, cmd.id, cmd.force); err != nil { 55 | log.Fatal(err) 56 | } 57 | } 58 | 59 | func deleteContainer(c client.Client, id string, force bool) error { 60 | operation, err := c.DeleteContainerByID(id, force) 61 | if err != nil { 62 | return err 63 | } 64 | 65 | // Wait for delete operation to finish 66 | return operation.Wait(context.Background()) 67 | } 68 | -------------------------------------------------------------------------------- /api/ams/service.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package api 20 | 21 | // ServiceStatus represents the status of the AMS service 22 | // 23 | // swagger:model ServiceStatus 24 | type ServiceStatus struct { 25 | // List of supported features for the service version running 26 | // Example: ["addon_restore_hook", "container_logs", "registry"] 27 | APIExtensions []string `json:"api_extensions" yaml:"api_extensions"` 28 | // Shows the API stability status 29 | // Example: stable 30 | APIStatus string `json:"api_status" yaml:"api_status"` 31 | // API version for the service 32 | // Example: 1.0 33 | APIVersion string `json:"api_version" yaml:"api_version"` 34 | // Used to see if the client is trusted. Can be `trusted` or `untrusted`. 35 | // Example: untrusted 36 | Auth string `json:"auth" yaml:"auth"` 37 | // Authentication method used for the requests. 38 | // Example: 2waySSL 39 | AuthMethods []string `json:"auth_methods" yaml:"auth_methods"` 40 | 41 | // ID of the subcluster the AMS instance is part of 42 | // Example: cilsreunfpfec9b1ktg0 43 | ClusterID string `json:"cluster_id" yaml:"cluster_id"` 44 | // Name of the subcluster the AMS instance is part of 45 | // Example: prod0 46 | ClusterName string `json:"cluster_name" yaml:"cluster_name"` 47 | } 48 | -------------------------------------------------------------------------------- /pkg/ams/client/payload.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | "crypto/sha256" 23 | "fmt" 24 | "io" 25 | "os" 26 | 27 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared" 28 | errs "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/errors" 29 | ) 30 | 31 | // Uploader represents a uploader that tracks progress 32 | type Uploader struct { 33 | r io.Reader 34 | sent chan float64 35 | } 36 | 37 | // Read implements io.Reader interface 38 | func (u *Uploader) Read(p []byte) (int, error) { 39 | n, err := u.r.Read(p) 40 | if u.sent != nil { 41 | u.sent <- float64(n) 42 | } 43 | return n, err 44 | } 45 | 46 | func preparePayload(filepath string) (io.Reader, string, error) { 47 | if !shared.PathExists(filepath) { 48 | return nil, "", errs.NewErrNotFound("payload") 49 | } 50 | 51 | f, err := os.Open(filepath) 52 | if err != nil { 53 | return nil, "", err 54 | } 55 | 56 | hasher := sha256.New() 57 | _, err = io.Copy(hasher, f) 58 | if err != nil { 59 | return nil, "", err 60 | } 61 | 62 | fingerprint := fmt.Sprintf("%x", hasher.Sum(nil)) 63 | 64 | // move cursor to the beginning of the file after hashing 65 | _, err = f.Seek(0, 0) 66 | if err != nil { 67 | return nil, "", err 68 | } 69 | 70 | return f, fingerprint, nil 71 | } 72 | -------------------------------------------------------------------------------- /examples/ams/container-show-log/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "flag" 23 | "fmt" 24 | "io" 25 | "io/ioutil" 26 | "log" 27 | "net/http" 28 | "os" 29 | 30 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 31 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 32 | ) 33 | 34 | type containerLogCmd struct { 35 | common.ConnectionCmd 36 | id string 37 | logName string 38 | } 39 | 40 | func (command *containerLogCmd) Parse() { 41 | flag.StringVar(&command.id, "id", "", "Container id") 42 | flag.StringVar(&command.logName, "log-name", "", "Log name to be fetched from the container") 43 | 44 | command.ConnectionCmd.Parse() 45 | 46 | if len(command.id) == 0 || len(command.logName) == 0 { 47 | flag.Usage() 48 | os.Exit(1) 49 | } 50 | } 51 | 52 | func main() { 53 | cmd := &containerLogCmd{} 54 | cmd.Parse() 55 | c := cmd.NewClient() 56 | 57 | if err := showContainerLog(c, cmd.id, cmd.logName); err != nil { 58 | log.Fatal(err) 59 | } 60 | } 61 | 62 | func showContainerLog(c client.Client, id, logName string) error { 63 | return c.RetrieveContainerLog(id, logName, func(header *http.Header, body io.ReadCloser) error { 64 | content, err := ioutil.ReadAll(body) 65 | if err != nil { 66 | return err 67 | } 68 | fmt.Printf("%s", string(content)) 69 | return nil 70 | }) 71 | } 72 | -------------------------------------------------------------------------------- /pkg/network/port.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package network 20 | 21 | import "net" 22 | 23 | // AllocatePorts asks the kernel for a set of free open ports that are 24 | // not in use. The implementation gurantees that all ports are unique 25 | // but does not give a gurantee that they haven't been taken by the time 26 | // they are actually used. 27 | func AllocatePorts(num int) ([]int, error) { 28 | var listeners []*net.TCPListener 29 | 30 | defer func() { 31 | for _, l := range listeners { 32 | l.Close() 33 | } 34 | }() 35 | 36 | var ports []int 37 | for n := 0; n < num; n++ { 38 | addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0") 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | l, err := net.ListenTCP("tcp", addr) 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | ports = append(ports, l.Addr().(*net.TCPAddr).Port) 49 | listeners = append(listeners, l) 50 | } 51 | 52 | return ports, nil 53 | } 54 | 55 | // AllocatePort asks the kernel for a free open port that is ready to use 56 | func AllocatePort() (int, error) { 57 | addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0") 58 | if err != nil { 59 | return -1, err 60 | } 61 | 62 | l, err := net.ListenTCP("tcp", addr) 63 | if err != nil { 64 | return -1, err 65 | } 66 | defer l.Close() 67 | return l.Addr().(*net.TCPAddr).Port, nil 68 | } 69 | -------------------------------------------------------------------------------- /examples/ams/application-revoke/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | "strconv" 27 | 28 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 29 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 30 | ) 31 | 32 | type appRevokeCmd struct { 33 | common.ConnectionCmd 34 | id string 35 | version string 36 | } 37 | 38 | func (command *appRevokeCmd) Parse() { 39 | flag.StringVar(&command.id, "id", "", "Application id") 40 | flag.StringVar(&command.version, "version", "", "Application version to revoke") 41 | 42 | command.ConnectionCmd.Parse() 43 | 44 | if len(command.id) == 0 || len(command.version) == 0 { 45 | flag.Usage() 46 | os.Exit(1) 47 | } 48 | } 49 | 50 | func main() { 51 | cmd := &appRevokeCmd{} 52 | cmd.Parse() 53 | c := cmd.NewClient() 54 | 55 | version, err := strconv.Atoi(cmd.version) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | 60 | if err := revokeApplicationVersion(c, cmd.id, version); err != nil { 61 | log.Fatal(err) 62 | } 63 | } 64 | 65 | func revokeApplicationVersion(c client.Client, id string, version int) error { 66 | operation, err := c.RevokeApplicationVersion(id, version) 67 | if err != nil { 68 | return err 69 | } 70 | 71 | // Wait for the revoke operation to finish 72 | return operation.Wait(context.Background()) 73 | } 74 | -------------------------------------------------------------------------------- /examples/ams/application-publish/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | "strconv" 27 | 28 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 29 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 30 | ) 31 | 32 | type appPublishCmd struct { 33 | common.ConnectionCmd 34 | id string 35 | version string 36 | } 37 | 38 | func (command *appPublishCmd) Parse() { 39 | flag.StringVar(&command.id, "id", "", "Application id") 40 | flag.StringVar(&command.version, "version", "", "Application version to publish") 41 | 42 | command.ConnectionCmd.Parse() 43 | 44 | if len(command.id) == 0 || len(command.version) == 0 { 45 | flag.Usage() 46 | os.Exit(1) 47 | } 48 | } 49 | 50 | func main() { 51 | cmd := &appPublishCmd{} 52 | cmd.Parse() 53 | c := cmd.NewClient() 54 | 55 | version, err := strconv.Atoi(cmd.version) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | 60 | if err := publishApplicationVersion(c, cmd.id, version); err != nil { 61 | log.Fatal(err) 62 | } 63 | } 64 | 65 | func publishApplicationVersion(c client.Client, id string, version int) error { 66 | operation, err := c.PublishApplicationVersion(id, version) 67 | if err != nil { 68 | return err 69 | } 70 | 71 | // Wait for publish operation to finish 72 | return operation.Wait(context.Background()) 73 | } 74 | -------------------------------------------------------------------------------- /examples/ams/application-update/README.md: -------------------------------------------------------------------------------- 1 | Update Application Example 2 | ========================== 3 | 4 | Demonstrates how to update an existing application using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `id` | Identifier of the application to update | required | 17 | | `package-path` | Path to the application zip or tarball | required | 18 | 19 | The package must be a valid tar.bz2 file with this struture: 20 | 21 | * Application_folder 22 | - manifest.yaml 23 | - app.apk 24 | 25 | Where: 26 | 27 | * `Application_folder` Folder with the same name of the application to install 28 | * `manifest.yaml` contains metadata for the application. Including: 29 | - `name` The desired name for the new application 30 | - `image` The id or name of an existing image. It is used as the base for the application image. 31 | - `instance-type` Size of the machines in terms of memory and CPU to use for the application containers 32 | - `addons` List of addons this application uses 33 | - `extra-data` Any additional data needed by the application, provided in a free format 34 | * `app.apk` The Android installable file for this application. Must have exactly that _app.apk_ name 35 | 36 | 37 | Example of application package content 38 | 39 | clashofclans 40 | ├── app.apk 41 | └── manifest.yaml 42 | 43 | Example of manifest.yaml: 44 | 45 | name: Clash of Clans 46 | image: default 47 | instance-type: a2.3 48 | required_permissions: [] 49 | addons: 50 | - debugger 51 | extra-data: 52 | 53 | 54 | Example: 55 | 56 | application-update -cert=./client.crt -key=./client.key -url=https://:8443 -id=bgutrvm5nof0fqm0894g -package-path=./clashofclans.tar.bz2 57 | 58 | Output: 59 | 60 | empty 61 | 62 | -------------------------------------------------------------------------------- /examples/ams/application-create/README.md: -------------------------------------------------------------------------------- 1 | Create Application Example 2 | ========================== 3 | 4 | Demonstrates how to create a new application using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | | `name` | Name of the addon | required | 17 | | `package-path` | Path to the application zip or tarball | required | 18 | 19 | The package must be a valid tar.bz2 file with this struture: 20 | 21 | * Application_folder 22 | - manifest.yaml 23 | - app.apk 24 | 25 | Where: 26 | 27 | * `Application_folder` Folder with the same name of the application to install 28 | * `manifest.yaml` contains metadata for the application. Including: 29 | - `name` The desired name for the new application 30 | - `image` The id or name of an existing image. It is used as the base for the application image. 31 | - `instance-type` Size of the machines in terms of memory and CPU to use for the application containers 32 | - `addons` List of addons this application uses 33 | - `extra-data` Any additional data needed by the application, provided in a free format 34 | * `app.apk` The Android installable file for this application. Must have exactly that _app.apk_ name 35 | 36 | 37 | Example of application package content 38 | 39 | clashofclans 40 | ├── app.apk 41 | └── manifest.yaml 42 | 43 | Example of manifest.yaml: 44 | 45 | name: Clash of Clans 46 | image: default 47 | instance-type: a2.3 48 | required_permissions: [] 49 | addons: 50 | - debugger 51 | extra-data: 52 | 53 | 54 | Example: 55 | 56 | application-create -cert=./client.crt -key=./client.key -url=https://:8443 -package-path=./clashofclans.tar.bz2 57 | 58 | Output: 59 | 60 | { 61 | "applications": [ 62 | "bgutrvm5nof0fqm0894g" 63 | ] 64 | } 65 | 66 | -------------------------------------------------------------------------------- /examples/ams/application-list/README.md: -------------------------------------------------------------------------------- 1 | List Applications Example 2 | ========================= 3 | 4 | Demonstrates how to list the existing applications using AMS SDK 5 | 6 | Parameters 7 | ----- 8 | 9 | You have to provide the following parameters in any order: 10 | 11 | | Name | Description | Attribute | 12 | | --------- |:-------------------- | :--------: | 13 | | `cert` | Path to the file with the client certificate to use to connect to AMS | required | 14 | | `key` | Path to the file with the client key to use to connect to AMS | required | 15 | | `url` | URL of the AMS server | required | 16 | 17 | Example: 18 | 19 | application-list -cert=./client.crt -key=./client.key -url=https://:8443 20 | 21 | Output: 22 | 23 | [ 24 | { 25 | "id": "bgutrvm5nof0fqm0894g", 26 | "name": "clash of clans", 27 | "status_code": 2, 28 | "status": "ready", 29 | "instance_type": "a2.3", 30 | "boot_package": "com.supercell.clashofclans", 31 | "parent_image_id": "bguqesm5nof675ard8b0", 32 | "published": true, 33 | "versions": [ 34 | { 35 | "number": 0, 36 | "parent_image_version": 0, 37 | "status_code": 3, 38 | "status": "active", 39 | "published": true, 40 | "created_at": 1547558410, 41 | "boot_activity": "", 42 | "required_permissions": [ 43 | "android.permission.WRITE_EXTERNAL_STORAGE", 44 | "android.permission.READ_EXTERNAL_STORAGE" 45 | ], 46 | "addons": [], 47 | "extra_data": { 48 | "com.supercell.clashofclans.obb": { 49 | "target": "/data/app/com.supercell.clashofclans-1/lib", 50 | "owner": "", 51 | "permissions": "" 52 | }, 53 | "game-data-folder": { 54 | "target": "/sdcard/Android/data/com.supercell.clashofclans/", 55 | "owner": "", 56 | "permissions": "" 57 | } 58 | } 59 | } 60 | ], 61 | "addons": null, 62 | "created_at": 0, 63 | "immutable": false 64 | } 65 | ] 66 | 67 | -------------------------------------------------------------------------------- /pkg/ams/client/registry.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | api "github.com/anbox-cloud/ams-sdk/api/ams" 23 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/client" 24 | ) 25 | 26 | // ListApplicationsFromRegistry returns a list of all availables applications through the 27 | // registered application registry 28 | func (c *clientImpl) ListApplicationsFromRegistry() ([]api.RegistryApplication, error) { 29 | apps := []api.RegistryApplication{} 30 | _, err := c.QueryStruct("GET", client.APIPath("registry", "applications"), nil, nil, nil, "", &apps) 31 | return apps, err 32 | } 33 | 34 | // PushApplicationToRegistry pushes an application to the configured application registry 35 | func (c *clientImpl) PushApplicationToRegistry(id string) (client.Operation, error) { 36 | op, _, err := c.QueryOperation("POST", client.APIPath("registry", "applications", id, "push"), nil, nil, nil, "") 37 | return op, err 38 | } 39 | 40 | // PullApplicationFromRegistry pulls an application from the configured application registry 41 | func (c *clientImpl) PullApplicationFromRegistry(id string) (client.Operation, error) { 42 | op, _, err := c.QueryOperation("POST", client.APIPath("registry", "applications", id, "pull"), nil, nil, nil, "") 43 | return op, err 44 | } 45 | 46 | // DeleteApplicationFromRegistry deletes an application from the configured application registry 47 | func (c *clientImpl) DeleteApplicationFromRegistry(id string) (client.Operation, error) { 48 | op, _, err := c.QueryOperation("DELETE", client.APIPath("registry", "applications", id), nil, nil, nil, "") 49 | return op, err 50 | } 51 | -------------------------------------------------------------------------------- /pkg/ams/shared/rest/api/oidc.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package api 20 | 21 | // AuthenticationMethod describes the type of an authentication to use with a remote (tls, oidc) 22 | type AuthenticationMethod = string 23 | 24 | const ( 25 | // AuthenticationMethodTLS specifies that the authentication type to be 26 | // used with a remote should be mTLS 27 | AuthenticationMethodTLS AuthenticationMethod = "tls" 28 | // AuthenticationMethodOIDC specifies that the authentication type to be 29 | // used with a remote should be OIDC. 30 | AuthenticationMethodOIDC AuthenticationMethod = "oidc" 31 | ) 32 | 33 | // OIDCResponse represents the OIDC configuration accepted by AMS 34 | // 35 | // swagger:model OIDCResponse 36 | type OIDCResponse struct { 37 | // Issuer URL as configured in AMS 38 | // Example: "https://myauth.auth0.com/" 39 | IssuerURL string `json:"issuer" yaml:"issuer"` 40 | // Required Scope for AMS to work. These scopes should be request by clients 41 | // when performing OIDC based authentication with an Identity Provider. 42 | // Example: ["openid", "email", "profile"] 43 | RequiredScopes []string `json:"required_scopes" yaml:"required_scopes"` 44 | // ClientID to use when using flows that do not require a client_secret on 45 | // identity provider e.g Device flow grant. 46 | // Example: web 47 | ClientID string `json:"client_id,omitempty" yaml:"client_id,omitempty"` 48 | // Audience to use when using flows that do not require a client_secret on 49 | // identity provider e.g Device flow grant. 50 | // Example: http://ams.example.com 51 | Audience string `json:"audience,omitempty" yaml:"audience,omitempty"` 52 | } 53 | -------------------------------------------------------------------------------- /pkg/ams/shared/rest/client/certificates.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | "bytes" 23 | "encoding/json" 24 | "fmt" 25 | 26 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/api" 27 | ) 28 | 29 | type certificates struct { 30 | Client 31 | } 32 | 33 | // UpgradeToCertificatesClient wraps generic client to implement Operations interface operations 34 | func UpgradeToCertificatesClient(c Client) Certificates { 35 | return &certificates{c} 36 | } 37 | 38 | func (c *certificates) ListCertificates() ([]api.Certificate, error) { 39 | certs := []api.Certificate{} 40 | _, err := c.QueryStruct("GET", APIPath("certificates"), nil, nil, nil, "", &certs) 41 | return certs, err 42 | } 43 | 44 | func (c *certificates) AddCertificate(base64PublicKey, trustPassword string) error { 45 | req := api.CertificatesPost{ 46 | Certificate: base64PublicKey, 47 | TrustPassword: trustPassword, 48 | } 49 | 50 | b, err := json.Marshal(req) 51 | if err != nil { 52 | return fmt.Errorf("Could not marshal request body: %v", err) 53 | } 54 | 55 | _, _, err = c.CallAPI("POST", APIPath("certificates"), nil, nil, bytes.NewReader(b), "") 56 | return err 57 | } 58 | 59 | func (c *certificates) RetrieveCertificate(fingerprint string) (*api.Certificate, error) { 60 | cert := &api.Certificate{} 61 | _, err := c.QueryStruct("GET", APIPath("certificates", fingerprint), nil, nil, nil, "", &cert) 62 | return cert, err 63 | } 64 | 65 | func (c *certificates) DeleteCertificate(fingerprint string) (Operation, error) { 66 | op, _, err := c.QueryOperation("DELETE", APIPath("certificates", fingerprint), nil, nil, nil, "") 67 | return op, err 68 | } 69 | -------------------------------------------------------------------------------- /pkg/ams/shared/ask.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package shared 20 | 21 | import ( 22 | "bufio" 23 | "fmt" 24 | "os" 25 | "strings" 26 | 27 | "golang.org/x/crypto/ssh/terminal" 28 | ) 29 | 30 | var stdin = bufio.NewReader(os.Stdin) 31 | 32 | // AskForBool asks a question and expect a yes/no answer. 33 | func AskForBool(question string, defaultAnswer string) bool { 34 | for { 35 | answer := askQuestion(question, defaultAnswer) 36 | 37 | if StringInSlice(strings.ToLower(answer), []string{"yes", "y"}) { 38 | return true 39 | } else if StringInSlice(strings.ToLower(answer), []string{"no", "n"}) { 40 | return false 41 | } 42 | 43 | invalidInput() 44 | } 45 | } 46 | 47 | // AskForPassword asks the user to enter a password. 48 | func AskForPassword(question string) string { 49 | fmt.Print(question) 50 | pwd, _ := terminal.ReadPassword(0) 51 | fmt.Println("") 52 | 53 | return string(pwd) 54 | } 55 | 56 | // Ask a question on the output stream and read the answer from the input stream 57 | func askQuestion(question, defaultAnswer string) string { 58 | fmt.Print(question) 59 | 60 | return readAnswer(defaultAnswer) 61 | } 62 | 63 | // Read the user's answer from the input stream, trimming newline and providing a default. 64 | func readAnswer(defaultAnswer string) string { 65 | answer, _ := stdin.ReadString('\n') 66 | answer = strings.TrimSuffix(answer, "\n") 67 | answer = strings.TrimSpace(answer) 68 | if answer == "" { 69 | answer = defaultAnswer 70 | } 71 | 72 | return answer 73 | } 74 | 75 | // Print an invalid input message on the error stream 76 | func invalidInput() { 77 | fmt.Fprint(os.Stderr, "Invalid input, try again.\n\n") 78 | } 79 | -------------------------------------------------------------------------------- /examples/ams/addon-show/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "flag" 23 | "log" 24 | "os" 25 | "time" 26 | 27 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 28 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 29 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared" 30 | ) 31 | 32 | type addonShowCmd struct { 33 | common.ConnectionCmd 34 | name string 35 | } 36 | 37 | func (command *addonShowCmd) Parse() { 38 | flag.StringVar(&command.name, "name", "", "Name of the addon") 39 | command.ConnectionCmd.Parse() 40 | 41 | if len(command.name) == 0 { 42 | flag.Usage() 43 | os.Exit(1) 44 | } 45 | } 46 | 47 | func main() { 48 | cmd := &addonShowCmd{} 49 | cmd.Parse() 50 | c := cmd.NewClient() 51 | 52 | if err := showAddon(c, cmd.name); err != nil { 53 | log.Fatal(err) 54 | } 55 | } 56 | 57 | func showAddon(c client.Client, name string) error { 58 | addon, _, err := c.RetrieveAddon(name) 59 | if err != nil { 60 | return err 61 | } 62 | 63 | type addonVersion struct { 64 | Size string `yaml:"size" json:"size"` 65 | CreatedAt string `yaml:"created-at" json:"created-at"` 66 | } 67 | 68 | var outputData struct { 69 | Name string `yaml:"name" json:"name"` 70 | Versions map[int]addonVersion `yaml:"versions" json:"versions"` 71 | } 72 | outputData.Name = addon.Name 73 | outputData.Versions = make(map[int]addonVersion) 74 | 75 | for _, v := range addon.Versions { 76 | t := time.Unix(v.CreatedAt, 0) 77 | outputData.Versions[v.Number] = addonVersion{ 78 | Size: shared.GetByteSizeString(v.Size, 2), 79 | CreatedAt: t.String(), 80 | } 81 | } 82 | 83 | return common.DumpData(outputData) 84 | } 85 | -------------------------------------------------------------------------------- /examples/ams/addon-delete/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | "strconv" 27 | 28 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 29 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 30 | ) 31 | 32 | type addonDeleteCmd struct { 33 | common.ConnectionCmd 34 | name string 35 | version string 36 | } 37 | 38 | func (command *addonDeleteCmd) Parse() { 39 | flag.StringVar(&command.name, "name", "", "Name of the addon") 40 | flag.StringVar(&command.version, "version", "", "Version of the addon") 41 | 42 | command.ConnectionCmd.Parse() 43 | 44 | if len(command.name) == 0 { 45 | flag.Usage() 46 | os.Exit(1) 47 | } 48 | } 49 | 50 | func main() { 51 | cmd := &addonDeleteCmd{} 52 | cmd.Parse() 53 | c := cmd.NewClient() 54 | 55 | var version int 56 | var err error 57 | if len(cmd.version) > 0 { 58 | version, err = strconv.Atoi(cmd.version) 59 | if err == nil { 60 | err = deleteAddonVersion(c, cmd.name, version) 61 | } 62 | } else { 63 | err = deleteAddon(c, cmd.name) 64 | } 65 | 66 | if err != nil { 67 | log.Fatal(err) 68 | } 69 | } 70 | 71 | func deleteAddon(c client.Client, name string) error { 72 | operation, err := c.DeleteAddon(name) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | // Wait for delete operation to finish 78 | return operation.Wait(context.Background()) 79 | } 80 | 81 | func deleteAddonVersion(c client.Client, name string, version int) error { 82 | operation, err := c.DeleteAddonVersion(name, version) 83 | if err != nil { 84 | return err 85 | } 86 | 87 | // Wait for delete operation to finish 88 | return operation.Wait(context.Background()) 89 | } 90 | -------------------------------------------------------------------------------- /pkg/ams/client/certificates.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | "bytes" 23 | "context" 24 | "encoding/json" 25 | "fmt" 26 | 27 | errs "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/errors" 28 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/api" 29 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/client" 30 | ) 31 | 32 | // ListCertificates lists all available certificates the AMS service knows about 33 | func (c *clientImpl) ListCertificates() ([]api.Certificate, error) { 34 | params := client.QueryParams{ 35 | "recursion": "1", 36 | } 37 | var certs []api.Certificate 38 | _, err := c.QueryStruct("GET", client.APIPath("certificates"), params, nil, nil, "", &certs) 39 | return certs, err 40 | } 41 | 42 | // AddCertificate adds a new certificate to the service trust store 43 | func (c *clientImpl) AddCertificate(details *api.CertificatesPost) (*api.Response, error) { 44 | if len(details.Certificate) == 0 { 45 | return nil, fmt.Errorf("No certificate specified") 46 | } 47 | 48 | b, err := json.Marshal(details) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | resp, _, err := c.CallAPI("POST", client.APIPath("certificates"), nil, nil, bytes.NewReader(b), "") 54 | return resp, err 55 | } 56 | 57 | // DeleteCertificate deletes an existing trusted certificate by its fingerprint 58 | func (c *clientImpl) DeleteCertificate(fingerprint string) error { 59 | if len(fingerprint) == 0 { 60 | return errs.NewInvalidArgument("fingerprint") 61 | } 62 | op, _, err := c.QueryOperation("DELETE", client.APIPath("certificates", fingerprint), nil, nil, nil, "") 63 | if err != nil { 64 | return err 65 | } 66 | return op.Wait(context.Background()) 67 | } 68 | -------------------------------------------------------------------------------- /pkg/ams/shared/hash.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package shared 20 | 21 | import ( 22 | "bytes" 23 | "crypto/rand" 24 | "encoding/hex" 25 | "errors" 26 | "io" 27 | 28 | "golang.org/x/crypto/scrypt" 29 | ) 30 | 31 | // Hash creates a hash of 192 chars from a value. 32 | // A random salt of 32 bytes is used. The result is that salt plus the 33 | // hashed result encoded to hexadecimal 34 | func Hash(value string) (string, error) { 35 | // Nothing to do on unset 36 | if len(value) == 0 { 37 | return value, nil 38 | } 39 | 40 | buf := make([]byte, 32) 41 | // Generate a random salt of 32 bytes 42 | _, err := io.ReadFull(rand.Reader, buf) 43 | if err != nil { 44 | return "", err 45 | } 46 | 47 | hash, err := scrypt.Key([]byte(value), buf, 1<<14, 8, 1, 64) 48 | if err != nil { 49 | return "", err 50 | } 51 | 52 | // buf = salt + hash 53 | buf = append(buf, hash...) 54 | value = hex.EncodeToString(buf) 55 | 56 | return value, nil 57 | } 58 | 59 | // ValidateHash decodes hexadecimal hashed, extracts the salt from the first 32 bytes and 60 | // hashes the value param using that salt. The result of that hash function should 61 | // match the rest of the decoded secret buffer. Otherwise the validation fails 62 | func ValidateHash(hashed, value string) error { 63 | if len(hashed) == 0 { 64 | return errors.New("No password is set") 65 | } 66 | 67 | buff, err := hex.DecodeString(hashed) 68 | if err != nil { 69 | return err 70 | } 71 | 72 | salt := buff[0:32] 73 | hash, err := scrypt.Key([]byte(value), salt, 1<<14, 8, 1, 64) 74 | if err != nil { 75 | return err 76 | } 77 | 78 | if !bytes.Equal(hash, buff[32:]) { 79 | return errors.New("Bad password provided") 80 | } 81 | 82 | return nil 83 | } 84 | -------------------------------------------------------------------------------- /examples/ams/application-delete/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | "strconv" 27 | 28 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 29 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 30 | ) 31 | 32 | type appDeleteCmd struct { 33 | common.ConnectionCmd 34 | id string 35 | version string 36 | } 37 | 38 | func (command *appDeleteCmd) Parse() { 39 | flag.StringVar(&command.id, "id", "", "Application id") 40 | flag.StringVar(&command.version, "version", "", "Application id") 41 | 42 | command.ConnectionCmd.Parse() 43 | 44 | if len(command.id) == 0 { 45 | flag.Usage() 46 | os.Exit(1) 47 | } 48 | } 49 | 50 | func main() { 51 | cmd := &appDeleteCmd{} 52 | cmd.Parse() 53 | c := cmd.NewClient() 54 | 55 | var version int 56 | var err error 57 | if len(cmd.version) > 0 { 58 | version, err = strconv.Atoi(cmd.version) 59 | if err == nil { 60 | err = deleteApplicationVersion(c, cmd.id, version) 61 | } 62 | } else { 63 | err = deleteApplication(c, cmd.id) 64 | } 65 | 66 | if err != nil { 67 | log.Fatal(err) 68 | } 69 | } 70 | 71 | func deleteApplication(c client.Client, id string) error { 72 | operation, err := c.DeleteApplicationByID(id, false) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | // Wait for delete operation to finish 78 | return operation.Wait(context.Background()) 79 | } 80 | 81 | func deleteApplicationVersion(c client.Client, id string, version int) error { 82 | operation, err := c.DeleteApplicationVersion(id, version, false) 83 | if err != nil { 84 | return err 85 | } 86 | 87 | // Wait for delete operation to finish 88 | return operation.Wait(context.Background()) 89 | } 90 | -------------------------------------------------------------------------------- /examples/ams/addon-add/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | 27 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 28 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 29 | ) 30 | 31 | type addonAddCmd struct { 32 | common.ConnectionCmd 33 | name string 34 | addonPath string 35 | } 36 | 37 | func (command *addonAddCmd) Parse() { 38 | flag.StringVar(&command.name, "name", "", "Name of the addon") 39 | flag.StringVar(&command.addonPath, "path", "", "Path to the addon package") 40 | 41 | command.ConnectionCmd.Parse() 42 | 43 | if len(command.name) == 0 || len(command.addonPath) == 0 { 44 | flag.Usage() 45 | os.Exit(1) 46 | } 47 | } 48 | 49 | func main() { 50 | cmd := &addonAddCmd{} 51 | cmd.Parse() 52 | c := cmd.NewClient() 53 | 54 | if _, err := os.Stat(cmd.addonPath); err != nil { 55 | if os.IsNotExist(err) { 56 | log.Fatal("Specified payload does not exist") 57 | } 58 | log.Fatal(err) 59 | } 60 | 61 | if err := addAddon(c, cmd.name, cmd.addonPath); err != nil { 62 | log.Fatal(err) 63 | } 64 | } 65 | 66 | func addAddon(c client.Client, name, sourcePath string) error { 67 | // We can read from this channel the number of bytes already 68 | // sent to the server. This is useful to identify when all the 69 | // payload has been sent. 70 | sentBytesCh := make(chan float64) 71 | 72 | operation, err := c.AddAddon(name, sourcePath, sentBytesCh) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | // Wait for add operation to finish 78 | err = operation.Wait(context.Background()) 79 | if err != nil { 80 | return err 81 | } 82 | 83 | common.PrintCreated(operation.Get().Resources) 84 | return nil 85 | } 86 | -------------------------------------------------------------------------------- /examples/ams/image-add/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | 27 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 28 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 29 | ) 30 | 31 | type imageAddCmd struct { 32 | common.ConnectionCmd 33 | name string 34 | packagePath string 35 | } 36 | 37 | func (command *imageAddCmd) Parse() { 38 | flag.StringVar(&command.name, "name", "", "Name of the image") 39 | flag.StringVar(&command.packagePath, "package-path", "", "Path to the image package") 40 | 41 | command.ConnectionCmd.Parse() 42 | 43 | if len(command.name) == 0 || len(command.packagePath) == 0 { 44 | flag.Usage() 45 | os.Exit(1) 46 | } 47 | } 48 | 49 | func main() { 50 | cmd := &imageAddCmd{} 51 | cmd.Parse() 52 | c := cmd.NewClient() 53 | 54 | if _, err := os.Stat(cmd.packagePath); err != nil { 55 | if os.IsNotExist(err) { 56 | log.Fatal("Specified iamge does not exist") 57 | } 58 | log.Fatal(err) 59 | } 60 | 61 | if err := addImage(c, cmd.name, cmd.packagePath); err != nil { 62 | log.Fatal(err) 63 | } 64 | } 65 | 66 | func addImage(c client.Client, name, sourcePath string) error { 67 | // We can read from this channel the number of bytes already 68 | // sent to the server. This is useful to identify when all the 69 | // payload has been sent. 70 | sentBytesCh := make(chan float64) 71 | 72 | operation, err := c.AddImage(name, sourcePath, false, sentBytesCh) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | // Wait for add operation to finish 78 | if err := operation.Wait(context.Background()); err != nil { 79 | return err 80 | } 81 | 82 | common.PrintCreated(operation.Get().Resources) 83 | return nil 84 | } 85 | -------------------------------------------------------------------------------- /examples/ams/addon-update/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | 27 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 28 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 29 | ) 30 | 31 | type addonUpdateCmd struct { 32 | common.ConnectionCmd 33 | name string 34 | addonPath string 35 | } 36 | 37 | func (command *addonUpdateCmd) Parse() { 38 | flag.StringVar(&command.name, "name", "", "Name of the addon") 39 | flag.StringVar(&command.addonPath, "path", "", "Path to the addon package") 40 | 41 | command.ConnectionCmd.Parse() 42 | 43 | if len(command.name) == 0 || len(command.addonPath) == 0 { 44 | flag.Usage() 45 | os.Exit(1) 46 | } 47 | } 48 | 49 | func main() { 50 | cmd := &addonUpdateCmd{} 51 | cmd.Parse() 52 | c := cmd.NewClient() 53 | 54 | if _, err := os.Stat(cmd.addonPath); err != nil { 55 | if os.IsNotExist(err) { 56 | log.Fatal("Specified payload does not exist") 57 | } 58 | log.Fatal(err) 59 | } 60 | 61 | if err := updateAddon(c, cmd.name, cmd.addonPath); err != nil { 62 | log.Fatal(err) 63 | } 64 | } 65 | 66 | func updateAddon(c client.Client, name, sourcePath string) error { 67 | // We can read from this channel the number of bytes already 68 | // sent to the server. This is useful to identify when all the 69 | // payload has been sent. 70 | sentBytesCh := make(chan float64) 71 | 72 | operation, err := c.UpdateAddon(name, sourcePath, sentBytesCh) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | // Wait for the update operation to finish 78 | err = operation.Wait(context.Background()) 79 | if err != nil { 80 | return err 81 | } 82 | 83 | common.PrintCreated(operation.Get().Resources) 84 | return nil 85 | } 86 | -------------------------------------------------------------------------------- /examples/ams/application-update/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | 27 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 28 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 29 | ) 30 | 31 | type appUpdateCmd struct { 32 | common.ConnectionCmd 33 | id string 34 | packagePath string 35 | } 36 | 37 | func (command *appUpdateCmd) Parse() { 38 | flag.StringVar(&command.id, "id", "", "Application id") 39 | flag.StringVar(&command.packagePath, "package-path", "", "Path to the application package") 40 | 41 | command.ConnectionCmd.Parse() 42 | 43 | if len(command.id) == 0 || len(command.packagePath) == 0 { 44 | flag.Usage() 45 | os.Exit(1) 46 | } 47 | } 48 | 49 | func main() { 50 | cmd := &appUpdateCmd{} 51 | cmd.Parse() 52 | c := cmd.NewClient() 53 | 54 | if err := updateApplication(c, cmd.id, cmd.packagePath); err != nil { 55 | log.Fatal(err) 56 | } 57 | } 58 | 59 | func updateApplication(c client.Client, id, packagePath string) error { 60 | // We can read from this channel the number of bytes already 61 | // sent to the server. This is useful to identify when all the 62 | // payload has been sent. 63 | sentBytesCh := make(chan float64) 64 | 65 | operation, err := c.UpdateApplicationWithPackage(id, packagePath, sentBytesCh) 66 | if err != nil { 67 | return err 68 | } 69 | 70 | // Simply print sent bytes to stdout 71 | closeCh := make(chan struct{}) 72 | go func() { 73 | for { 74 | select { 75 | case n := <-sentBytesCh: 76 | log.Printf("Sent: %v", n) 77 | case <-closeCh: 78 | return 79 | } 80 | } 81 | }() 82 | 83 | // Wait for update operation to finish 84 | return operation.Wait(context.Background()) 85 | } 86 | -------------------------------------------------------------------------------- /examples/ams/image-update/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | 27 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 28 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 29 | ) 30 | 31 | type imageUpdateCmd struct { 32 | common.ConnectionCmd 33 | name string 34 | packagePath string 35 | } 36 | 37 | func (command *imageUpdateCmd) Parse() { 38 | flag.StringVar(&command.name, "name", "", "Name of the image") 39 | flag.StringVar(&command.packagePath, "package-path", "", "Path to the image package") 40 | 41 | command.ConnectionCmd.Parse() 42 | 43 | if len(command.name) == 0 || len(command.packagePath) == 0 { 44 | flag.Usage() 45 | os.Exit(1) 46 | } 47 | } 48 | 49 | func main() { 50 | cmd := &imageUpdateCmd{} 51 | cmd.Parse() 52 | c := cmd.NewClient() 53 | 54 | if _, err := os.Stat(cmd.packagePath); err != nil { 55 | if os.IsNotExist(err) { 56 | log.Fatal("Specified image does not exist") 57 | } 58 | log.Fatal(err) 59 | } 60 | 61 | if err := updateImage(c, cmd.name, cmd.packagePath); err != nil { 62 | log.Fatal(err) 63 | } 64 | } 65 | 66 | func updateImage(c client.Client, name, imagePath string) error { 67 | // We can read from this channel the number of bytes already 68 | // sent to the server. This is useful to identify when all the 69 | // payload has been sent. 70 | sentBytesCh := make(chan float64) 71 | 72 | operation, err := c.UpdateImage(name, imagePath, sentBytesCh) 73 | if err != nil { 74 | log.Fatal(err) 75 | } 76 | 77 | // Wait for update operation to finish 78 | if err := operation.Wait(context.Background()); err != nil { 79 | log.Fatal(err) 80 | } 81 | 82 | common.PrintCreated(operation.Get().Resources) 83 | return nil 84 | } 85 | -------------------------------------------------------------------------------- /examples/ams/image-delete/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | "strconv" 27 | 28 | api "github.com/anbox-cloud/ams-sdk/api/ams" 29 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 30 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 31 | ) 32 | 33 | type imageDeleteCmd struct { 34 | common.ConnectionCmd 35 | id string 36 | version string 37 | } 38 | 39 | func (command *imageDeleteCmd) Parse() { 40 | flag.StringVar(&command.id, "id", "", "ID or name of the image") 41 | flag.StringVar(&command.version, "version", "", "Version of the image to delete") 42 | 43 | command.ConnectionCmd.Parse() 44 | 45 | if len(command.id) == 0 { 46 | flag.Usage() 47 | os.Exit(1) 48 | } 49 | } 50 | 51 | func main() { 52 | cmd := &imageDeleteCmd{} 53 | cmd.Parse() 54 | c := cmd.NewClient() 55 | 56 | var version int 57 | var err error 58 | if len(cmd.version) > 0 { 59 | version, err = strconv.Atoi(cmd.version) 60 | if err == nil { 61 | err = deleteImageVersion(c, cmd.id, version) 62 | } 63 | } else { 64 | err = deleteImage(c, cmd.id) 65 | } 66 | 67 | if err != nil { 68 | log.Fatal(err) 69 | } 70 | } 71 | 72 | func deleteImage(c client.Client, id string) error { 73 | operation, err := c.DeleteImageByIDOrName(id, false, api.ImageTypeAny) 74 | if err != nil { 75 | return err 76 | } 77 | 78 | // Wait for delete operation to finish 79 | return operation.Wait(context.Background()) 80 | } 81 | 82 | func deleteImageVersion(c client.Client, id string, version int) error { 83 | operation, err := c.DeleteImageVersion(id, version) 84 | if err != nil { 85 | return err 86 | } 87 | 88 | // Wait for delete operation to finish 89 | return operation.Wait(context.Background()) 90 | } 91 | -------------------------------------------------------------------------------- /examples/ams/application-create/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | 27 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 28 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 29 | ) 30 | 31 | type appCreateCmd struct { 32 | common.ConnectionCmd 33 | packagePath string 34 | } 35 | 36 | func (command *appCreateCmd) Parse() { 37 | flag.StringVar(&command.packagePath, "package-path", "", "Path to the application package") 38 | 39 | command.ConnectionCmd.Parse() 40 | 41 | if len(command.packagePath) == 0 { 42 | flag.Usage() 43 | os.Exit(1) 44 | } 45 | } 46 | 47 | func main() { 48 | cmd := &appCreateCmd{} 49 | cmd.Parse() 50 | c := cmd.NewClient() 51 | 52 | if err := createApplication(c, cmd.packagePath); err != nil { 53 | log.Fatal(err) 54 | } 55 | } 56 | 57 | func createApplication(c client.Client, packagePath string) error { 58 | // We can read from this channel the number of bytes already 59 | // sent to the server. This is useful to identify when all the 60 | // payload has been sent. 61 | sentBytesCh := make(chan float64) 62 | closeCh := make(chan struct{}) 63 | 64 | go func() { 65 | for { 66 | select { 67 | case n := <-sentBytesCh: 68 | // Simply print sent bytes to stdout 69 | log.Printf("Sent: %v", n) 70 | case <-closeCh: 71 | return 72 | } 73 | } 74 | }() 75 | 76 | operation, err := c.CreateApplication(packagePath, sentBytesCh) 77 | if err != nil { 78 | return err 79 | } 80 | 81 | // Wait for create operation to finish 82 | if err := operation.Wait(context.Background()); err != nil { 83 | return err 84 | } 85 | 86 | // Print to stdout the generated resources path 87 | common.PrintCreated(operation.Get().Resources) 88 | return nil 89 | } 90 | -------------------------------------------------------------------------------- /api/ams/registry.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package api 20 | 21 | // RegistryApplicationHooks describes the fields used to configure the hooks of an application 22 | type RegistryApplicationHooks struct { 23 | Timeout string `json:"timeout" yaml:"timeout"` 24 | } 25 | 26 | // RegistryApplicationBootstrap describes the fields used to configure the application bootstrap 27 | type RegistryApplicationBootstrap struct { 28 | Keep []string `json:"keep" yaml:"keep"` 29 | } 30 | 31 | // RegistryApplicationVersion describes a version of an application available 32 | // in the registry 33 | type RegistryApplicationVersion struct { 34 | BootActivity string `json:"boot_activity" yaml:"boot_activity"` 35 | Features []string `json:"features" yaml:"features"` 36 | Hooks RegistryApplicationHooks `json:"hooks" yaml:"hooks"` 37 | Bootstrap RegistryApplicationBootstrap `json:"bootstrap" yaml:"bootstrap"` 38 | VideoEncoder string `json:"video_encoder" yaml:"video_encoder"` 39 | } 40 | 41 | // RegistryApplication describes a single application available in the registry 42 | // 43 | // swagger:model 44 | type RegistryApplication struct { 45 | Name string `json:"name" yaml:"name"` 46 | Architectures []string `json:"architectures" yaml:"architectures"` 47 | BootPackage string `json:"boot_package" yaml:"boot_package"` 48 | InstanceType string `json:"instance_type" yaml:"instance_type"` 49 | Tags []string `json:"tags" yaml:"tags"` 50 | Versions map[int]*RegistryApplicationVersion `json:"versions" yaml:"versions"` 51 | VM bool `json:"vm" yaml:"vm"` 52 | } 53 | -------------------------------------------------------------------------------- /pkg/ams/shared/reverter.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package shared 20 | 21 | import ( 22 | "context" 23 | "log" 24 | "time" 25 | ) 26 | 27 | const ( 28 | fullRevertTimeout = time.Second * 5 29 | ) 30 | 31 | // RevertFunc describes a function used to revert an operation 32 | type RevertFunc func(ctx context.Context) error 33 | 34 | // Reverter provides functionality to automatically revert a set of executed operations. It 35 | // can be used this way: 36 | // 37 | // r := shared.NewReverter() 38 | // defer r.Finish() 39 | // 40 | // doOperation() 41 | // 42 | // r.Add(func(ctx context.Context) error { 43 | // revertOperation() 44 | // return nil 45 | // }) 46 | // 47 | // if err := doOtherOperation(); err != nil { 48 | // return err 49 | // } 50 | // 51 | // r.Defuse() 52 | type Reverter struct { 53 | needRevert bool 54 | reverters []RevertFunc 55 | } 56 | 57 | // Add adds a new revert function to the reverter which will be called when Finish() is 58 | // called unless the reverter gets defused. 59 | func (r *Reverter) Add(f ...RevertFunc) { 60 | r.reverters = append(r.reverters, f...) 61 | } 62 | 63 | // Defuse defuses the reverter. If defused none of the added revert functions will be 64 | // called when Finish() is invoked. 65 | func (r *Reverter) Defuse() { 66 | r.needRevert = false 67 | } 68 | 69 | // Finish invokes all added revert functions if the reverter was not defused. 70 | func (r *Reverter) Finish() { 71 | if !r.needRevert { 72 | return 73 | } 74 | ctx, cancel := context.WithTimeout(context.Background(), fullRevertTimeout) 75 | defer cancel() 76 | // Walk in reverse order through our revertes and call them all 77 | for n := range r.reverters { 78 | revert := r.reverters[len(r.reverters)-n-1] 79 | if err := revert(ctx); err != nil { 80 | log.Printf("Failed to revert: %v", err) 81 | } 82 | } 83 | } 84 | 85 | // NewReverter constructs a new reverter. 86 | func NewReverter() *Reverter { 87 | return &Reverter{needRevert: true} 88 | } 89 | -------------------------------------------------------------------------------- /api/ams/shares.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package api 20 | 21 | // InstanceSharesPost contains information required to create a share for an instance 22 | type InstanceSharesPost struct { 23 | // Type is the type of the session to be shared 24 | Type string `json:"type" example:"adb"` 25 | // Description is the user provided description for the share to be created 26 | Description string `json:"description" example:"instance shared with john"` 27 | // ExpiryAt specifies the exact expiration time for the share. 28 | // The value is a Unix timestamp (UTC) indicating when the share will expire. 29 | ExpiryAt *int64 `json:"expiry_at" example:"1610645117"` 30 | } 31 | 32 | // InstanceSharesPostResponse is returned when sharing an instance 33 | // 34 | // swagger:model 35 | type InstanceSharesPostResponse struct { 36 | Response 37 | Metadata InstanceSharesPostResponseData `json:"metadata"` 38 | } 39 | 40 | // InstanceSharesPostResponseData contains the share URL 41 | type InstanceSharesPostResponseData struct { 42 | // ID of the share 43 | ID string `json:"id" example:"ctigqirc209urni862a0"` 44 | // Type of the share 45 | Type string `json:"type" example:"adb"` 46 | // URL is the endpoint to reach to start the WebRTC signaling process 47 | URL string `json:"url" example:"https://api.example.com/1.0/sessions/foo/connect?token=bar"` 48 | // ExpiryAt specifies the exact expiration time for the share 49 | ExpiryAt int64 `json:"expiry_at" example:"1610645117"` 50 | } 51 | 52 | // InstanceSharePatch contains information required to update a share 53 | type InstanceSharePatch struct { 54 | // Description is the user provided description for the share to be created 55 | Description *string `json:"description,omitempty" example:"instance shared with john"` 56 | // ExpiryAt specifies the exact expiration time for the share. 57 | // The value is a Unix timestamp (UTC) indicating when the share will expire. 58 | ExpiryAt *int64 `json:"expiry_at,omitempty" example:"1610645117"` 59 | } 60 | -------------------------------------------------------------------------------- /examples/ams/node-add/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "flag" 24 | "log" 25 | "os" 26 | 27 | api "github.com/anbox-cloud/ams-sdk/api/ams" 28 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 29 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 30 | ) 31 | 32 | type nodeAddCmd struct { 33 | common.ConnectionCmd 34 | name string 35 | address string 36 | trustPassword string 37 | storageDevice string 38 | networkBridgeMTU int 39 | } 40 | 41 | func (command *nodeAddCmd) Parse() { 42 | flag.StringVar(&command.name, "name", "", "Name of the node") 43 | flag.StringVar(&command.address, "address", "", "Address where the node is accessible") 44 | flag.StringVar(&command.trustPassword, "trust-password", "", "Trust password for the remote LXD node") 45 | flag.StringVar(&command.storageDevice, "storage-device", "", "Storage device LXD node should use") 46 | flag.IntVar(&command.networkBridgeMTU, "network-bridge-mtu", 1500, "MTU of the network bridge configured for LXD") 47 | 48 | command.ConnectionCmd.Parse() 49 | 50 | if len(command.name) == 0 || len(command.address) == 0 { 51 | flag.Usage() 52 | os.Exit(1) 53 | } 54 | } 55 | 56 | func main() { 57 | cmd := &nodeAddCmd{} 58 | cmd.Parse() 59 | c := cmd.NewClient() 60 | 61 | node := &api.NodesPost{ 62 | Name: cmd.name, 63 | TrustPassword: cmd.trustPassword, 64 | Address: cmd.address, 65 | StorageDevice: cmd.storageDevice, 66 | NetworkBridgeMTU: cmd.networkBridgeMTU, 67 | } 68 | 69 | if err := addNode(c, node); err != nil { 70 | log.Fatal(err) 71 | } 72 | } 73 | 74 | func addNode(c client.Client, node *api.NodesPost) error { 75 | operation, err := c.AddNode(node) 76 | if err != nil { 77 | return err 78 | } 79 | 80 | // Wait for add operation to finish 81 | err = operation.Wait(context.Background()) 82 | if err != nil { 83 | return err 84 | } 85 | 86 | common.PrintCreated(operation.Get().Resources) 87 | return nil 88 | } 89 | -------------------------------------------------------------------------------- /examples/ams/image-show/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "flag" 23 | "log" 24 | "os" 25 | "time" 26 | 27 | api "github.com/anbox-cloud/ams-sdk/api/ams" 28 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 29 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 30 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared" 31 | ) 32 | 33 | type imageShowCmd struct { 34 | common.ConnectionCmd 35 | id string 36 | } 37 | 38 | func (command *imageShowCmd) Parse() { 39 | flag.StringVar(&command.id, "id", "", "Id or name of image") 40 | 41 | command.ConnectionCmd.Parse() 42 | 43 | if len(command.id) == 0 { 44 | flag.Usage() 45 | os.Exit(1) 46 | } 47 | } 48 | 49 | func main() { 50 | cmd := &imageShowCmd{} 51 | cmd.Parse() 52 | c := cmd.NewClient() 53 | 54 | if err := showImage(c, cmd.id); err != nil { 55 | log.Fatal(err) 56 | } 57 | } 58 | 59 | func showImage(c client.Client, id string) error { 60 | image, _, err := c.RetrieveImageByIDOrName(id, api.ImageTypeAny) 61 | if err != nil { 62 | return err 63 | } 64 | 65 | type imageVersion struct { 66 | Size string `yaml:"size" json:"size"` 67 | CreatedAt string `yaml:"created-at" json:"created-at"` 68 | Status string `yaml:"status" json:"status"` 69 | } 70 | 71 | var outputData struct { 72 | ID string `yaml:"id" json:"id"` 73 | Name string `yaml:"name" json:"name"` 74 | Status string `yaml:"status" json:"status"` 75 | Versions map[int]imageVersion `yaml:"versions" json:"versions"` 76 | } 77 | outputData.ID = image.ID 78 | outputData.Name = image.Name 79 | outputData.Status = image.Status 80 | outputData.Versions = make(map[int]imageVersion) 81 | 82 | for _, v := range image.Versions { 83 | t := time.Unix(v.CreatedAt, 0) 84 | outputData.Versions[v.Number] = imageVersion{ 85 | Size: shared.GetByteSizeString(v.Size, 2), 86 | CreatedAt: t.String(), 87 | Status: v.Status, 88 | } 89 | } 90 | 91 | return common.DumpData(outputData) 92 | } 93 | -------------------------------------------------------------------------------- /pkg/ams/shared/rest/client/websocket.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | "errors" 23 | "fmt" 24 | "net/http" 25 | "time" 26 | 27 | "github.com/gorilla/websocket" 28 | ) 29 | 30 | func (c *client) Websocket(resource string) (*websocket.Conn, error) { 31 | return c.dialWebsocket(c.composeWebsocketPath(resource)) 32 | } 33 | 34 | // composeWebsocketPath returns websocket url related with rest client one 35 | func (c *client) composeWebsocketPath(path string) string { 36 | host := c.serviceURL.Host 37 | 38 | scheme := "ws" 39 | if c.serviceURL.Scheme == "https" { 40 | scheme = "wss" 41 | } 42 | 43 | return fmt.Sprintf("%s://%s%s", scheme, host, path) 44 | } 45 | 46 | func (c *client) dialWebsocket(url string) (*websocket.Conn, error) { 47 | 48 | var t *http.Transport 49 | switch c := c.Doer.(type) { 50 | case *oidcClient: 51 | t = c.Client.Transport.(*http.Transport) 52 | case *http.Client: 53 | t = c.Transport.(*http.Transport) 54 | default: 55 | return nil, errors.New("Client is not a valid http one") 56 | } 57 | 58 | // Setup a new websocket dialer based on it 59 | dialer := websocket.Dialer{ 60 | NetDial: t.Dial, 61 | TLSClientConfig: t.TLSClientConfig, 62 | Proxy: t.Proxy, 63 | } 64 | 65 | // Set the user agent 66 | headers := http.Header{} 67 | if cl, ok := c.Doer.(*oidcClient); ok { 68 | expiry, err := cl.tokenProvider.GetAccessTokenExpiry() 69 | if err != nil { 70 | return nil, err 71 | } 72 | if expiry.Before(time.Now()) { 73 | if err := cl.tokenProvider.RefreshToken(); err != nil { 74 | return nil, err 75 | } 76 | } 77 | token, err := cl.tokenProvider.GetAccessToken() 78 | if err != nil { 79 | return nil, err 80 | } 81 | headers.Set("Authorization", "Bearer "+token) 82 | } 83 | if c.httpUserAgent != "" { 84 | headers.Set("User-Agent", c.httpUserAgent) 85 | } 86 | 87 | // Establish the connection 88 | conn, _, err := dialer.Dial(url, headers) 89 | if err != nil { 90 | return nil, err 91 | } 92 | 93 | return conn, err 94 | } 95 | -------------------------------------------------------------------------------- /pkg/ams/shared/rest/client/oidc_client.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | "context" 23 | "net/http" 24 | "time" 25 | ) 26 | 27 | type TokenProvider interface { 28 | GetAccessToken() (string, error) 29 | RefreshToken() error 30 | GetAccessTokenExpiry() (time.Time, error) 31 | Authenticate(context.Context) error 32 | } 33 | 34 | // oidcClient is a structure encapsulating an HTTP client, and attaches a token for each request. 35 | type oidcClient struct { 36 | Client *http.Client 37 | tokenProvider TokenProvider 38 | } 39 | 40 | // Do function executes an HTTP request using the oidcClient's http client, and manages authorization by refreshing or authenticating as needed. 41 | // If the request fails with an HTTP Unauthorized status, it attempts to refresh the access token, or perform an OIDC authentication if refresh fails. 42 | func (o *oidcClient) Do(req *http.Request) (*http.Response, error) { 43 | // Pre maturely refresh token in case the token has expired and a refresh 44 | // token is available 45 | expiry, err := o.tokenProvider.GetAccessTokenExpiry() 46 | if err != nil { 47 | return nil, err 48 | } 49 | if expiry.Before(time.Now()) { 50 | if err := o.tokenProvider.RefreshToken(); err != nil { 51 | return nil, err 52 | } 53 | } 54 | 55 | token, err := o.tokenProvider.GetAccessToken() 56 | if err != nil { 57 | return nil, err 58 | } 59 | // Set the new access token in the header. 60 | req.Header.Set("Authorization", "Bearer "+token) 61 | resp, err := o.Client.Do(req) 62 | if err != nil { 63 | return nil, err 64 | } 65 | 66 | // Return immediately if the error is not HTTP status unauthorized. 67 | if resp.StatusCode != http.StatusUnauthorized { 68 | return resp, nil 69 | } 70 | 71 | err = o.tokenProvider.RefreshToken() 72 | if err != nil { 73 | return nil, err 74 | } 75 | token, err = o.tokenProvider.GetAccessToken() 76 | if err != nil { 77 | return nil, err 78 | } 79 | 80 | // Set the new access token in the header. 81 | req.Header.Set("Authorization", "Bearer "+token) 82 | return o.Client.Do(req) 83 | } 84 | -------------------------------------------------------------------------------- /api/ams/network.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package api 20 | 21 | // NetworkProtocol describes a specific network protocol like TCP or UDP a ContainerService can use 22 | type NetworkProtocol string 23 | 24 | const ( 25 | // NetworkProtocolUnknown describes a unknown network protocol 26 | NetworkProtocolUnknown NetworkProtocol = "unknown" 27 | // NetworkProtocolTCP describes the TCP network protocol 28 | NetworkProtocolTCP NetworkProtocol = "tcp" 29 | // NetworkProtocolUDP describes the UDP network protocol 30 | NetworkProtocolUDP NetworkProtocol = "udp" 31 | ) 32 | 33 | // NetworkProtocolFromString parses a network protocol from the given value. Returns NetworkProtocolUnknown 34 | // if not known value can be parsed. 35 | func NetworkProtocolFromString(value string) NetworkProtocol { 36 | switch value { 37 | case "tcp": 38 | return NetworkProtocolTCP 39 | case "udp": 40 | return NetworkProtocolUDP 41 | } 42 | return "unknown" 43 | } 44 | 45 | // NetworkServiceSpec is used to define the user defined network services that should be opened on a container 46 | type NetworkServiceSpec struct { 47 | // Port is the port the container provides a service on 48 | // Example: 3000 49 | Port int `json:"port,omitempty" yaml:"port,omitempty"` 50 | // PortEnd is the end of the port range set for a service. If empty, only a 51 | // single port is opened 52 | // Example: 3010 53 | PortEnd int `json:"port_end,omitempty" yaml:"port_end,omitempty"` 54 | // List of network protocols (tcp, udp) the port should be exposed for 55 | // Example: ["tcp", "udp"] 56 | Protocols []NetworkProtocol `json:"protocols" yaml:"protocols"` 57 | // Expose defines wether the service is exposed on the public endpoint of the node 58 | // or if it is only available on the private endpoint. To expose the service set to 59 | // true and to false otherwise. 60 | Expose bool `json:"expose" yaml:"expose"` 61 | // Name gives the container a hint what the exposed port is being used for. This 62 | // allows further tweaks inside the container to expose the service correctly. 63 | // Exampe: ssh 64 | Name string `json:"name" yaml:"name"` 65 | } 66 | -------------------------------------------------------------------------------- /examples/ams/node-show/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "flag" 23 | "log" 24 | "os" 25 | 26 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 27 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 28 | ) 29 | 30 | type nodeShowCmd struct { 31 | common.ConnectionCmd 32 | name string 33 | } 34 | 35 | func (command *nodeShowCmd) Parse() { 36 | flag.StringVar(&command.name, "name", "", "Name of the node") 37 | 38 | command.ConnectionCmd.Parse() 39 | 40 | if len(command.name) == 0 { 41 | flag.Usage() 42 | os.Exit(1) 43 | } 44 | } 45 | 46 | func main() { 47 | cmd := &nodeShowCmd{} 48 | cmd.Parse() 49 | c := cmd.NewClient() 50 | 51 | if err := showNode(c, cmd.name); err != nil { 52 | log.Fatal(err) 53 | } 54 | } 55 | 56 | func showNode(c client.Client, name string) error { 57 | node, _, err := c.RetrieveNodeByName(name) 58 | if err != nil { 59 | return err 60 | } 61 | 62 | var outputData struct { 63 | Name string `yaml:"name" json:"name"` 64 | Network struct { 65 | Address string `yaml:"address" json:"address"` 66 | BridgeMTU int `yaml:"bridge-mtu" json:"bridge-mtu"` 67 | } `yaml:"network" json:"network"` 68 | Status string `yaml:"status" json:"status"` 69 | Config struct { 70 | PublicAddress string `yaml:"public-address" json:"public-address"` 71 | CPUs int `yaml:"cpus" json:"cpus"` 72 | CPUAllocationRate float32 `yaml:"cpu-allocation-rate" json:"cpu-allocation-rate"` 73 | Memory string `yaml:"memory" json:"memory"` 74 | MemoryAllocationRate float32 `yaml:"memory-allocation-rate" json:"memory-allocation-rate"` 75 | } `yaml:"config" json:"config"` 76 | } 77 | outputData.Name = node.Name 78 | outputData.Network.Address = node.Address 79 | outputData.Network.BridgeMTU = node.NetworkBridgeMTU 80 | outputData.Status = node.Status 81 | outputData.Config.PublicAddress = node.PublicAddress 82 | outputData.Config.CPUs = node.CPUs 83 | outputData.Config.CPUAllocationRate = node.CPUAllocationRate 84 | outputData.Config.Memory = node.Memory 85 | outputData.Config.MemoryAllocationRate = node.MemoryAllocationRate 86 | 87 | return common.DumpData(outputData) 88 | } 89 | -------------------------------------------------------------------------------- /api/ams/addon.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package api 20 | 21 | const swaggerModelAddonVersion = ` 22 | addon-version: 23 | type: object 24 | properties: 25 | number: 26 | type: integer 27 | example: 3 28 | fingerprint: 29 | type: string 30 | example: e25f3e3bcead096461d89d8ab7043f14bdb1ecd39 31 | size: 32 | type: integer 33 | format: int64 34 | example: 28171923 35 | created_at: 36 | type: integer 37 | format: int64 38 | example: 1583946268 39 | ` 40 | 41 | // AddonVersion describes a single version of an addon 42 | // 43 | // swagger:model 44 | type AddonVersion struct { 45 | // Version for the addon 46 | // Example: 0 47 | Number int `json:"version" yaml:"version"` 48 | // SHA-256 fingerprint of the addon version 49 | // Example: 0791cfc011f67c60b7bd0f852ddb686b79fa46083d9d43ef9845c9235c67b261 50 | Fingerprint string `json:"fingerprint" yaml:"fingerprint"` 51 | // Size (in bytes) of the addon payload 52 | // Example: 529887868 53 | Size int64 `json:"size" yaml:"size"` 54 | // Creation timestamp of the addon 55 | // Example: 1610641117 56 | CreatedAt int64 `json:"created_at" yaml:"created_at"` 57 | } 58 | 59 | const swaggerModelAddon = ` 60 | addon: 61 | type: object 62 | properties: 63 | name: 64 | type: string 65 | versions: 66 | type: array 67 | items: 68 | $ref: "#/definitions/addon-version" 69 | ` 70 | 71 | // Addon describes a package with additional functionality to be added to containers 72 | // 73 | // swagger:model 74 | type Addon struct { 75 | // Name of the addon 76 | // Example: my-addon 77 | Name string `json:"name" yaml:"name"` 78 | // List of versions of the addon 79 | Versions []AddonVersion `json:"versions" yaml:"versions"` 80 | // List of applications using this addon 81 | // Example: ["app1", "app2"] 82 | UsedBy []string `json:"used_by" yaml:"used_by"` 83 | } 84 | 85 | // AddonsPost is used to create a new addon 86 | // 87 | // swagger:model 88 | type AddonsPost struct { 89 | // Name of the addon 90 | // Example: my-addon 91 | Name string `json:"name" yaml:"name"` 92 | } 93 | 94 | // AddonPatch allows updating an existing addon with a new version 95 | // 96 | // swagger:model 97 | type AddonPatch struct{} 98 | -------------------------------------------------------------------------------- /pkg/network/cert.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package network 20 | 21 | import ( 22 | "crypto/sha256" 23 | "crypto/tls" 24 | "crypto/x509" 25 | "encoding/pem" 26 | "fmt" 27 | "net/http" 28 | "time" 29 | ) 30 | 31 | const ( 32 | // DefaultTransportTimeout stands for the default value for client requests to wait for a reply 33 | DefaultTransportTimeout = 30 * time.Second 34 | ) 35 | 36 | // CertFingerprint returns the sha256 fingerprint of the given x509.Certificate 37 | func CertFingerprint(cert *x509.Certificate) string { 38 | return fmt.Sprintf("%x", sha256.Sum256(cert.Raw)) 39 | } 40 | 41 | // CertFingerprintStr decodes the given string to x509.Certificate and then generates a sha256 fingerprint 42 | func CertFingerprintStr(c string) (string, error) { 43 | pemCertificate, _ := pem.Decode([]byte(c)) 44 | if pemCertificate == nil { 45 | return "", fmt.Errorf("invalid certificate") 46 | } 47 | 48 | cert, err := x509.ParseCertificate(pemCertificate.Bytes) 49 | if err != nil { 50 | return "", err 51 | } 52 | 53 | return CertFingerprint(cert), nil 54 | } 55 | 56 | // GetRemoteCertificate connects to the server and returns its certificate 57 | func GetRemoteCertificate(address string) (*x509.Certificate, error) { 58 | // Setup a permissive TLS config 59 | tlsConfig, err := GetTLSConfig("", "", "", nil) 60 | if err != nil { 61 | return nil, err 62 | } 63 | 64 | return GetRemoteCertificateWithTLSConfig(address, tlsConfig) 65 | } 66 | 67 | // GetRemoteCertificateWithTLSConfig connects to the server and returns its certificate 68 | func GetRemoteCertificateWithTLSConfig(address string, tlsConfig *tls.Config) (*x509.Certificate, error) { 69 | tlsConfig.InsecureSkipVerify = true 70 | tr := &http.Transport{ 71 | TLSClientConfig: tlsConfig, 72 | Dial: RFC3493Dialer, 73 | DisableKeepAlives: true, 74 | IdleConnTimeout: 30 * time.Second, 75 | MaxIdleConns: 1, 76 | } 77 | 78 | client := &http.Client{ 79 | Transport: tr, 80 | Timeout: DefaultTransportTimeout, 81 | } 82 | resp, err := client.Get(address) 83 | if err != nil { 84 | return nil, err 85 | } 86 | defer resp.Body.Close() 87 | 88 | // Retrieve the certificate 89 | if resp.TLS == nil || len(resp.TLS.PeerCertificates) == 0 { 90 | return nil, fmt.Errorf("unable to read remote TLS certificate") 91 | } 92 | 93 | return resp.TLS.PeerCertificates[0], nil 94 | } 95 | -------------------------------------------------------------------------------- /examples/ams/node-set/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "context" 23 | "errors" 24 | "flag" 25 | "log" 26 | "os" 27 | "strconv" 28 | 29 | api "github.com/anbox-cloud/ams-sdk/api/ams" 30 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 31 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 32 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared" 33 | ) 34 | 35 | type nodeSetCmd struct { 36 | common.ConnectionCmd 37 | name string 38 | key string 39 | value string 40 | } 41 | 42 | func (command *nodeSetCmd) Parse() { 43 | flag.StringVar(&command.name, "name", "", "Name of the node") 44 | flag.StringVar(&command.key, "key", "", "Key of the property to set") 45 | flag.StringVar(&command.value, "value", "", "Value of the property to set") 46 | 47 | command.ConnectionCmd.Parse() 48 | 49 | if len(command.name) == 0 || len(command.key) == 0 || 50 | len(command.value) == 0 { 51 | flag.Usage() 52 | os.Exit(1) 53 | } 54 | } 55 | 56 | func main() { 57 | cmd := &nodeSetCmd{} 58 | cmd.Parse() 59 | c := cmd.NewClient() 60 | 61 | if err := updateNode(c, cmd.name, cmd.key, cmd.value); err != nil { 62 | log.Fatal(err) 63 | } 64 | } 65 | 66 | func updateNode(c client.Client, node, key, value string) error { 67 | details := &api.NodePatch{} 68 | switch key { 69 | case "public-address": 70 | details.PublicAddress = &value 71 | case "cpus": 72 | v, err := strconv.Atoi(value) 73 | if err != nil { 74 | return err 75 | } 76 | details.CPUs = &v 77 | case "cpu-allocation-rate": 78 | v, err := strconv.ParseFloat(value, 32) 79 | if err != nil { 80 | return err 81 | } 82 | v32 := float32(v) 83 | details.CPUAllocationRate = &v32 84 | case "memory": 85 | _, err := shared.ParseByteSizeString(value) 86 | if err != nil { 87 | return err 88 | } 89 | details.Memory = &value 90 | case "memory-allocation-rate": 91 | v, err := strconv.ParseFloat(value, 32) 92 | if err != nil { 93 | return err 94 | } 95 | v32 := float32(v) 96 | details.MemoryAllocationRate = &v32 97 | default: 98 | return errors.New("Unknown configuration item") 99 | } 100 | 101 | operation, err := c.UpdateNode(node, details) 102 | if err != nil { 103 | return err 104 | } 105 | 106 | // Wait for add operation to finish 107 | return operation.Wait(context.Background()) 108 | } 109 | -------------------------------------------------------------------------------- /pkg/ams/shared/atomic_file.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package shared 20 | 21 | import ( 22 | "fmt" 23 | "io/ioutil" 24 | "os" 25 | "path" 26 | ) 27 | 28 | // AtomicFile allows operation on a file to happen atomicly. Changes must be committed in 29 | // the end before the final file will appear at its target location 30 | type AtomicFile struct { 31 | *os.File 32 | 33 | targetPath string 34 | committed bool 35 | } 36 | 37 | // WriteFileAtomic writes the given content to the target path in an atomic way 38 | func WriteFileAtomic(targetPath string, content []byte, mode os.FileMode) error { 39 | f, err := NewAtomicFile(targetPath, mode) 40 | if err != nil { 41 | return err 42 | } 43 | defer f.Cancel() 44 | 45 | n, err := f.Write(content) 46 | if err != nil { 47 | return err 48 | } 49 | if n != len(content) { 50 | return fmt.Errorf("failed to write full content to file at path %s", targetPath) 51 | } 52 | 53 | return f.Commit() 54 | } 55 | 56 | // NewAtomicFile creates a new AtomicFile with the given target path and mode 57 | func NewAtomicFile(targetPath string, mode os.FileMode) (*AtomicFile, error) { 58 | f, err := ioutil.TempFile(path.Dir(targetPath), path.Base(targetPath)) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | if err := f.Chmod(mode); err != nil { 64 | f.Close() 65 | os.Remove(f.Name()) 66 | return nil, err 67 | } 68 | 69 | af := AtomicFile{ 70 | File: f, 71 | targetPath: targetPath, 72 | } 73 | 74 | return &af, nil 75 | } 76 | 77 | // Commit commits changes made to the file and moves the temporary file to its 78 | // final location 79 | func (af *AtomicFile) Commit() error { 80 | if err := af.Sync(); err != nil { 81 | return err 82 | } 83 | 84 | if err := af.Close(); err != nil { 85 | return err 86 | } 87 | 88 | if err := os.Rename(af.Name(), af.targetPath); err != nil { 89 | return err 90 | } 91 | 92 | af.committed = true 93 | 94 | return nil 95 | } 96 | 97 | // Cancel all changes made. Is a no-op when Commit was already called 98 | func (af *AtomicFile) Cancel() error { 99 | if af.committed { 100 | return fmt.Errorf("cannot canceled as already committed") 101 | } 102 | 103 | if err := af.Close(); err != nil { 104 | return err 105 | } 106 | 107 | if err := os.Remove(af.Name()); err != nil { 108 | return err 109 | } 110 | 111 | return nil 112 | } 113 | -------------------------------------------------------------------------------- /pkg/ams/client/nodes.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | "bytes" 23 | "encoding/json" 24 | 25 | api "github.com/anbox-cloud/ams-sdk/api/ams" 26 | errs "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/errors" 27 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/client" 28 | ) 29 | 30 | // ListNodes returns a list of all availables LXD nodes AMS knows about 31 | func (c *clientImpl) ListNodes() ([]api.Node, error) { 32 | nodes := []api.Node{} 33 | params := client.QueryParams{ 34 | "recursion": "1", 35 | } 36 | _, err := c.QueryStruct("GET", client.APIPath("nodes"), params, nil, nil, "", &nodes) 37 | return nodes, err 38 | } 39 | 40 | // AddNode adds a new node to AMS 41 | func (c *clientImpl) AddNode(node *api.NodesPost) (client.Operation, error) { 42 | b, err := json.Marshal(node) 43 | if err != nil { 44 | return nil, err 45 | } 46 | op, _, err := c.QueryOperation("POST", client.APIPath("nodes"), nil, nil, bytes.NewReader(b), "") 47 | return op, err 48 | } 49 | 50 | // RemoveNode removes a single node 51 | func (c *clientImpl) RemoveNode(name string, force, keepInCluster bool) (client.Operation, error) { 52 | if len(name) == 0 { 53 | return nil, errs.NewInvalidArgument("name") 54 | } 55 | 56 | details := api.NodeDelete{ 57 | Force: force, 58 | KeepInCluster: keepInCluster, 59 | } 60 | b, err := json.Marshal(details) 61 | if err != nil { 62 | return nil, err 63 | } 64 | 65 | op, _, err := c.QueryOperation("DELETE", client.APIPath("nodes", name), nil, nil, bytes.NewReader(b), "") 66 | return op, err 67 | } 68 | 69 | // RetrieveNodeByName retrieves a node specified by name from AMS 70 | func (c *clientImpl) RetrieveNodeByName(name string) (*api.Node, string, error) { 71 | if len(name) == 0 { 72 | return nil, "", errs.NewInvalidArgument("name") 73 | } 74 | node := &api.Node{} 75 | etag, err := c.QueryStruct("GET", client.APIPath("nodes", name), nil, nil, nil, "", node) 76 | return node, etag, err 77 | } 78 | 79 | // UpdateNode updates an existing node 80 | func (c *clientImpl) UpdateNode(name string, details *api.NodePatch) (client.Operation, error) { 81 | if len(name) == 0 { 82 | return nil, errs.NewInvalidArgument("name") 83 | } 84 | if details == nil { 85 | return nil, errs.NewInvalidArgument("details") 86 | } 87 | b, err := json.Marshal(details) 88 | if err != nil { 89 | return nil, err 90 | } 91 | op, _, err := c.QueryOperation("PATCH", client.APIPath("nodes", name), nil, nil, bytes.NewReader(b), "") 92 | return op, err 93 | } 94 | -------------------------------------------------------------------------------- /pkg/ams/client/addon.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | "strconv" 23 | 24 | api "github.com/anbox-cloud/ams-sdk/api/ams" 25 | errs "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/errors" 26 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/client" 27 | ) 28 | 29 | // AddAddon adds a new addon and uploads the given addon package to AMS 30 | func (c *clientImpl) AddAddon(name string, packagePath string, sentBytes chan float64) (client.Operation, error) { 31 | details := api.AddonsPost{Name: name} 32 | return c.upload("POST", client.APIPath("addons"), nil, packagePath, details, sentBytes) 33 | } 34 | 35 | // UpdateAddon updates an existing addon 36 | func (c *clientImpl) UpdateAddon(name, packagePath string, sentBytes chan float64) (client.Operation, error) { 37 | if len(name) == 0 { 38 | return nil, errs.NewInvalidArgument("name") 39 | } 40 | details := api.AddonPatch{} 41 | return c.upload("PATCH", client.APIPath("addons", name), nil, packagePath, details, sentBytes) 42 | } 43 | 44 | // RetrieveAddon loads an addon from the connected AMS service 45 | func (c *clientImpl) RetrieveAddon(name string) (*api.Addon, string, error) { 46 | if len(name) == 0 { 47 | return nil, "", errs.NewInvalidArgument("name") 48 | } 49 | var details api.Addon 50 | etag, err := c.QueryStruct("GET", client.APIPath("addons", name), nil, nil, nil, "", &details) 51 | return &details, etag, err 52 | } 53 | 54 | // DeleteAddon deletes an existing addon 55 | func (c *clientImpl) DeleteAddon(name string) (client.Operation, error) { 56 | if len(name) == 0 { 57 | return nil, errs.NewInvalidArgument("name") 58 | } 59 | op, _, err := c.QueryOperation("DELETE", client.APIPath("addons", name), nil, nil, nil, "") 60 | return op, err 61 | } 62 | 63 | // DeleteAddonVersion deletes a specific version of the given addon 64 | func (c *clientImpl) DeleteAddonVersion(name string, version int) (client.Operation, error) { 65 | if len(name) == 0 { 66 | return nil, errs.NewInvalidArgument("name") 67 | } 68 | op, _, err := c.QueryOperation("DELETE", client.APIPath("addons", name, strconv.Itoa(version)), nil, nil, nil, "") 69 | return op, err 70 | } 71 | 72 | // ListAddons lists all currently available addons of the connected AMS service 73 | func (c *clientImpl) ListAddons() ([]api.Addon, error) { 74 | addons := []api.Addon{} 75 | params := client.QueryParams{ 76 | "recursion": "1", 77 | } 78 | _, err := c.QueryStruct("GET", client.APIPath("addons"), params, nil, nil, "", &addons) 79 | return addons, err 80 | } 81 | -------------------------------------------------------------------------------- /pkg/ams/shared/rest/api/statuscode.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package api 20 | 21 | const swaggerModelStatusCode = ` 22 | rest-api-status-code: 23 | type: integer 24 | description: | 25 | * 100: Operation Created 26 | * 101: Started 27 | * 102: Stopped 28 | * 103: Running 29 | * 104: Cancelling 30 | * 105: Pending 31 | * 106: Startings 32 | * 107: Stopping 33 | * 108: Aborting 34 | * 109: Freezing 35 | * 110: Frozen 36 | * 111: Thawed 37 | * 112: Error 38 | * 200: Success 39 | * 400: Failure 40 | * 401: Cancelled 41 | enum: 42 | - 100 43 | - 101 44 | - 102 45 | - 103 46 | - 104 47 | - 105 48 | - 106 49 | - 107 50 | - 108 51 | - 109 52 | - 110 53 | - 111 54 | - 112 55 | - 200 56 | - 400 57 | - 401 58 | ` 59 | 60 | // StatusCode represents a valid REST operation 61 | type StatusCode int 62 | 63 | // status codes 64 | const ( 65 | OperationCreated StatusCode = 100 66 | Started StatusCode = 101 67 | Stopped StatusCode = 102 68 | Running StatusCode = 103 69 | Cancelling StatusCode = 104 70 | Pending StatusCode = 105 71 | Starting StatusCode = 106 72 | Stopping StatusCode = 107 73 | Aborting StatusCode = 108 74 | Freezing StatusCode = 109 75 | Frozen StatusCode = 110 76 | Thawed StatusCode = 111 77 | Error StatusCode = 112 78 | 79 | Success StatusCode = 200 80 | 81 | Failure StatusCode = 400 82 | Cancelled StatusCode = 401 83 | ) 84 | 85 | // String returns a suitable string representation for the status code 86 | func (o StatusCode) String() string { 87 | return map[StatusCode]string{ 88 | OperationCreated: "Operation created", 89 | Started: "Started", 90 | Stopped: "Stopped", 91 | Running: "Running", 92 | Cancelling: "Cancelling", 93 | Pending: "Pending", 94 | Success: "Success", 95 | Failure: "Failure", 96 | Cancelled: "Cancelled", 97 | Starting: "Starting", 98 | Stopping: "Stopping", 99 | Aborting: "Aborting", 100 | Freezing: "Freezing", 101 | Frozen: "Frozen", 102 | Thawed: "Thawed", 103 | Error: "Error", 104 | }[o] 105 | } 106 | 107 | // IsFinal will return true if the status code indicates an end state 108 | func (o StatusCode) IsFinal() bool { 109 | return int(o) >= 200 110 | } 111 | -------------------------------------------------------------------------------- /pkg/ams/shared/rest/client/interfaces.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package client 20 | 21 | import ( 22 | "context" 23 | "io" 24 | "net/http" 25 | "time" 26 | 27 | "github.com/gorilla/websocket" 28 | 29 | "github.com/anbox-cloud/ams-sdk/pkg/ams/shared/rest/api" 30 | ) 31 | 32 | // The Operation interface represents a currently running operation. 33 | type Operation interface { 34 | AddHandler(function func(api.Operation)) (target *EventTarget, err error) 35 | Cancel() (err error) 36 | Get() (op api.Operation) 37 | RemoveHandler(target *EventTarget) (err error) 38 | Refresh() (err error) 39 | Wait(ctx context.Context) (err error) 40 | } 41 | 42 | // The Operations interface represents operations exposed API methods 43 | type Operations interface { 44 | ListOperationUUIDs() (uuids []string, err error) 45 | ListOperations() (operations []api.Operation, err error) 46 | RetrieveOperationByID(uuid string) (op *api.Operation, etag string, err error) 47 | WaitForOperationToFinish(uuid string, timeout time.Duration) (op *api.Operation, err error) 48 | GetOperationWebsocket(uuid, secret string) (conn *websocket.Conn, err error) 49 | DeleteOperation(uuid string) (err error) 50 | } 51 | 52 | // The Certificates interface represents client certificates related API methods 53 | type Certificates interface { 54 | ListCertificates() (certificates []api.Certificate, err error) 55 | AddCertificate(base64PublicKey, trustPassword string) (err error) 56 | RetrieveCertificate(fingerprint string) (certificate *api.Certificate, err error) 57 | DeleteCertificate(fingerprint string) (op Operation, err error) 58 | } 59 | 60 | // The Client interface represents all available REST client operations 61 | type Client interface { 62 | ServiceURL() string 63 | HTTPTransport() *http.Transport 64 | 65 | SetTransportTimeout(timeout time.Duration) 66 | 67 | QueryStruct(method, path string, params QueryParams, header http.Header, body io.Reader, ETag string, target interface{}) (etag string, err error) 68 | QueryOperation(method, path string, params QueryParams, header http.Header, body io.Reader, ETag string) (operation Operation, etag string, err error) 69 | CallAPI(method, path string, params QueryParams, header http.Header, body io.Reader, ETag string) (response *api.Response, etag string, err error) 70 | DownloadFile(path string, params QueryParams, header http.Header, downloader func(header *http.Header, body io.ReadCloser) error) error 71 | 72 | Websocket(resource string) (conn *websocket.Conn, err error) 73 | 74 | // Event handling functions 75 | GetEvents() (listener *EventListener, err error) 76 | } 77 | -------------------------------------------------------------------------------- /examples/ams/container-show/main.go: -------------------------------------------------------------------------------- 1 | // -*- Mode: Go; indent-tabs-mode: t -*- 2 | /* 3 | * This file is part of AMS SDK 4 | * Copyright 2021 Canonical Ltd. 5 | * 6 | * This program is free software: you can redistribute it and/or modify it under 7 | * the terms of the Lesser GNU General Public License version 3, as published 8 | * by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY 12 | * QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the Lesser GNU General Public License along 16 | * with this program. If not, see . 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "flag" 23 | "log" 24 | "os" 25 | "time" 26 | 27 | api "github.com/anbox-cloud/ams-sdk/api/ams" 28 | "github.com/anbox-cloud/ams-sdk/examples/ams/common" 29 | "github.com/anbox-cloud/ams-sdk/pkg/ams/client" 30 | ) 31 | 32 | type containerShowCmd struct { 33 | common.ConnectionCmd 34 | id string 35 | } 36 | 37 | func (command *containerShowCmd) Parse() { 38 | flag.StringVar(&command.id, "id", "", "Container id") 39 | 40 | command.ConnectionCmd.Parse() 41 | 42 | if len(command.id) == 0 { 43 | flag.Usage() 44 | os.Exit(1) 45 | } 46 | } 47 | 48 | func main() { 49 | cmd := &containerShowCmd{} 50 | cmd.Parse() 51 | c := cmd.NewClient() 52 | 53 | if err := showContainer(c, cmd.id); err != nil { 54 | log.Fatal(err) 55 | } 56 | } 57 | 58 | func showContainer(c client.Client, id string) error { 59 | container, _, err := c.RetrieveContainerByID(id) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | var outputData struct { 65 | ID string `yaml:"id" json:"id"` 66 | Name string `yaml:"name" json:"name"` 67 | Status string `yaml:"status" json:"status"` 68 | Node string `yaml:"node" json:"node"` 69 | CreatedAt time.Time `yaml:"created_at" json:"created_at"` 70 | 71 | Application struct { 72 | ID string `yaml:"id" json:"id"` 73 | Version int `yaml:"version" json:"version"` 74 | } `yaml:"application" json:"application"` 75 | 76 | Network struct { 77 | Address string `yaml:"address" json:"address"` 78 | PublicAddress string `yaml:"public_address" json:"public_address"` 79 | Services []api.ContainerService `yaml:"services" json:"services"` 80 | } `yaml:"network" json:"network"` 81 | 82 | StoredLogs []string `json:"stored_logs" yaml:"stored_logs"` 83 | ErrorMessage string `json:"error_message" yaml:"error_message"` 84 | } 85 | outputData.ID = container.ID 86 | outputData.Name = container.Name 87 | outputData.Status = container.Status 88 | outputData.Node = container.Node 89 | outputData.CreatedAt = time.Unix(container.CreatedAt, 0) 90 | outputData.Application.ID = container.AppID 91 | outputData.Application.Version = container.AppVersion 92 | outputData.Network.Address = container.Address 93 | outputData.Network.PublicAddress = container.PublicAddress 94 | outputData.Network.Services = container.Services 95 | outputData.StoredLogs = container.StoredLogs 96 | outputData.ErrorMessage = container.ErrorMessage 97 | 98 | return common.DumpData(outputData) 99 | } 100 | --------------------------------------------------------------------------------