Charm store API
The current live api lives at https://api.jujucharms.com/charmstore/v4
Intro
The charm store stores and indexes charms and bundles. A charm or bundle is referred to by a charm store id which can take one of the following two forms:
- ~owner/series/name(-revision)
- series/name(-revision)
Owner is the name of the user that owns the charm. Series is one of a small number of known possible series for charms (currently just the Ubuntu series names) or the special name bundle to signify that the charm id refers to a charm bundle.
A charm store id referring to a charm (not a bundle) can also use one of the following two forms, omitting the series:
- ~owner/name(-revision)
- name(-revision)
In this case the store will look at all charms with the same owner and name, and choose one according to its preference (for example, it currently prefers the latest LTS series).
Data format
All endpoints that do not produce binary data produce a single JSON object as
their result. These will be described in terms of the Go types that produce and
consume the format, along with an example. A charm id is represented as a
charm.Reference type.
Errors
If any request returns an error, it will produce it in the following form:
type Error struct {
Message string
Code string
Info map[string] Error `json:",omitempty"`
}Example:
{
"Message": "unexpected Content-Type \"image/jpeg\"; expected \"application/json\"",
"Code": "bad request"
}Note: this format is compatible with the error results used by juju-core. Currently defined codes are the following:
- not found
- metadata not found
- forbidden
- bad request
- duplicate upload
- multiple errors
- unauthorized
- method not allowed
The Info field is set when a request returns a "multiple errors" error code;
currently the only two endpoints that can are "/meta" and "id/meta/any".
Each element in Info corresponds to an element in the PUT request, and holds
the error for that element. See those endpoints for examples.
Bulk requests and missing metadata
There are two forms of "bulk" API request that can return information about
several items at once. The /meta/any endpoint (along with some others) have a
set of "include" flags that specify metadata to return. The /meta endpoint
has a set of "id" flags that specify a set of ids to return data on.
In both of these cases, when the relevant data does not exist, the result will
be omitted from the returned map. For example a GET of
/meta/archive-size?id=something will return an empty map if the id
"something" is not found; a GET of
/precise/wordpress-34/meta/any?include=bundle-metadata will return an empty
map if the id "precise/wordpress-34" refers to a bundle rather than a charm.
For the singular forms of these endpoints, a 404 "metadata not found" error will be returned when this happens.
In the meta/any GET bulk request, if some data requires authorization, the
default behavior is to return an authorization required response. Clients
interested in public data only can include a ignore-auth=1 query so that only
public information is returned. In this case, results requiring authorization
(if any) will be omitted.
Versioning
The version of the API is indicated by an initial "vN" prefix to the path.
Later versions will increment this number. This also means we can potentially
serve backwardly compatible paths to juju-core. All paths in this document
should be read as if they had a "v4" prefix. For example, the
wordpress/meta/charm-metadata path is actually at
v4/wordpress/meta/charm-metadata.
Boolean values
Where a flag specifies a boolean property, the value must be either "1", signifying true, or empty or "0", signifying false.
Requests
Expand-id
GET id/expand-id
The expand-id path expands a general id into a set of specific ids. It strips any revision number and series from id, and returns a slice of all the possible ids matched by that, including all the versions and series.
[]Id
type Id struct {
Id string
}Example: GET wordpress/expand-id
[
{"Id": "precise/wordpress-1"},
{"Id": "precise/wordpress-2"},
{"Id": "trusty/wordpress-1"},
{"Id": "trusty/wordpress-2"}
]Example: GET precise/wordpress-34/expand-id
[
{"Id": "precise/wordpress-1"},
{"Id": "precise/wordpress-2"},
{"Id": "trusty/wordpress-1"},
{"Id": "trusty/wordpress-2"}
]Archive
GET id/archive
The /archive path returns the raw archive zip file for the charm with the
given charm id. The response header includes the SHA 384 hash of the archive
(Content-Sha384) and the fully qualified entity id (Entity-Id).
Example: GET wordpress/archive
Any additional elements attached to the /charm path retrieve the file from
the charm or bundle's zip file. The Content-Sha384 header field in the
response will hold the hash checksum of the archive.
GET id/archive/path
Retrieve a file corresponding to path in the charm or bundle's zip archive.
Example: GET trusty/wordpress/archive/config.yaml
POST id/archive
This uploads the given charm or bundle in zip format.
POST id/archive?hash=sha384hash
The id specified must specify the series and must not contain a revision number. The hash flag must specify the SHA384 hash of the uploaded archive in hexadecimal format. If the same content has already been uploaded, the response will return immediately without reading the entire body.
The charm or bundle is verified before being made available.
The response holds the full charm/bundle id including the revision number.
type UploadedId struct {
Id string
}Example response body:
{
"Id": "precise/wordpress-24"
}DELETE id/archive
This deletes the given charm or bundle with the given id. If the ID is not
fully specified, the charm series or revisions are not resolved and the charm
is not deleted. In order to delete the charm, the ID must include series as
well as revisions. In order to delete all versions of the charm, use
/expand-id and iterate on all elements in the result.
Visual diagram
GET id/diagram.svg
This returns a scalable vector-graphics image representing the entity with the given id. This will return a not-found error for charms.
GET id/icon.svg
This returns the SVG image of the charm's icon. This reports a not-found error
for bundles. Unlike the archive/icon.svg where 404 is returned in case an
icon does not exist, this endpoint returns the default icon.
GET id/readme
This returns the README.
Promulgation
PUT id/promulgate
A PUT to ~user/anyseries/name-anyrevision sets whether entities with the id x/name are considered to be aliases for ~user/x/name for all series x. The series and revision in the id are ignored (except that an entity must exist that matches the id).
If Promulgate is true, it means that any new charms published to ~user/x/name will also be given the alias x/name. The latest revision for all ids ~user/anyseries/name will also be aliased likewise.
If Promulgate is false, any new charms published to ~user/anyseries/name will not be given a promulgated alias, but no change is made to any existing aliases.
The promulgated status can be retrieved from the promulgated meta endpoint.
type PromulgateRequest struct {
Promulgate bool
}Example: PUT ~charmers/precise/wordpress-23/promulgate
Request body:
{
"Promulgate" : true,
}Stats
GET stats/counter/...
This endpoint can be used to retrieve stats related to entities.
GET stats/counter/key[:key]...?[by=unit]&start=date][&stop=date][&list=1]
The stats path allows the retrieval of counts of operations in a general way. A statistic is composed of an ordered tuple of keys:
kind:series:name:user
Operations on the store increment counts associated with a specific tuple, determined by the operation and the charm being operated on.
When querying statistics, it is possible to aggregate statistics by using a
\* as the last tuple element, standing for all tuples with the given prefix.
For example, missing:\* will retrieve the counts for all operations of kind
"missing", regardless of the series, name or user.
If the list flag is specified, counts for all next level keys will be listed.
For example, a query for stats/counter/download:*?list=1&by=week will show
all the download counts for each series for each week.
If a date range is specified, the returned counts will be restricted to the
given date range. Dates are specified in the form "yyyy-mm-dd". If the by
flag is specified, one count is shown for each unit in the specified period,
where unit can be week or day.
Possible kinds are:
- archive-download
- archive-delete
- archive-upload
- archive-failed-upload
[]Statistic
type Statistic struct {
Key string `json:",omitempty"`
Date string `json:",omitempty"`
Count int64
}Example: GET "stats/counter/missing:trusty:*"
[
{"Count": 1917}
]Example:
GET stats/counter/download/archive-download:*?by=week&list=1&start=2014-03-01
[
{
"Key": "charm-bundle:precise:*",
"Date": "2014-06-08",
"Count": 2715
}, {
"Key": "charm-bundle:trusty:*",
"Date": "2014-06-08",
"Count": 2672
}, {
"Key": "charm-bundle:oneiric:*",
"Date": "2014-06-08",
"Count": 14
}, {
"Key": "charm-bundle:quantal:*",
"Date": "2014-06-08",
"Count": 1
}, {
"Key": "charm-bundle:trusty:*",
"Date": "2014-06-15",
"Count": 3835
}, {
"Key": "charm-bundle:precise:*",
"Date": "2014-06-15",
"Count": 3389
}
]Update: We need to provide aggregated stats for downloads:
- promulgated and ~user counterpart charms should have the same download stats.
Meta
GET meta
The meta path returns an array of all the path names under meta, excluding the
meta/any path, as suitable for passing as "include=" flags to paths that
allow those. Note that the result does not include sub-paths of extra-info
because these vary according to each charm or bundle.
Example: GET /meta
[
"archive-size",
"archive-upload-time",
"bundle-machine-count",
"bundle-metadata",
"bundle-unit-count",
"bundles-containing",
"charm-actions",
"charm-config",
"charm-metadata",
"charm-related",
"extra-info",
"hash",
"hash256",
"id",
"id-name",
"id-revision",
"id-series",
"id-user",
"manifest",
"promulgated",
"revision-info",
"stats",
"tags"
]GET meta/endpoint
This endpoint allows a user to query any number of IDs for metadata.
GET meta/endpoint?id=id0[&id=id1...][otherflags]
This call is equivalent to calling "id/meta" for each id separately. The result holds an element for each id in the request with the resulting metadata exactly as returned by "GET id/meta/endpoint[?otherflags]". The map keys are the ids exactly as specified in the request, although they are resolved to fill in series and revision as usual when fetching the metadata. Any ids that are not found, or with non-relevant metadata, will be omitted.
map[string] interface{}Example: GET meta/archive-size?id=wordpress&id=mysql
{
"wordpress": {
"Size": 1234
},
"mysql" : {
"Size": 4321
}
}Example: GET /meta/any?include=archive-size&include=extra-info/featured&id=wordpress&id=mysql
{
"wordpress": {
"Id": "precise/wordpress-3",
"Meta": {
"archive-size": {
"Size": 1234
},
"extra-info/featured": true
}
},
"mysql" : {
"Id": "precise/mysql-23",
"Meta": {
"archive-size": {
"Size": 4321
},
"extra-info/featured": true
}
}
}PUT meta/endpoint
A PUT to this endpoint allows the metadata endpoint of several ids to be updated. The request body is as specified in the result of the above GET request. The ids in the body specify the ids that will be updated. If there is a failure, the error code will be "multiple errors", and the Info field will holds one entry for each id in the request body that failed, holding the error for that id. If there are no errors, PUT endpoints usually return an empty body in the response.
Example: PUT meta/extra-info/featured
Request body:
{
"precise/wordpress-23" : true,
"precise/mysql-53" : true,
"precise/wordpress-22" : false,
}Example: PUT meta/any
Request body:
{
"precise/wordpress-23": {
"Meta": {
"extra-info/featured": true,
"extra-info/revision-info": "12dfede4ee23",
"bad-metaname": 3235
}
},
"trusty/mysql-23": {
"Meta": {
"extra-info/featured": false,
}
}
}Response body (with HTTP status 500):
{
"Message": "multiple errors (1) found",
"Code": "multiple errors",
"Info": {
"precise/wordpress-23": {
"Message": "multiple errors",
"Code": "multiple errors",
"Info": {
"bad-metaname": {
"Message": "metadata not found",
"Code": "not found"
}
}
}
}
}If the request succeeds, a 200 OK status code is returned with an empty response body.
GET id/meta
This path returns the same information as the meta path. The results are the same regardless of the actual id.
Example: GET foo/meta
[
"archive-size",
"archive-upload-time",
"bundle-machine-count",
"bundle-metadata",
"bundle-unit-count",
"bundles-containing",
"charm-actions",
"charm-config",
"charm-metadata",
"charm-related",
"extra-info",
"id",
"id-name",
"id-revision",
"id-series",
"id-user",
"manifest",
"promulgated",
"revision-info",
"stats",
"tags"
]GET id/meta/any
GET id/meta/any?[include=meta[&include=meta...]]
The meta/any path returns requested metadata information on the given id. If
the id is non-specific, the latest revision and preferred series for the id
will be assumed.
Other metadata can be requested by specifying one or more include flags. The
value of each meta must be the name of one of the path elements defined under
the /meta path (for example: charm-config, charm-meta, manifest) and
causes the desired metadata to be included in the Meta field, keyed by meta. If
there is no metadata for the given meta path, the element will be omitted (for
example, if bundle-specific data is requested for a charm id).
The any path may not itself be the subject of an include directive. It is
allowed to specify "charm-" or "bundle-"" specific metadata paths -- if the id
refers to a charm then bundle-specific metadata will be omitted and vice versa.
Various other paths use the same include mechanism to allow retrieval of
arbitrary metadata.
type Meta struct {
Id string `json:",omitempty"`
Meta map[string] interface{} `json:",omitempty"`
}Example: GET wordpress/meta/any
{
"Id": "trusty/wordpress-32"
}Example: GET ubuntu/meta/any?include=archive-size&include=extra-info/featured
{
"Id": "trusty/ubuntu-3",
"Meta": {
"archive-size": {
"Size": 7580
},
"extra-info/featured": true
}
}PUT id/meta/any
This endpoint allows the updating of several metadata elements at once. These must support PUT requests. The body of the PUT request is in the same form as returned by the above GET request, except with the Id field omitted. The elements inside the Meta field specify which meta endpoints will be updated. If one or more of the update fails, the resulting error will contain an Info field that has an entry for each update that fails, keyed by the endpoint name.
Example: PUT ubuntu/meta/any
Request body:
{
"Meta": {
"extra-info": {
"revision-info": "a46f45649f0d0e0b"
},
"extra-info/featured": true
}
}Example: PUT ubuntu/meta/any
Request body:
{
"Meta": {
"extra-info/featured": false,
"archive-size": 12354,
}
}Response body:
{
"Message": "multiple errors",
"Code": "multiple errors",
"Info": {
"archive-size": {
"Message": "method not allowed",
"Code": "bad request",
}
}
}GET id/meta/charm-metadata
The /meta/charm.metadata path returns the contents of the charm metadata file
for a charm. The id must refer to a charm, not a bundle.
type CharmMetadata struct {
Summary string
Description string
Subordinate bool `json:",omitempty"`
// Provides and Requires map from the relation name to
// information about the relation.
Provides map[string]Relation `json:",omitempty"`
Requires map[string]Relation `json:",omitempty"`
Peers map[string]Relation `json:",omitempty"`
Tags []string `json:",omitempty"`
}
type Relation struct {
Interface string
Optional bool `json:",omitempty"`
Limit int `json:",omitempty"`
Scope RelationScope
}
type RelationRole string
type RelationScope stringThe possible values of a RelationScope are
- global
- container
Example: GET wordpress/meta/charm-metadata
{
"Summary": "WordPress is a full featured web blogging tool, this charm deploys it.",
"Description": "This will install and setup WordPress optimized to run in the cloud. This install, in particular, will \n place Ngnix and php-fpm configured to scale horizontally with Nginx's reverse proxy\n",
"Provides": {
"website": {
"Interface": "http",
"Scope": "global"
}
},
"Requires": {
"cache": {
"Interface": "cache",
"Scope": "global"
},
"db": {
"Interface": "db",
"Scope": "global"
}
},
"Peers": {
"loadbalancer": {
"Interface": "reversenginx",
"Scope": "global"
}
},
"Tags": [
"applications"
]
}GET id/meta/bundle-metadata
The meta/bundle-metadata path returns the contents of the bundle metadata
file for a bundle. The id must refer to a bundle, not a charm.
type BundleData struct {
Services map[string] ServiceSpec
Machines map[string] MachineSpec `json:",omitempty"`
Series string `json:",omitempty"`
Relations [][]string `json:",omitempty"`
}
type MachineSpec struct {
Constraints string `json:",omitempty"`
Annotations map[string]string `json:",omitempty"`
}
type ServiceSpec struct {
Charm string
NumUnits int
To []string `json:",omitempty"`
// Options holds the configuration values
// to apply to the new service. They should
// be compatible with the charm configuration.
Options map[string]interface{} `json:",omitempty"`
Annotations map[string]string `json:",omitempty"`
Constraints string `json:",omitempty"`
}Example: GET mediawiki/meta/bundle-metadata
{
"Services": {
"mediawiki": {
"Charm": "cs:precise/mediawiki-10",
"NumUnits": 1,
"Options": {
"debug": false,
"name": "Please set name of wiki",
"skin": "vector"
},
"Annotations": {
"gui-x": "619",
"gui-y": "-128"
}
},
"memcached": {
"Charm": "cs:precise/memcached-7",
"NumUnits": 1,
"Options": {
"connection_limit": "global",
"factor": 1.25
},
"Annotations": {
"gui-x": "926",
"gui-y": "-125"
}
}
},
"Relations": [
[
"mediawiki:cache",
"memcached:cache"
]
]
}GET id/meta/bundle-unit-count
The meta/bundle-unit-count path returns a count of all the units that will be
created by a bundle. The id must refer to a bundle, not a charm.
type BundleCount struct {
Count int
}Example: GET bundle/mediawiki/meta/bundle-unit-count
{
"Count": 1
}GET id/meta/bundle-machine-count
The meta/bundle-machine-count path returns a count of all the machines used
by a bundle. The id must refer to a bundle, not a charm.
type BundleCount struct {
Count int
}Example: GET bundle/mediawiki/meta/bundle-machine-count
{
"Count": 2
}GET id/meta/manifest
The meta/manifest path returns the list of all files in the bundle or charm's
archive.
[]ManifestFile
type ManifestFile struct {
Name string
Size int64
}Example: GET trusty/juju-gui-3/meta/manifest
[
{
"Name": "config.yaml",
"Size": 8254
},
{
"Name": "HACKING.md",
"Size": 11376
},
{
"Name": "Makefile",
"Size": 3304
},
{
"Name": "metadata.yaml",
"Size": 1110
},
{
"Name": "README.md",
"Size": 9243
},
{
"Name": "hooks/config-changed",
"Size": 1636
},
{
"Name": "hooks/install",
"Size": 3055
},
{
"Name": "hooks/start",
"Size": 1101
},
{
"Name": "hooks/stop",
"Size": 1053
}
]GET id/meta/charm-actions
The meta/charm-actions path returns the actions available in a charm as
stored in its actions.yaml file. Id must refer to a charm, not a bundle.
type Actions struct {
Actions map[string]ActionSpec `json:",omitempty"`
}
type ActionSpec struct {
Description string
Params JSONSchema
}The Params field holds a JSON schema specification of an action's parameters. See http://json-schema.org/latest/json-schema-core.html.
Example: GET wordpress/meta/charm-actions
{
"Actions": {
"backup": {
"Description": "back up the charm",
"Params": {
"properties": {
"destination-host": {
"type": "string"
},
"destination-name": {
"type": "string"
}
},
"required": [
"destination-host"
],
"type": "object"
}
}
}
}GET id/meta/charm-config
The meta/charm-config path returns the charm's configuration specification as
stored in its config.yaml file. Id must refer to a charm, not a bundle.
type Config struct {
Options map[string] Option
}
// Option represents a single charm config option.
type Option struct {
Type string
Description string
Default interface{}
}Example: GET trusty/juju-gui-3/meta/charm-config
{
"Options": {
"builtin-server": {
"Type": "boolean",
"Description": "Enable the built-in server.",
"Default": true
},
"login-help": {
"Type": "string",
"Description": "The help text shown to the user.",
"Default": null
},
"read-only": {
"Type": "boolean",
"Description": "Enable read-only mode.",
"Default": false
}
}
}GET id/meta/archive-size
The meta/archive-size path returns the archive size, in bytes, of the archive
of the given charm or bundle id.
type ArchiveSize struct {
Size int64
}Example: GET wordpress/meta/archive-size
{
"Size": 4747
}GET id/meta/hash
This path returns the SHA384 hash sum of the archive of the given charm or bundle id.
type HashResponse struct {
Sum string
}Example: GET wordpress/meta/hash
Response body:
{
"Sum": "0a410321586d244d3981e2b23a27a7e86ebdcab8bd0ca8f818d3f4c34b2ea2791e0dbdc949f70b283a3f5efdf908abf1"
}GET id/meta/hash256
This path returns the SHA256 hash sum of the archive of the given charm or bundle id.
type HashResponse struct {
Sum string
}Example: GET wordpress/meta/hash256
Response body:
{
"Sum": "9ab5036cc18ba61a9d25fad389e46b3d407fc02c3eba917fe5f18fdf51ee6924"
}GET id/meta/bundles-containing
The meta/bundles-containing path returns information on the last revision of
any bundles that contain the charm with the given id.
GET id/meta/bundles-containing[?include=meta[&include=meta...]]
The Meta field is populated with information on the returned bundles according
to the include flags - see the meta/any path for more info on how to use the
include flag. The only values that are valid for any-series, any-revision
or all-results flags are 0, 1 and empty. If all-results is enabled, all the
bundle revisions are returned, not just the last one. The API should validate
that and return bad request if any other value is provided.
[]Bundle
type Bundle struct {
Id string
Meta map[string]interface{} `json:",omitempty"`
}Example: GET mysql/meta/bundles-containing?include=featured might return:
[
{
"Id": "bundle/mysql-scalable",
"Meta": {
"featured": {
"Featured": false
}
}
},
{
"Id": "bundle/wordpress-simple",
"Meta": {
"featured": {
"Featured": true
}
}
}
]GET id/meta/extra-info
The meta/extra-info path reports any additional metadata recorded for the
charm. This contains only information stored by clients - the API server itself
does not populate any fields. The resulting object holds an entry for each
piece of metadata recorded with a PUT to meta/extra-info.
type ExtraInfo struct {
Values map[string] interface{}
}Example: GET wordpress/meta/extra-info
{
"featured": true,
"vcs-digest": "4b6b3c7d795eb66ca5f82bc52c01eb57ab595ab2"
}GET id/meta/extra-info/key
This path returns the contents of the given extra-info key. The result is
exactly the JSON value stored as a result of the PUT request to extra-info or
extra-info/key.
Example: GET wordpress/meta/extra-info/featured
truePUT id/meta/extra-info
This request updates the value of any metadata values. Any values that are not mentioned in the request are left untouched.
Example: PUT precise/wordpress-32/meta/extra-info
Request body:
{
"vcs-digest": "7d6a853c7bb102d90027b6add67b15834d815e08",
}PUT id/meta/extra-info/key
This request creates or updates the value for a specific key.
Example: PUT precise/wordpress-32/meta/extra-info/vcs-digest
Request body:
"7d6a853c7bb102d90027b6add67b15834d815e08",The above example is equivalent to the meta/extra-info example above.
GET id/meta/charm-related
The meta/charm-related path returns all charms that are related to the given
charm id, which must not refer to a bundle. It is possible to include
additional metadata for charms by using the include query:
GET id/meta/charm-related[?include=meta[&include=meta...]]
type Related struct {
// Requires holds an entry for each interface provided by
// the charm, containing all charms that require that interface.
Requires map[string] []Item `json:",omitempty"`
// Provides holds an entry for each interface required by the
// the charm, containing all charms that provide that interface.
Provides map[string] []Item `json:",omitempty"`
}
type Item struct {
Id string
Meta map[string] interface{} `json:",omitempty"`
}The Meta field is populated according to the include flags - see the meta
path for more info on how to use this.
Example: GET wordpress/meta/charm-related
{
"Requires": {
"memcache": [
{"Id": "precise/memcached-13"}
],
"db": [
{"Id": "precise/mysql-46"},
{"Id": "~clint-fewbar/precise/galera-42"}
]
},
"Provides": {
"http": [
{"Id": "precise/apache2-24"},
{"Id": "precise/haproxy-31"},
{"Id": "precise/squid-reverseproxy-8"}
]
}
}Example: GET trusty/juju-gui-3/meta/charm-related?include=charm-config
{
"Provides": {
"http": [
{
"Id": "precise/apache2-24",
"Meta": {
"charm-config": {
"Options": {
"logrotate_count": {
"Type": "int",
"Description": "The number of days",
"Default": 365
}
}
}
}
}
],
"nrpe-external-master": [
{
"Id": "precise/nova-compute-31",
"Meta": {
"charm-config": {
"Options": {
"bridge-interface": {
"Type": "string",
"Description": "Bridge interface",
"Default": "br100"
},
"bridge-ip": {
"Type": "string",
"Description": "IP to be assigned to bridge",
"Default": "11.0.0.1"
}
}
}
}
}
]
}
}GET id/meta/archive-upload-time
The meta/archive-upload-time path returns the time the archives for the given
id was uploaded. The time is formatted according to RFC3339.
type ArchiveUploadTimeResponse struct {
UploadTime time.Time
}Example: GET trusty/wordpress-42/meta/archive-upload-time
{
"UploadTime": "2014-07-04T13:53:57.403506102Z"
}GET id/meta/promulgated
The promulgated path reports whether the entity with the given ID is promulgated.
Promulgated charms do not require the user portion of the ID to be specified.
type PromulgatedResponse struct {
Promulgated bool
}Example: GET trusty/wordpress-42/meta/promulgated
{
"Promulgated": true
}GET id/meta/stats
Many clients will need to use stats to determine the best result. Details for a charm/bundle might require the stats as important information to users. Currently we track deployment stats only. We intend to open this up to additional data. The response includes downloads count for both the specific requested entity revision and for all the revisions, and it is structured as below:
// StatsResponse holds the result of an id/meta/stats GET request.
type StatsResponse struct {
// ArchiveDownloadCount is superceded by ArchiveDownload but maintained for
// backward compatibility.
ArchiveDownloadCount int64
// ArchiveDownload holds the downloads count for a specific revision of the
// entity.
ArchiveDownload StatsCount
// ArchiveDownloadAllRevisions holds the downloads count for all revisions
// of the entity.
ArchiveDownloadAllRevisions StatsCount
}
// StatsCount holds stats counts and is used as part of StatsResponse.
type StatsCount struct {
Total int64 // Total count over all time.
Day int64 // Count over the last day.
Week int64 // Count over the last week.
Month int64 // Count over the last month.
}GET id/meta/tags
The tags path returns any tags that are associated with the entity.
Example: GET trusty/wordpress-42/meta/tags
{
"Tags": [
"blog",
"cms"
]
}GET id/meta/revision-info
The revision-info path returns information about other available revisions of
the charm id that the charm store knows about. It will include both older and
newer revisions. The fully qualified ids of those charms will be returned in an
ordered list from newest to oldest revision. Note that the current revision
will be included in the list as it is also an available revision.
type RevisionInfo struct {
Revisions []*charm.Reference
}Example: GET trusty/wordpress-42/meta/revision-info
{
"Revisions": [
"cs:trusty/wordpress-43",
"cs:trusty/wordpress-42",
"cs:trusty/wordpress-41",
"cs:trusty/wordpress-39"
]
}GET id/meta/id
The id path returns information on the charm or bundle id, split apart into
its various components, including the id itself. The information is exactly
that contained within the entity id.
type Id struct {
Id *charm.Reference
User string
Series string `json:",omitempty"`
Name string
Revision int
}Example: GET ~bob/trusty/wordpress/meta/id
{
"Id": "~bob/trusty/wordpress-42",
"User": "bob",
"Series": "trusty",
"Name": "wordpress",
"Revision": 42
}Example: GET precise/wordpress/meta/id
{
"Id": "precise/wordpress-42",
"Series": "precise",
"Name": "wordpress",
"Revision": 42
}Example: GET bundle/openstack/meta/id
{
"Id": "bundle/openstack-3",
"Series": "bundle",
"Name": "openstack",
"Revision": 3
}GET id/meta/id-revision
The revision path returns information on the revision of the id. The
information is exactly that contained within the id.
type Revision struct {
Revision int
}Example: GET trusty/wordpress-42/meta/id-revision
{
"Revision": 42
}GET id/meta/id-name
The name path returns information on the name of the id. The information is
exactly that contained within the id.
type Name struct {
Name string
}Example: GET trusty/wordpress-42/meta/id-name
{
"Name": "wordpress"
}GET id/meta/id-user
The id-user path returns information on the user name in the id. This
information is exactly that contained within the id.
type User struct {
User string
}Example: GET ~bob/trusty/wordpress-42/meta/id-user
{
"User": "bob"
}Example: GET trusty/wordpress-42/meta/id-user
{
"User": ""
}GET id/meta/id-series
The id-series path returns information on the series in the id. This
information is exactly that contained within the id. For bundles, this will
return "bundle".
type Series struct {
Series string
}Example: GET ~bob/trusty/wordpress-42/meta/id-series
{
"Series": "trusty"
}Resources
Not yet implemented
POST id/resources/name.stream
Posting to the resources path creates a new version of the given stream for the charm with the given id. The request returns the new version.
type ResourcesRevision struct {
Revision int
}GET id/resources/name.stream[-revision]/arch/filename
Getting from the /resources path retrieves a charm resource from the charm
with the given id. If version is not specified, it retrieves the latest version
of the resource. The SHA-256 hash of the data is specified in the HTTP response
headers.
PUT id/resources/[~user/]series/name.stream-revision/arch?sha256=hash
Putting to the resources path uploads a resource (an arbitrary "blob" of
data) associated with the charm with id series/name, which must not be a
bundle. Stream and arch specify which of the charms resource streams and which
architecture the resource will be associated with, respectively. Revision
specifies the revision of the stream that's being uploaded to.
The hash value must specify the hash of the stream. If the same series, name, stream, revision combination is PUT again, it must specify the same hash.
Search
GET search
The search path searches within the latest version of charms and bundles
within the store.
GET search[?text=text][&autocomplete=1][&filter=value...][&limit=limit][&skip=skip][&include=meta[&include=meta...]][&sort=field]
text specifies any text to search for. If autocomplete is specified, the
search will return only charms and bundles with a name that has text as a
prefix. limit limits the number of returned items to the specified limit
count. skip skips over the first skip items in the result. Any number of
filters may be specified, limiting the search to items with attributes that
match the specified filter value. Items matching any of the selected values for
a filter are selected, so name=1&name=2 would match items whose name was
either 1 or 2. However, if multiple filters are specified, the charm must match
all of them, so name=1&series=2 will only match charms whose name is 1 and
whose series is 2. Available filters are:
- tags - the set of tags associated with the charm.
- name - the charm's name.
- owner - the charm's owner (the ~user element of the charm id)
- promulgated - the charm has been promulgated.
- provides - interfaces provided by the charm.
- requires - interfaces required by the charm.
- series - the charm's series.
- summary - the charm's summary text.
- description - the charm's description text.
- type - "charm" or "bundle" to search only one doctype or the other.
Notes
- filtering on a specified, but empty, owner is the same as filtering on promulgated=1.
- a specified, but empty text field will return all charms and bundles.
- the promulgated filter is only applied if specified. If the value is "1" then only promulgated entities are returned if it is any other value only non-promulgated entities are returned.
The response contains a list of information on the charms or bundles that were matched by the request. If no parameters are specified, all charms and bundles will match. By default, only the charm store id is included.
The results are sorted according to the given sort field, which may be one of
owner, name or series, corresponding to the filters of the same names. If
the field is prefixed with a hyphen (-), the sorting order will be reversed. If
the sort field is not specified, the results are returned in
most-relevant-first order if the text filter was specified, or an arbitrary
order otherwise. It is possible to specify more than one sort field to get
multi-level sorting, e.g. sort=name,-series will get charms in order of the
charm name and then in reverse order of series.
The Meta field is populated according to the include flag - see the meta
path for more info on how to use this.
[]SearchResult
type SearchResult struct {
Id string
// Meta holds at most one entry for each meta value
// specified in the include flags, holding the
// data that would be returned by reading /meta/meta?id=id.
// Metadata not relevant to a particular result will not
// be included.
Meta map[string] interface{} `json:",omitempty"`
}Example: GET search?text=word&autocomplete=1&limit=2&include=archive-size
[
{
"Id": "precise/wordpress-1",
"Meta": {
"archive-size": {
"Size": 1024
}
}
},
{
"Id": "precise/wordpress-2",
"Meta": {
"archive-size": {
"Size": 4242
}
}
}
]GET search/interesting
This returns a list of bundles and charms which are interesting from the Juju GUI perspective. Those are shown on the left sidebar of the GUI when no other search requests are performed.
GET search/interesting[?limit=limit][&include=meta]
The Meta field is populated according to the include flag - see the meta
path for more info on how to use this.
The limit flag is the same as for the "search" path.
Debug info
GET /debug
Not yet implemented
This returns metadata describing the current version of the software running the server, and any other information deemed appropriate. The specific form of the returned data is deliberately left unspecified for now.
GET /debug/status
Used as a health check of the service. The API will also be used for nagios tests. The items that are checked:
- connection to MongoDB
- connection to ElasticSearch (if needed) (based on charm config) (elasticsearch cluster status, all nodes up/etc see charmworld)
- number of charms and bundles in the blobstore
- number of promulgated items
- time and location of service start
- time of last ingestion process
- did ingestion finish
- did ingestion finished without errors (this should not count charm/bundle ingest errors)
type DebugStatuses map[string] struct {
Name string
Value string
Passed bool
}Example: GET /debug/status
{
"mongo_connected" : {
"Name": "MongoDB is connected",
"Value": "Connected",
"Passed": true
},
"mongo_collections" : {
"Name": "MongoDB collections",
"Value": "All required collections exist",
"Passed": true
},
"ES_connected": {
"Name": "ElasticSearch is connected",
"Value": "Connected",
"Passed": true
},
"entities": {
"Name": "Entities in charm store",
"Value": "5701 charms; 2000 bundles; 42 promulgated",
"Passed": true,
},
"server_started": {
"Name": "Server started",
"Value": "123.45.67.89 2014-09-16 11:12:29Z",
"Passed": true
},
}Permissions
All entities in the charm store have their own access control lists. Read and write permissions are supported for specific users and groups. By default, all charms and bundles are readable by everyone, meaning that anonymous users can retrieve archives and metadata information without restrictions. The permission endpoints can be used to retrieve or change entities' permissions.
GET id/meta/perm
This path reports the read and write ACLs for the charm or bundle.
type PermResponse struct {
Read []string
Write []string
}If the Read ACL is empty, the entity and its metadata cannot be retrieved by
anyone.
If the Write ACL is empty, the entity cannot be modified by anyone.
The special user everyone indicates that the corresponding operation
(read or write) can be performed by everyone, including anonymous users.
Example: GET ~joe/wordpress/meta/perm
{
"Read": ["everyone"],
"Write": ["joe"]
}PUT id/meta/perm
This request updates the permissions associated with the charm or bundle.
type PermResponse struct {
Read []string
Write []string
}If the Read or Write ACL is empty or missing from the request body, that field will be overwritten as empty. See the id/meta/perm/key request to PUT only Read or Write.
Example: PUT precise/wordpress-32/meta/perm
Request body:
{
"Read": ["everyone"],
"Write": ["joe"]
}GET id/meta/perm/key
This path returns the contents of the given permission key (that can be
read or write). The result is exactly the JSON value stored as a result of
the PUT request to meta/perm/key.
Example: GET wordpress/meta/perm/read
["everyone"]PUT id/meta/perm/key
This request updates the key permission associated with the charm or bundle,
where key can be read or write.
Example: PUT precise/wordpress-32/meta/perm/read
Request body:
["joe", "frank"]Authorization
GET /macaroon
This endpoint returns a macaroon in JSON format that, when its third party caveats are discharged, will allow access to the charm store. No prior authorization is required.
GET /delegatable-macaroon
This endpoint returns a macaroon in JSON format that can be passed to third parties to allow them to access the charm store on the user's behalf. A first party "is-entity" caveat may be added to restrict those parties so that they can only access a given charmstore entity with a specified id.
A delegatable macaroon will only be returned to an authorized user (not including admin). It will carry the same privileges as the macaroon used to authorize the request.
Logs
GET /log
This endpoint returns the log messages stored on the charm store. It is possible to save them by sending POST requests to the same endpoint (see below). For instance, the ingestion of charms/bundles produces logs that are collected and send to the charm store by the ingestion client.
GET /log[?limit=count][&skip=count][&id=entity-id][&level=log-level][&type=log-type]
Each log message is defined as:
type LogResponse struct {
// Data holds the log message as a JSON-encoded value.
Data json.RawMessage
// Level holds the log level as a string.
Level LogLevel
// Type holds the log type as a string.
Type LogType
// URLs holds a slice of entity URLs associated with the log message.
URLs []`*`charm.Reference `json:",omitempty"`
// Time holds the time of the log.
Time time.Time
}The log entries are ordered by last inserted (most recent logs first), and by
default the last 1000 logs are returned. Use the limit and skip query
parameters to change the default behavior. Logs can further be filtered by log
level (“info”, “warning” or “error”) and by related entity id. The type query
parameter groups entries by type. For instance, to request all the ingestion
errors related to the utopic/django charm, use the following URL:
/log?type=ingestion&level=error&id=utopic/django
POST /log
This endpoint uploads logs to the charm store. The request content type must be
application/json. The body must contain the JSON representation of a list of
logs, each one being in this format:
type Log struct {
// Data holds the log message as a JSON-encoded value.
Data *json.RawMessage
// Level holds the log level as a string.
Level LogLevel
// Type holds the log type as a string.
Type LogType
// URLs holds a slice of entity URLs associated with the log message.
URLs []*charm.Reference `json:",omitempty"`
}Nothing is returned if the request succeeds. Otherwise, an error is returned.
Changes
Each charm store has a global feed for all new published charms and bundles.
GET changes/published
This endpoint returns the ids of published charms or bundles published, most recently published first.
GET changes/published[?limit=count][&from=fromdate][&to=todate]
The fromdate and todate values constrain the range of publish dates, in
"yyyy-mm-dd" format. If fromdate is specified only charms published on or
after that date are returned; if todate is specified, only charms published
on or before that date are returned. If the limit count is specified, it must
be positive, and only the first count results are returned. The published time
is in RFC3339 format.
[]Published
type Published struct {
Id string
PublishTime time.Time
}Example: GET changes/published
[
{
"Id": "cs:trusty/wordpress-42",
"PublishTime": "2014-07-31T15:04:05Z"
},
{
"Id": "cs:trusty/mysql-11",
"PublishTime": "2014-07-30T14:20:00Z"
},
{
"Id": "cs:bundle/mediawiki",
"PublishTime": "2014-07-29T13:45:10Z"
}
]Example: GET changes/published?limit=10&from=31-07-2014
[
{
"Id": "cs:trusty/wordpress-42",
"PublishTime": "2014-07-31T15:04:05Z"
}
]