Skip to content

Latest commit

 

History

History
2608 lines (2062 loc) · 65.7 KB

API.md

File metadata and controls

2608 lines (2062 loc) · 65.7 KB

Charm store API

The current live API lives at https://api.jujucharms.com/charmstore/v5

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.URL 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.

Channels

Any entity in the charm store is considered to be part of one or more "channels" (think "distribution channels"). Currently supported channels are "unpublished", "edge" and "stable". All entities are initially (and always) part of the "unpublished" channel; subsequent operations on the publish endpoint can make entities available in other channels.

All requests that take one or more entity ids as parameters accept a "channel" query parameter that influences what channel is chosen to resolve the ids. The default channel is "stable".

For example, if wordpress-3 has just been published to the stable channel, and wordpress-4 has been published to the edge one, then a GET of wordpress/meta/id-revision?channel=edge will return {"Revision": 4} and a GET of wordpress/wordpress/meta/id-revision will return {"Revision": 3} because the default channel is "stable".

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 "v5" prefix. For example, the wordpress/meta/charm-metadata path is actually at v5/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": "trusty/wordpress-2"}
    {"Id": "trusty/wordpress-1"},
    {"Id": "precise/wordpress-2"},
    {"Id": "precise/wordpress-1"},
]

Example: GET precise/wordpress-34/expand-id

[
    {"Id": "trusty/wordpress-2"}
    {"Id": "trusty/wordpress-1"},
    {"Id": "precise/wordpress-2"},
    {"Id": "precise/wordpress-1"},
]

Getting all permissions

GET id/allperms

The allperms path returns all permissions associated with the charm. It requires an id with a user part and no revision, and returns the permissions associated with all revisions of that charm or bundle. If a channel is not specified in the request, permissions will be checked on the unpublished channel.

type PermResponse struct {
    Read  []string
    Write []string
}

type AllPerms struct {
	Perms map[string]PermResponse
}

Example: GET ~charmers/wordpress/allperms

{
	"Perms": {
		"stable": {
			"Read": ["everyone"],
			"Write": ["alice", "bob"]
		},
		"edge": {
			"Read": ["alice"],
			"Write": ["alice"]
		}
	}
}

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 any of the old or new entities are multi-series, then only the latest multi-series id will be aliased.

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 {
	Promulgated bool
}

Example: PUT ~charmers/precise/wordpress-23/promulgate

Request body:

{
    "Promulgate" : true,
}

Charm and bundle publishing

PUT id/publish

A PUT to the publish endpoint publishes the entity with the given id on the channels provided in the request body. It reports an error if there are no channels specified or if one of the channels is invalid (the "unpublished" channel is special and is also considered invalid in a publish request).

See the section on Channels in the introduction for how the published channels affects id resolving.

type PublishRequest struct {
    Channels []string
}

On success, the response body will be empty.

Example: PUT ~charmers/trusty/django-42/publish

Request body:

{
    "Channels" : ["stable"],
}

After the above request, ~charmers/trusty/django will resolve to ~charmers/trusty/django-42 unless a different channel is specified in the request.

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/archive-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/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.

PUT stats/update

This endpoint can be used to increase the stats related to an entity. This will increase the download stats by one for the entity provided and at the time stamp provided. It can for future purpose include the client issuing the requests. This is used when charmstore is in front of a cache server that will not call the real /archive endpoint and as such will not increase the download counts.

PUT stats/counter

Request body:

type StatsUpdateRequest struct {
	Timestamp      time.Time
	Type           string
	CharmReference *charm.URL
}

Example: PUT stats/update

Request body:

{
    "Timestamp":"2015-08-06T06:46:13Z",
    "Type":"deploy",
    "CharmReference":"cs:~charmers/utopic/wordpress-42"
}

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-metrics",
    "charm-related",
    "extra-info",
    "hash",
    "hash256",
    "id",
    "id-name",
    "id-revision",
    "id-series",
    "id-user",
    "manifest",
    "promulgated",
    "published",
    "revision-info",
    "stats",
    "supported-series",
    "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-metrics",
    "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 string

The 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/charm-metrics

The /meta/charm-metrics path returns the contents of the charm metrics file for a charm, or a 404 not found response if no metrics are defined for the charm. The id must refer to a charm, not a bundle.

// Metrics contains the metrics declarations encoded in the metrics.yaml file.
type Metrics struct {
    Metrics map[string]Metric
}

// Metric represents a single metric definition
type Metric struct {
    Type        string
    Description string
}

The possible values of a Metric Type are

  • gauge
  • absolute

Example: GET wordpress/meta/charm-metrics

{
    "Metrics": {
        "juju-units": {
            "Type": "absolute",
            "Description": "The units!"
        },
        "pings": {
            "Type": "gauge",
            "Description": "Description of the metric."
        }
    }
}

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 {
        Applications map[string] ApplicationSpec
        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 ApplicationSpec struct {
        Charm string
        NumUnits int
        To []string                      `json:",omitempty"`

        // Options holds the configuration values
        // to apply to the new application. 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

{
    "Applications": {
        "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/published

The meta/published path returns a list of the channels that the entity has been published to.

type PublishedResponse struct {
	// Info holds an entry for each channel that the
	// entity has been published to.
	Info []PublishedInfo
}

// PublishedInfo holds information on a channel that an entity
// has been published to.
type PublishedInfo struct {
	// Channel holds the value of the channel that
	// the entity has been published to.
	// This will never be "unpublished" as entities
	// cannot be published to that channel.
	Channel Channel

	// Current holds whether the entity is the most
	// recently published member of the channel.
	Current bool
}

GET id/meta/terms

The meta/terms path returns a list of terms and conditions (as recorded in the terms field of the charm metadata) the user must agree to in order to obtain the archive of the given charm id.

Example: GET some-charm/meta/terms

[
    "enterprise-terms/1",
    "special-terms/17"
]

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/supported-series

This path returns the set of series supported by the given charm. This endpoint is appropriate for charms only.

type SupportedSeriesResponse struct {
    SupportedSeries []string
}

Example: GET precise/wordpress/meta/supported-series

Response body:

{
    "SupportedSeries": ["precise"]
}

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

true

PUT 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. Any fields with null values are deleted.

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. If the value is null, the key is deleted.

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/can-ingest

The can-ingest path reports whether the entity with the given ID is eligible for ingestion. When an entity is manually uploaded (via the /archive endpoint with the POST method), it becomes ineligible for ingestion.

type CanIngestResponse struct {
	CanIngest bool
}

Example: GET trusty/wordpress-42/meta/can-ingest

{
	"CanIngest": false
}

GET id/meta/stats

GET id/meta/stats?[refresh=0|1]

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.
}

If the refresh boolean parameter is non-zero, the latest stats will be returned without caching.

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 RevisionInfoResponse struct {
        Revisions []*charm.URL
}

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 IdResponse struct {
        Id *charm.URL
        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"
}

GET id/meta/unpromulgated-id

The unpromulgated-id path is like meta/id but always returns the id with an owner - the canonical form of the charm or bundle id.

GET id/meta/promulgated-id

The promulgated-id path is like meta/id but if the entity has been promulgated, it returns the promulgated id (without owner). If the entity has never been promulgated, it returns a "metadata not found" error (or the entry is omitted when within a bulk metadata request).

GET id/meta/owner

The owner path returns information on the owner of the charm or bundle. This is the owner of the charm or bundle referenced by id irrespective of whether a user is included in the id.

type User struct {
        User string
}

Example: GET ~bob/trusty/wordpress-42/meta/owner

{
    "User": "bob"
}

Example: GET trusty/wordpress-42/meta/owner

{
    "User": "charmers"
}

GET id/meta/common-info

The meta/common-info path reports any common metadata recorded for the base entity. 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/common-info.

type CommonInfo struct {
        Values map[string] interface{}
}

Example: GET wordpress/meta/common-info GET precise/wordpress-32/meta/common-info

{
    "homepage": "http://wordpress.org",
    "bugs-url": "http://wordpress.org/bugs",
}

GET id/meta/common-info/key

This path returns the contents of the given common-info key. The result is exactly the JSON value stored as a result of the PUT request to common-info or common-info/key.

Example: GET wordpress/meta/common-info/homepage GET precise/wordpress-32/meta/common-info/homepage

"http://wordpress.org"

PUT id/meta/common-info

This request updates the value of any metadata values. Any values that are not mentioned in the request are left untouched. Any fields with null values are deleted.

Example: PUT precise/wordpress-32/meta/common-info

Request body:

{
    "bugs-url": "http://wordpress.org/newbugs",
}

PUT id/meta/common-info/key

This request creates or updates the value for a specific key. If the value is null, the key is deleted.

Example: PUT precise/wordpress-32/meta/common-info/bugs-url

Request body:

"http://wordpress.org/newbugs",

The above example is equivalent to the meta/common-info example above.

GET id/meta/resources

The meta/resources path returns information on all the resources associated with the given charm id as an array of resource objects.

If the resource exists in the charm metadata but has not been uploaded, the Revision, Fingerprint and Size fields will be -1, null and 0 respectively.

type Resource struct {
	// Name identifies the resource.
	Name string

	// Type is the name of the resource type. Currently only
	// "file" is supported, which is the default if Type is not specified.
	Type string

	// Path holds where the resource will be stored on units
	// deployed with the charm.
	Path string

	// Description contains user-facing info about the resource.
	Description string `json:",omitempty"`

	// Revision is the revision, if applicable.
	Revision int

	// Fingerprint is the SHA-384 checksum for the resource blob.
	Fingerprint []byte

	// Size is the size of the resource, in bytes.
	Size int64
}

[]Resource

GET id/meta/resources/name[/revision]

This endpoint retrieves information on the resource with the given name associated with the charm id as a resource object (see above).

If revision is omitted, information on the latest revision of the resource is returned.

If the resource exists in the charm metadata but has not been uploaded, the Revision, Fingerprint and Size fields will be -1, null and 0 respectively.

Resources

POST id/resource/name?[hash=sha384][&filename=path][&upload-id=uploadid]

Posting to the resource path uploads a resource (an arbitrary "blob" of data) associated with the charm with the given id, which must not be a bundle. The sha384 parameter must hold the hex-encoded SHA384 hash of the blob unless uploadid is specified.

If provided, the path parameter should hold the filename that the resource has been read from, and its file extension will be verified against the extension of the filename in the declared charm metadata resources of the resolved charm.

As a special case, if the filename in the charm metadata has no extension, any file name will be allowed.

If upload-id is specified, it should refer to an already-uploaded blob (see the Uploads section in this document) and the hash parameter does not need to be specified, otherwise the resource will be read from the body of the HTTP request.

type ResourcesRevision struct {
        Revision int
}

GET id/resource/name[/revision]

Getting from the /resource path retrieves a charm resource from the charm with the given id. If version is not specified, it retrieves the latest published version of the resource (for the "unpublished" channel, this will be the most recently uploaded version of the resource).

The SHA-384 checksum of the data is returned in the Content-Sha384 HTTP response header.

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

  1. filtering on a specified, but empty, owner is the same as filtering on promulgated=1.
  2. a specified, but empty text field will return all charms and bundles.
  3. 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.

List

GET list

The list path lists charms and bundles within the store.

GET list[?filter=value...][&include=meta[&include=meta...]][&sort=field]

Any number of filters may be specified, limiting the list 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:

  • name - the charm's name.
  • owner - the charm's owner (the ~user element of the charm id)
  • promulgated - the charm has been promulgated.
  • series - the charm's series.
  • type - "charm" or "bundle" to search only one doctype or the other.

Notes

  1. 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 order will be a server side logical order. 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.

[]EntityResult

type EntityResult 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 list?name=wordpress&include=archive-size

[
    {
        "Id": "precise/wordpress-1",
        "Meta": {
            "archive-size": {
                "Size": 1024
            }
        }
    },
    {
        "Id": "precise/wordpress-2",
        "Meta": {
            "archive-size": {
                "Size": 4242
            }
        }
    }
]

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/can-write

This path reports whether the client has permission to modify the charm, including uploading new revisions of the charm and attaching resources.

type CanWriteResponse struct {
	CanWrite bool
}

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. If the "id" parameter is specified (url encoded), the returned macaroon will be restricted for use only with the entity with the given 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, but is suitable for use by third parties.

GET /whoami

This endpoint returns the user name of the client and the list of groups the user is a member of. This endpoint requires authorization.

Example: GET whoami

{
    "User": "alice",
    "Groups": ["charmers", "admin", "team-awesome"]
}

The response is defined as:

type WhoAmIResponse struct {
    User string
    Groups []string
}

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.URL `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.URL `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][&start=fromdate][&stop=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&start=31-07-2014

[
    {
        "Id": "cs:trusty/wordpress-42",
        "PublishTime": "2014-07-31T15:04:05Z"
    }
]

Uploads

When uploading a large resource to a charm, it can be unreliable to do it in a single HTTP request, so the charm store provides a way to upload the data as a set of parts that are then stitched together to make the whole resource.

POST /upload[?expires=expires]

This endpoint starts an upload. If the uploaded data is not used within the given expiry duration, it will be discarded. If the expiry duration is greater than some maximum (currently 24 hours), it will be limited to that maximum. The duration is in a format acceptable to Go's time.ParseDuration function (e.g. "8h", "5m3s").

The response holds a JSON object containing information about the upload.

type UploadInfoResponse struct {
	// UploadId holds the id of the upload.
	UploadId string

	// Parts holds all the known parts of the upload.
	// Parts that haven't been uploaded yet will have nil
	// elements.
	Parts Parts

	// Expires holds when the upload id expires (encoded
	// in RFC3339 format).
	Expires time.Time

	// MinPartSize holds the minimum size of a part that may
	// be uploaded (not including the last part).
	MinPartSize int64

	// MaxPartSize holds the maximum size of a part that may
	// be uploaded.
	MaxPartSize int64

	// MaxParts holds the maximum number of parts.
	MaxParts int
}

Once an upload has been started, all its parts should be uploaded (they do not have to be uploaded in order), and then finished with a PUT to /upload/uploadid before the upload can be used to attach a resource to a charm.

Example: `POST /v5/upload

{
	UploadId: "WLQfoTqvbCHcVojo",
	Expires: "2017-02-28T12:46:25.878Z",
	MinPartSize: 5242880,
	MaxPartSize: 4294967295,
	MaxParts: 400,
	Parts: {Parts: []}
}

PUT /upload/uploadid/part?hash=sha384

This endpoint uploads a single part with the given part number part to the upload with the given uploadid. The hash parameter must specify the SHA384 hash of the uploaded part in hexadecimal format. The data is read from the request body. The request must specify the size of the data in its Content-Length header.

PUT /upload/uploadid

This endpoint completes an upload. The body should contain a JSON object holding the hashes of all the parts that have been uploaded. Once this request has completed successfully, the upload can be used as a resource.

type Parts struct {
	Parts []Part
}

// Part represents one part of a multipart blob.
type Part struct {
	// SHA384 hash of part (hex-encoded).
	Hash string
}

The response will return the hash of all the data in all the uploaded parts.

type FinishUploadResponse struct {
	// Hash holds the SHA384 hash of the complete blob. (hex-encoded)
	Hash string
}

GET /upload/uploadid

This endpoint retrieve an upload info from the given uploadid started with a POST /upload. If the upload is not found, this will results in a 404.

The response holds a JSON object containing information about the upload.

type UploadInfoResponse struct {
	// UploadId holds the id of the upload.
	UploadId string

	// Parts holds all the known parts of the upload.
	// Parts that haven't been uploaded yet will have all fields zero (not present).
	Parts Parts

    // Expires holds when the upload id expires (encoded
    // in RFC3339 format).
	Expires time.Time

	// MinPartSize holds the minimum size of a part that may
	// be uploaded (not including the last part).
	MinPartSize int64

	// MaxPartSize holds the maximum size of a part that may
	// be uploaded.
	MaxPartSize int64

	// MaxParts holds the maximum number of parts.
	MaxParts int
}

Once an upload has been started, all its parts that have been uploaded will be describe as well as the expiry time of this upload document.

Example: `GET /v5/upload/1234

{
	Expires: "2017-02-28T12:46:25.878Z",
	Parts: {Parts: [
	  {
        Hash: "8763245979",
        Size: "52442880",
        Complete: true
	  } , {}, {
        Hash: "4365432652435",
        Size: "324434",
        Complete: true
	  }
	]},
	MinPartSize: 5242880,
	MaxPartSize: 4294967295,
	MaxParts: 400,
	UploadId: "1234"
}