diff --git a/CNAME b/CNAME new file mode 100644 index 000000000..0da558c57 --- /dev/null +++ b/CNAME @@ -0,0 +1,2 @@ +www.drycc.cc +drycc.cc diff --git a/README.md b/README.md new file mode 100644 index 000000000..bbb184163 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Workflow Contrib + +Scripts and tools that are not a core part of Drycc Workflow v2. diff --git a/_includes/install-workflow/index.html b/_includes/install-workflow/index.html new file mode 100644 index 000000000..b9ca82617 --- /dev/null +++ b/_includes/install-workflow/index.html @@ -0,0 +1,897 @@ + + + + + + + + + + + + + + + + + + Install workflow - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Check Your Setup

+

First check that the helm command is available and the version is v2.5.0 or newer.

+
$ helm version
+Client: &version.Version{SemVer:"v2.5.0", GitCommit:"012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6", GitTreeState:"clean"}
+Server: &version.Version{SemVer:"v2.5.0", GitCommit:"012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6", GitTreeState:"clean"}
+ + +

Ensure the kubectl client is installed and can connect to your Kubernetes cluster.

+

Install Drycc Workflow

+

Now that Helm is installed and the repository has been added, install Workflow by running:

+
$ helm install drycc oci://registry.drycc.cc/charts/workflow --namespace drycc
+ + +

Helm will install a variety of Kubernetes resources in the drycc namespace. +Wait for the pods that Helm launched to be ready. Monitor their status by running:

+
$ kubectl --namespace=drycc get pods
+ + +

If it's preferred to have kubectl automatically update as the pod states change, run (type Ctrl-C to stop the watch):

+
$ kubectl --namespace=drycc get pods -w
+ + +

Depending on the order in which the Workflow components initialize, some pods may restart. This is common during the +installation: if a component's dependencies are not yet available, that component will exit and Kubernetes will +automatically restart it.

+

Here, it can be seen that the controller, builder and registry all took a few loops before they were able to start:

+
$ kubectl --namespace=drycc get pods
+NAME                          READY     STATUS    RESTARTS   AGE
+drycc-builder-hy3xv            1/1       Running   5          5m
+drycc-controller-g3cu8         1/1       Running   5          5m
+drycc-controller-celery-cmxxn  3/3       Running   0          5m
+drycc-database-rad1o           1/1       Running   0          5m
+drycc-logger-fluentbit-1v8uk   1/1       Running   0          5m
+drycc-logger-fluentbit-esm60   1/1       Running   0          5m
+drycc-logger-sm8b3             1/1       Running   0          5m
+drycc-storage-4ww3t            1/1       Running   0          5m
+drycc-registry-asozo           1/1       Running   1          5m
+drycc-rabbitmq-0               1/1       Running   0          5m
+ + +

Once all of the pods are in the READY state, Drycc Workflow is up and running!

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/deploying-apps/index.html b/applications/deploying-apps/index.html new file mode 100644 index 000000000..80954b55f --- /dev/null +++ b/applications/deploying-apps/index.html @@ -0,0 +1,946 @@ + + + + + + + + + + + + + + + + + + Deploying Apps - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Deploying an Application

+

An Application is deployed to Drycc using git push or the drycc client.

+

Supported Applications

+

Drycc Workflow can deploy any application or service that can run inside a container. In order to be scaled +horizontally, applications must follow the Twelve-Factor App methodology and store any application state in external +backing services.

+

For example, if your application persists state to the local filesystem -- common with content management systems like +Wordpress and Drupal -- it cannot be scaled horizontally using drycc scale.

+

Fortunately, most modern applications feature a stateless application tier that can scale horizontally inside Drycc.

+

Login to the Controller

+
+

Important

+

if you haven't yet, now is a good time to install the client and register.

+
+

Before deploying an application, users must first authenticate against the Drycc Controller +using the URL supplied by their Drycc administrator.

+
$ drycc login http://drycc.example.com
+Opening browser to http://drycc.example.com/v2/login/drycc/?key=4ccc81ee2dce4349ad5261ceffe72c71
+Waiting for login... .o.Logged in as admin
+Configuration file written to /root/.drycc/client.json
+ + +

Select a Build Process

+

Drycc Workflow supports three different ways of building applications:

+

Buildpacks

+

Cloud Native Buildpacks are useful if you want to follow cnb's docs for building applications.

+

Learn how to deploy applications using Buildpacks.

+

Dockerfiles

+

Dockerfiles are a powerful way to define a portable execution environment built on a base OS of your choosing.

+

Learn how to deploy applications using Dockerfiles.

+

Container Image

+

Deploying a Container image onto Drycc allows you to take a Container image from either a public +or a private registry and copy it over bit-for-bit, ensuring that you are running the same +image in development or in your CI pipeline as you are in production.

+

Learn how to deploy applications using Container images.

+

Tuning Application Settings

+

It is possible to configure a few of the globally tunable settings on per application basis using config:set.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SettingDescription
DRYCC_DISABLE_CACHEif set, this will disable the [imagebuilder cache][] (default: not set)
DRYCC_DEPLOY_BATCHESthe number of pods to bring up and take down sequentially during a scale (default: number of available nodes)
DRYCC_DEPLOY_TIMEOUTdeploy timeout in seconds per deploy batch (default: 120)
IMAGE_PULL_POLICYthe kubernetes [image pull policy][pull-policy] for application images (default: "IfNotPresent") (allowed values: "Always", "IfNotPresent")
KUBERNETES_DEPLOYMENTS_REVISION_HISTORY_LIMIThow many revisions Kubernetes keeps around of a given Deployment (default: all revisions)
KUBERNETES_POD_TERMINATION_GRACE_PERIOD_SECONDShow many seconds kubernetes waits for a pod to finish work after a SIGTERM before sending SIGKILL (default: 30)
+

Deploy Timeout

+

Deploy timeout in seconds - There are 2 deploy methods, Deployments (see below) and RC (versions prior to 2.4) and this setting affects those a bit differently.

+

Deployments

+

Deployments behave a little bit differently from the RC based deployment strategy.

+

Kubernetes takes care of the entire deploy, doing rolling updates in the background. As a result, there is only an overall deployment timeout instead of a configurable per-batch timeout.

+

The base timeout is multiplied with DRYCC_DEPLOY_BATCHES to create an overall timeout. This would be 240 (timeout) * 4 (batches) = 960 second overall timeout.

+

RC deploy

+

This deploy timeout defines how long to wait for each batch to complete in DRYCC_DEPLOY_BATCHES.

+

Additions to the base timeout

+

The base timeout is extended as well with healthchecks using initialDelaySeconds on liveness and readiness where the bigger of those two is applied. +Additionally the timeout system accounts for slow image pulls by adding an additional 10 minutes when it has seen an image pull take over 1 minute. This allows the timeout values to be reasonable without having to account for image pull slowness in the base deploy timeout.

+

Deployments

+

Workflow uses Deployments for deploys. In prior versions ReplicationControllers were used with the ability to turn on Deployments via DRYCC_KUBERNETES_DEPLOYMENTS=1.

+

The advantage of Deployments is that rolling-updates will happen server-side in Kubernetes instead of in Drycc Workflow Controller, +along with a few other Pod management related functionality. This allows a deploy to continue even when the CLI connection is interrupted.

+

Behind the scenes your application deploy will be built up of a Deployment object per process type, +each having multiple ReplicaSets (one per release) which in turn manage the Pods running your application.

+

Drycc Workflow will behave the same way with DRYCC_KUBERNETES_DEPLOYMENTS enabled or disabled (only applicable to versions prior to 2.4). +The changes are behind the scenes. Where you will see differences while using the CLI is drycc ps:list will output Pod names differently.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/domains-and-routing/index.html b/applications/domains-and-routing/index.html new file mode 100644 index 000000000..b829e8de7 --- /dev/null +++ b/applications/domains-and-routing/index.html @@ -0,0 +1,888 @@ + + + + + + + + + + + + + + + + + + Domains and Routing - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Domains and Routing

+

You can use drycc domains to add or remove custom domains to the application:

+
$ drycc domains:add hello.bacongobbler.com
+Adding hello.bacongobbler.com to finest-woodshed... done
+ + +

Once that's done, you can go into a DNS registrar and set up a CNAME from the new +appname to the old one:

+
$ dig hello.dryccapp.com
+[...]
+;; ANSWER SECTION:
+hello.bacongobbler.com.         1759    IN    CNAME    finest-woodshed.dryccapp.com.
+finest-woodshed.dryccapp.com.    270     IN    A        172.17.8.100
+ + +
+

Note

+

Setting a CNAME for a root domain can cause issues. Setting an @ record +to be a CNAME causes all traffic to go to the other domain, including mail and the SOA +("start-of-authority") records. It is highly recommended that you bind a subdomain to +an application, however you can work around this by pointing the @ record to the +address of the load balancer (if any).

+
+

To add or remove the application from the routing mesh, use drycc routing:

+
$ drycc routing:disable
+Disabling routing for finest-woodshed... done
+ + +

This will make the application unreachable through the Router, but the application is still +reachable internally through its Kubernetes Service. To re-enable routing:

+
$ drycc routing:enable
+Enabling routing for finest-woodshed... done
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/inter-app-communication/index.html b/applications/inter-app-communication/index.html new file mode 100644 index 000000000..bf9406b32 --- /dev/null +++ b/applications/inter-app-communication/index.html @@ -0,0 +1,860 @@ + + + + + + + + + + + + + + + + + + Inter-app Communication - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Inter-app Communication

+

A common architecture pattern of multi-process applications is to have one process serve public requests while having multiple other processes supporting the public one to, for example, perform actions on a schedule or process work items from a queue. To implement this system of apps in Drycc Workflow, set up the apps to communicate using DNS resolution, as shown above, and hide the supporting processes from public view by removing them from the Drycc Workflow router.

+

DNS Service Discovery

+

Drycc Workflow supports deploying a single app composed of a system of processes. Each Drycc Workflow app communicates on a single port, so communicating with another Workflow app means finding that app's address and port. All Workflow apps are mapped to port 80 externally, so finding its IP address is the only challenge. Workflow creates a Kubernetes Service for each app, which effectively assigns a name and one cluster-internal IP address to an app. The DNS service running in the cluster adds and removes DNS records which point from the app name to its IP address as services are added and removed. Drycc Workflow apps, then, can simply send requests to the domain name given to the service, which is "app-name.app-namespace".

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/managing-app-configuration/index.html b/applications/managing-app-configuration/index.html new file mode 100644 index 000000000..4b6f68c55 --- /dev/null +++ b/applications/managing-app-configuration/index.html @@ -0,0 +1,1043 @@ + + + + + + + + + + + + + + + + + + Managing App Configuration - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Configuring an Application

+

A Drycc application stores config in environment variables.

+

Setting Environment Variables

+

Use drycc config to modify environment variables for a deployed application.

+
$ drycc help config
+Valid commands for config:
+
+config:list        list environment variables for an app
+config:set         set environment variables for an app
+config:unset       unset environment variables for an app
+config:pull        extract environment variables to .env
+config:push        set environment variables from .env
+
+Use `drycc help [command]` to learn more.
+ + +

When config is changed, a new release is created and deployed automatically.

+

You can set multiple environment variables with one drycc config:set command, +or with drycc config:push and a local .env file.

+
$ drycc config:set FOO=1 BAR=baz && drycc config:pull
+$ cat .env
+FOO=1
+BAR=baz
+$ echo "TIDE=high" >> .env
+$ drycc config:push
+Creating config... done, v4
+
+=== yuppie-earthman
+DRYCC_APP: yuppie-earthman
+FOO: 1
+BAR: baz
+TIDE: high
+ + +

Attach to Backing Services

+

Drycc treats backing services like databases, caches and queues as attached resources. +Attachments are performed using environment variables.

+

For example, use drycc config to set a DATABASE_URL that attaches +the application to an external PostgreSQL database.

+
$ drycc config:set DATABASE_URL=postgres://user:pass@example.com:5432/db
+=== peachy-waxworks
+DATABASE_URL: postgres://user:pass@example.com:5432/db
+ + +

Detachments can be performed with drycc config:unset.

+

Buildpacks Cache

+

By default, apps using the [Imagebuilder][] will reuse the latest image data. +When deploying applications that depend on third-party libraries that have to be fetched, +this could speed up deployments a lot. In order to make use of this, the buildpack must implement +the cache by writing to the cache directory. Most buildpacks already implement this, but when using +custom buildpacks, it might need to be changed to make full use of the cache.

+

Disabling and re-enabling the cache

+

In some cases, cache might not speed up your application. To disable caching, you can set the +DRYCC_DISABLE_CACHE variable with drycc config:set DRYCC_DISABLE_CACHE=1. When you disable the +cache, Drycc will clear up files it created to store the cache. After having it turned off, run +drycc config:unset DRYCC_DISABLE_CACHE to re-enable the cache.

+

Clearing the cache

+

Use the following procedure to clear the cache:

+
$ drycc config:set DRYCC_DISABLE_CACHE=1
+$ git commit --allow-empty -m "Clearing Drycc cache"
+$ git push drycc # (if you use a different remote, you should use your remote name)
+$ drycc config:unset DRYCC_DISABLE_CACHE
+ + +

Custom Health Checks

+

By default, Workflow only checks that the application starts in their Container. If it is preferred +to have Kubernetes respond to application health, a health check may be added by configuring a +health check probe for the application.

+

The health checks are implemented as Kubernetes container probes. A liveness +and a readiness probe can be configured, and each probe can be of type httpGet, exec, or +tcpSocket depending on the type of probe the container requires.

+

A liveness probe is useful for applications running for long periods of time, eventually +transitioning to broken states and cannot recover except by restarting them.

+

Other times, a readiness probe is useful when the container is only temporarily unable to serve, +and will recover on its own. In this case, if a container fails its readiness probe, the container +will not be shut down, but rather the container will stop receiving incoming requests.

+

httpGet probes are just as it sounds: it performs a HTTP GET operation on the Container. A +response code inside the 200-399 range is considered a pass.

+

exec probes run a command inside the Container to determine its health, such as +cat /var/run/myapp.pid or a script that determines when the application is ready. An exit code of +zero is considered a pass, while a non-zero status code is considered a fail.

+

tcpSocket probes attempt to open a socket in the Container. The Container is only considered +healthy if the check can establish a connection. tcpSocket probes accept a port number to perform +the socket connection on the Container.

+

Health checks can be configured on a per-proctype basis for each application using drycc healthchecks:set. If no type is mentioned then the health checks are applied to default proc types, web or cmd, whichever is present. To +configure a httpGet liveness probe:

+
$ drycc healthchecks:set liveness httpGet 80 --type cmd
+=== peachy-waxworks Healthchecks
+
+cmd:
+Liveness
+--------
+Initial Delay (seconds): 50
+Timeout (seconds): 50
+Period (seconds): 10
+Success Threshold: 1
+Failure Threshold: 3
+Exec Probe: N/A
+HTTP GET Probe: Path="/" Port=80 HTTPHeaders=[]
+TCP Socket Probe: N/A
+
+Readiness
+---------
+No readiness probe configured.
+ + +

If the application relies on certain headers being set (such as the Host header) or a specific +URL path relative to the root, you can also send specific HTTP headers:

+
$ drycc healthchecks:set liveness httpGet 80 \
+    --path /welcome/index.html \
+    --headers "X-Client-Version:v1.0,X-Foo:bar"
+=== peachy-waxworks Healthchecks
+
+web/cmd:
+Liveness
+--------
+Initial Delay (seconds): 50
+Timeout (seconds): 50
+Period (seconds): 10
+Success Threshold: 1
+Failure Threshold: 3
+Exec Probe: N/A
+HTTP GET Probe: Path="/welcome/index.html" Port=80 HTTPHeaders=[X-Client-Version=v1.0]
+TCP Socket Probe: N/A
+
+Readiness
+---------
+No readiness probe configured.
+ + +

To configure an exec readiness probe:

+
$ drycc healthchecks:set readiness exec -- /bin/echo -n hello --type cmd
+=== peachy-waxworks Healthchecks
+
+cmd:
+Liveness
+--------
+No liveness probe configured.
+
+Readiness
+---------
+Initial Delay (seconds): 50
+Timeout (seconds): 50
+Period (seconds): 10
+Success Threshold: 1
+Failure Threshold: 3
+Exec Probe: Command=[/bin/echo -n hello]
+HTTP GET Probe: N/A
+TCP Socket Probe: N/A
+ + +

You can overwrite a probe by running drycc healthchecks:set again:

+
$ drycc healthchecks:set readiness httpGet 80 --type cmd
+=== peachy-waxworks Healthchecks
+
+cmd:
+Liveness
+--------
+No liveness probe configured.
+
+Readiness
+---------
+Initial Delay (seconds): 50
+Timeout (seconds): 50
+Period (seconds): 10
+Success Threshold: 1
+Failure Threshold: 3
+Exec Probe: N/A
+HTTP GET Probe: Path="/" Port=80 HTTPHeaders=[]
+TCP Socket Probe: N/A
+ + +

Configured health checks also modify the default application deploy behavior. When starting a new +Pod, Workflow will wait for the health check to pass before moving onto the next Pod.

+

Isolate the Application

+

Workflow supports isolating applications onto a set of nodes using drycc tags.

+
+

Note

+

In order to use tags, you must first launch your cluster with the proper node labels. If you do +not, tag commands will fail. Learn more by reading "Assigning Pods to Nodes".

+
+

Once your nodes are configured with appropriate label selectors, use drycc tags:set to restrict +the application to those nodes:

+
$ drycc tags:set environ=prod
+Applying tags...  done, v4
+
+environ  prod
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/managing-app-gateway/index.html b/applications/managing-app-gateway/index.html new file mode 100644 index 000000000..5147f8d6f --- /dev/null +++ b/applications/managing-app-gateway/index.html @@ -0,0 +1,864 @@ + + + + + + + + + + + + + + + + + + Managing App Gateway - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

About gateway for an Application

+

A Gateway describes how traffic can be translated to Services within the cluster. That is, it defines a request for a way to translate traffic from somewhere that does not know about Kubernetes to somewhere that does. For example, traffic sent to a Kubernetes Service by a cloud load balancer, an in-cluster proxy, or an external hardware load balancer. While many use cases have client traffic originating “outside” the cluster, this is not a requirement.

+

Create Gateway for an Application

+

Gateway is a way of exposing services externally, which generates an external IP address to connect route and service.

+

Create service for an Application

+

Service is a way of exposing services internally, creating a service generates an internal DNS that can access procfile_type.

+

Create Route for an Application

+

A Gateway may be attached to one or more Route references which serve to direct traffic for a subset of traffic to a specific service.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/managing-app-lifecycle/index.html b/applications/managing-app-lifecycle/index.html new file mode 100644 index 000000000..c97f98682 --- /dev/null +++ b/applications/managing-app-lifecycle/index.html @@ -0,0 +1,952 @@ + + + + + + + + + + + + + + + + + + Managing App Lifecycle - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Managing an Application

+

Track Application Changes

+

Drycc Workflow tracks all changes to your application. Application changes are the result of either new application code +pushed to the platform (via git push drycc master), or an update to application configuration (via drycc config:set KEY=VAL).

+

Each time a build or config change is made to your application a new release is created. These release numbers +increase monotonically.

+

You can see a record of changes to your application using drycc releases:

+
$ drycc releases
+=== peachy-waxworks Releases
+v4      3 minutes ago                     gabrtv deployed d3ccc05
+v3      1 hour 17 minutes ago             gabrtv added DATABASE_URL
+v2      6 hours 2 minutes ago             gabrtv deployed 7cb3321
+v1      6 hours 2 minutes ago             gabrtv deployed drycc/helloworld
+ + +

Rollback a Release

+

Drycc Workflow also supports rolling back go previous releases. If buggy code or an errant configuration change is pushed +to your application, you may rollback to a previously known, good release.

+
+

Note

+

All rollbacks create a new, numbered release. But will reference the build/code and configuration from the desired rollback point.

+
+

In this example, the application is currently running release v4. Using drycc rollback v2 tells Workflow to deploy the +build and configuration that was used for release v2. This creates a new release named v5 whose contents are the source +and configuration from release v2:

+
$ drycc releases
+=== folksy-offshoot Releases
+v4      4 minutes ago                     gabrtv deployed d3ccc05
+v3      1 hour 18 minutes ago             gabrtv added DATABASE_URL
+v2      6 hours 2 minutes ago             gabrtv deployed 7cb3321
+v1      6 hours 3 minutes ago             gabrtv deployed drycc/helloworld
+
+$ drycc rollback v2
+Rolled back to v2
+
+$ drycc releases
+=== folksy-offshoot Releases
+v5      Just now                          gabrtv rolled back to v2
+v4      4 minutes ago                     gabrtv deployed d3ccc05
+v3      1 hour 18 minutes ago             gabrtv added DATABASE_URL
+v2      6 hours 2 minutes ago             gabrtv deployed 7cb3321
+v1      6 hours 3 minutes ago             gabrtv deployed drycc/helloworld
+ + +

Run One-off Administration Tasks

+

Drycc applications use one-off processes for admin tasks like database migrations and other commands that must run against the live application.

+

Use drycc run to execute commands on the deployed application.

+
$ drycc run 'ls -l'
+Running `ls -l`...
+
+total 28
+-rw-r--r-- 1 root root  553 Dec  2 23:59 LICENSE
+-rw-r--r-- 1 root root   60 Dec  2 23:59 Procfile
+-rw-r--r-- 1 root root   33 Dec  2 23:59 README.md
+-rw-r--r-- 1 root root 1622 Dec  2 23:59 pom.xml
+drwxr-xr-x 3 root root 4096 Dec  2 23:59 src
+-rw-r--r-- 1 root root   25 Dec  2 23:59 system.properties
+drwxr-xr-x 6 root root 4096 Dec  3 00:00 target
+ + +

Share an Application

+

Use drycc perms:create to allow another Drycc user to collaborate on your application.

+
$ drycc perms:create otheruser
+Adding otheruser to peachy-waxworks collaborators... done
+ + +

Use drycc perms to see who an application is currently shared with, and drycc perms:delete to remove a collaborator.

+
+

Note

+

Collaborators can do anything with an application that its owner can do, except delete the application.

+
+

When working with an application that has been shared with you, clone the original repository and add Drycc' git remote +entry before attempting to git push any changes to Drycc.

+
$ git clone https://github.com/drycc/example-java-jetty.git
+Cloning into 'example-java-jetty'... done
+$ cd example-java-jetty
+$ git remote add -f drycc ssh://git@local3.dryccapp.com:2222/peachy-waxworks.git
+Updating drycc
+From drycc-controller.local:peachy-waxworks
+ * [new branch]      master     -> drycc/master
+ + +

Application Troubleshooting

+

Applications deployed on Drycc Workflow treat logs as event streams. Drycc Workflow aggregates stdout and stderr +from every Container making it easy to troubleshoot problems with your application.

+

Use drycc logs to view the log output from your deployed application.

+
$ drycc logs -f
+Dec  3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.5]: INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null}
+Dec  3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.8]: INFO:oejs.Server:jetty-7.6.0.v20120127
+Dec  3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.5]: INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:10005
+Dec  3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.6]: INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null}
+Dec  3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.7]: INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null}
+Dec  3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.6]: INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:10006
+Dec  3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.8]: INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null}
+Dec  3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.7]: INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:10007
+Dec  3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.8]: INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:10008
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/managing-app-processes/index.html b/applications/managing-app-processes/index.html new file mode 100644 index 000000000..84916b361 --- /dev/null +++ b/applications/managing-app-processes/index.html @@ -0,0 +1,1088 @@ + + + + + + + + + + + + + + + + + + Managing App Processes - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Managing Application Processes

+

Drycc Workflow manages your application as a set of processes that can be named, scaled and configured according to their +role. This gives you the flexibility to easily manage the different facets of your application. For example, you may have +web-facing processes that handle HTTP traffic, background worker processes that do async work, and a helper process that +streams from the Twitter API.

+

By using a Procfile, either checked in to your application or provided via the CLI you can specify the name of the type +and the application command that should run. To spawn other process types, use drycc scale <type>=<n> to scale those +types accordingly.

+

Default Process Types

+

In the absence of a Procfile, a single, default process type is assumed for each application.

+

Applications built using Buildpacks via git push implicitly receive a web process type, which starts +the application server. Rails 4, for example, has the following process type:

+
web: bundle exec rails server -p $PORT
+ + +

All applications utilizing Dockerfiles have an implied cmd process type, which runs the +Dockerfile's CMD directive unmodified:

+
$ cat Dockerfile
+FROM centos:latest
+COPY . /app
+WORKDIR /app
+CMD python -m SimpleHTTPServer 5000
+EXPOSE 5000
+ + +

For the above Dockerfile-based application, the cmd process type would run the Container CMD of python -m SimpleHTTPServer 5000.

+

Applications utilizing remote Container images, a cmd process type is also implied, and runs the CMD +specified in the Container image.

+
+

Note

+

The web and cmd process types are special as they’re the only process types that will +receive HTTP traffic from Workflow’s routers. Other process types can be named arbitrarily.

+
+

Declaring Process Types

+

If you use Buildpack or Dockerfile builds and want to override or specify additional process +types, simply include a file named Procfile in the root of your application's source tree.

+

The format of a Procfile is one process type per line, with each line containing the command to invoke:

+
<process type>: <command>
+ + +

The syntax is defined as:

+
    +
  • <process type> – a lowercase alphanumeric string, is a name for your command, such as web, worker, urgentworker, clock, etc.
  • +
  • <command> – a command line to launch the process, such as rake jobs:work.
  • +
+

This example Procfile specifies two types, web and sleeper. The web process launches a web server on port 5000 and +a simple process which sleeps for 900 seconds and exits.

+
$ cat Procfile
+web: bundle exec ruby web.rb -p ${PORT:-5000}
+sleeper: sleep 900
+ + +

If you are using remote Container images, you may define process types by either running drycc pull with a +Procfile in your working directory, or by passing a stringified Procfile to the --procfile CLI option.

+

For example, passing process types inline:

+
$ drycc pull drycc/example-go:latest --procfile="cmd: /app/bin/boot"
+ + +

Read a Procfile in another directory:

+
$ drycc pull drycc/example-go:latest --procfile="$(cat deploy/Procfile)"
+ + +

Or via a Procfile located in your current, working directory:

+
$ cat Procfile
+cmd: /bin/boot
+sleeper: echo "sleeping"; sleep 900
+
+
+$ drycc pull -a steely-mainsail drycc/example-go
+Creating build... done
+
+$ drycc scale sleeper=1 -a steely-mainsail
+Scaling processes... but first, coffee!
+done in 0s
+=== steely-mainsail Processes
+--- cmd (started): 1
+steely-mainsail-cmd-3291896318-nyrim up (v3)
+--- sleeper (started): 1
+steely-mainsail-sleeper-3291896318-oq1jr up (v3)
+ + +
+

Note

+

Only process types of web and cmd will be scaled to 1 automatically. If you have additional process types +remember to scale the process counts after creation.

+
+

To remove a process type simply scale it to 0:

+
$ drycc scale sleeper=0 -a steely-mainsail
+Scaling processes... but first, coffee!
+done in 3s
+=== steely-mainsail Processes
+--- cmd (started): 1
+steely-mainsail-cmd-3291896318-nyrim up (v3)
+--- sleeper (started): 0
+ + +

Scaling Processes

+

Applications deployed on Drycc Workflow scale out via the process model. Use drycc scale to control the number of +containers that power your app.

+
$ drycc scale cmd=5 -a iciest-waggoner
+Scaling processes... but first, coffee!
+done in 3s
+=== iciest-waggoner Processes
+--- cmd (started): 5
+iciest-waggoner-web-3291896318-09j0o up (v2)
+iciest-waggoner-web-3291896318-3r7kp up (v2)
+iciest-waggoner-web-3291896318-gc4xv up (v2)
+iciest-waggoner-web-3291896318-lviwo up (v2)
+iciest-waggoner-web-3291896318-kt7vu up (v2)
+ + +

If you have multiple process types for your application you may scale the process count for each type separately. For +example, this allows you to manage web process independently from background workers. For more information on process +types see our documentation for Managing App Processes.

+

In this example, we are scaling the process type web to 5 but leaving the process type background with one worker.

+
$ drycc scale web=5
+Scaling processes... but first, coffee!
+done in 4s
+=== scenic-icehouse Processes
+--- web (started): 5
+scenic-icehouse-web-3291896318-7lord up (v2)
+scenic-icehouse-web-3291896318-jn957 up (v2)
+scenic-icehouse-web-3291896318-rsekj up (v2)
+scenic-icehouse-web-3291896318-vwhnh up (v2)
+scenic-icehouse-web-3291896318-vokg7 up (v2)
+--- background (started): 1
+scenic-icehouse-web-3291896318-background-yf8kh up (v2)
+ + +
+

Note

+

The default process type for Dockerfile and Container Image applications is 'cmd' rather than 'web'.

+
+

Scaling a process down, by reducing the process count, sends a TERM signal to the processes, followed by a SIGKILL +if they have not exited within 30 seconds. Depending on your application, scaling down may interrupt long-running HTTP +client connections.

+

For example, scaling from 5 processes to 3:

+
$ drycc scale web=3
+Scaling processes... but first, coffee!
+done in 1s
+=== scenic-icehouse Processes
+--- background (started): 1
+scenic-icehouse-web-3291896318-background-yf8kh up (v2)
+--- web (started): 3
+scenic-icehouse-web-3291896318-7lord up (v2)
+scenic-icehouse-web-3291896318-rsekj up (v2)
+scenic-icehouse-web-3291896318-vokg7 up (v2)
+ + +

Get a Shell to a Running Container

+

Verify that the container is running:

+
# drycc ps
+=== python-getting-started Processes
+--- web:
+python-getting-started-web-69b7d4bfdc-kl4xf up (v2)
+ + +

Get a shell to the running container:

+
# drycc ps:exec python-getting-started-web-69b7d4bfdc-kl4xf -it -- bash
+ + +

In your shell, list the root directory:

+
# Run this inside the container
+ls /
+ + +

Running individual commands in a container

+
# drycc ps:exec python-getting-started-web-69b7d4bfdc-kl4xf -- date
+ + +

Use "drycc ps --help" for a list of global command-line (applies to all commands).

+

Autoscale

+

Autoscale allows adding a minimum and maximum number of pods on a per process type basis. This is accomplished by specifying a target CPU usage across all available pods.

+

This feature is built on top of Horizontal Pod Autoscaling in Kubernetes or HPA for short.

+
+

Note

+

This is an alpha feature. It is recommended to be on the latest Kubernetes when using this feature.

+
+
$ drycc autoscale:set web --min=3 --max=8 --cpu-percent=75
+Applying autoscale settings for process type web on scenic-icehouse... done
+ + +

And then review the scaling rule that was created for web

+
$ drycc autoscale:list
+=== scenic-icehouse Autoscale
+
+--- web:
+Min Replicas: 3
+Max Replicas: 8
+CPU: 75%
+ + +

Remove scaling rule

+
$ drycc autoscale:unset web
+Removing autoscale for process type web on scenic-icehouse... done
+ + +

For autoscaling to work CPU requests have to be specified on each application Pod (can be done via drycc limits --cpu). This allows the autoscale policies to do the appropriate calculations and make decisions on when to scale up and down.

+

Scale up can only happen if there was no rescaling within the last 3 minutes. Scale down will wait for 5 minutes from the last rescaling. That information and more can be found at HPA algorithm page.

+

Web vs Cmd Process Types

+

When deploying to Drycc Workflow using a Heroku Buildpack, Workflow boots the web process type to +boot the application server. When you deploy an application that has a Dockerfile or uses Container +images, Workflow boots the cmd process type. Both act similarly in that +they are exposed to the router as web applications. However, the cmd process type is special +because, if left undefined, it is equivalent to running the container without any additional +arguments. (i.e. The process specified by the Dockerfile or Container image's CMD directive will +be used.)

+

If migrating an application from Heroku Buildpacks to a Container-based deployment, Workflow will not +automatically convert the web process type to cmd. To do this, you'll have to manually scale +down the old process type and scale the new process type up.

+

Restarting an Application Processes

+

If you need to restart an application process, you may use drycc ps:restart. Behind the scenes, Drycc Workflow instructs +Kubernetes to terminate the old process and launch a new one in its place.

+
$ drycc ps
+=== scenic-icehouse Processes
+--- web (started): 3
+scenic-icehouse-web-3291896318-7lord up (v2)
+scenic-icehouse-web-3291896318-rsekj up (v2)
+scenic-icehouse-web-3291896318-vokg7 up (v2)
+--- background (started): 1
+scenic-icehouse-background-3291896318-yf8kh up (v2)
+$ drycc ps:restart scenic-icehouse-background-3291896318-yf8kh
+Restarting processes... but first, coffee!
+done in 6s
+=== scenic-icehouse Processes
+--- background (started): 1
+scenic-icehouse-background-3291896318-yd87g up (v2)
+ + +

Notice that the process name has changed from scenic-icehouse-background-3291896318-yf8kh to +scenic-icehouse-background-3291896318-yd87g. In a multi-node Kubernetes cluster, this may also have the effect of scheduling +the Pod to a new node.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/managing-app-resources/index.html b/applications/managing-app-resources/index.html new file mode 100644 index 000000000..d57506e0f --- /dev/null +++ b/applications/managing-app-resources/index.html @@ -0,0 +1,968 @@ + + + + + + + + + + + + + + + + + + Managing App Resources - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Managing resources for an Application

+

We can use blow command to create resources and bind which resource is created. +This command depend on service-catalog.

+

Use drycc resources to create and bind a resource for a deployed application.

+
$ drycc help resources
+Valid commands for resources:
+
+resources:services         list all available resource services
+resources:plans            list all available plans for an resource services
+resources:create           create a resource for the application
+resources:list             list resources in the application
+resources:describe         get a resource detail info in the application
+resources:update           update a resource from the application
+resources:destroy          delete a resource from the applicationa
+resources:bind             bind a resource to servicebroker
+resources:unbind           unbind a resource from servicebroker
+
+Use 'drycc help [command]' to learn more.
+ + +

List all available resource services

+

You can list available resource services with one drycc resources:services command

+
$ drycc resources:services
++------------+------------+
+|    NAME    | UPDATEABLE |
++------------+------------+
+| mysql      | true       |
+| postgresql | true       |
+| memcached  | true       |
+| redis      | true       |
++------------+------------+
+ + +

List all available plans for an resource services

+

You can list all available plans for an resource services with one drycc resources:plans command

+
$ drycc resources:plans redis
++-------+--------------------------------+
+| NAME  |          DESCRIPTION           |
++-------+--------------------------------+
+| 40000 | Redis 40000 plan which limit   |
+|       | resources memory size 40Gi.    |
+|   250 | Redis 250 plan which limit     |
+|       | resources memory size 250Mi.   |
+| 20000 | Redis 20000 plan which limit   |
+|       | resources memory size 20Gi.    |
+|  5000 | Redis 5000 plan which limit    |
+|       | resources memory size 5Gi.     |
+|   500 | Redis 500 plan which limit     |
+|       | resources memory size 500Mi.   |
+|   128 | Redis 128 plan which limit     |
+|       | resources memory size 128Mi.   |
+| 50000 | Redis 50000 plan which limit   |
+|       | resources memory size 50Gi.    |
+|  2500 | Redis 2500 plan which limit    |
+|       | resources memory size 2.5Gi.   |
+| 30000 | Redis 30000 plan which limit   |
+|       | resources memory size 30Gi.    |
+| 10000 | Redis 10000 plan which limit   |
+|       | resources memory size 10Gi.    |
+|  1000 | Redis 1000 plan which limit    |
+|       | resources memory size 1Gi.     |
++-------+--------------------------------+
+ + +

Create resource in application

+

You can create a resource with one drycc resources:create command

+
$ drycc resources:create redis:1000 redis
+Creating redis to scenic-icehouse... done
+ + +

After resources are created, you can list the resources in this application.

+
$ drycc resources:list
+=== scenic-icehouse resources
+redis      redis:1000
+ + +

Bind resources

+

The resource which is named redis is created, you can bind the redis to the application, +use the command of drycc resources:bind redis.

+
$ drycc resources:bind redis
+Binding resource... done
+ + +

Describe resources

+

And use drycc resources:describe show the binding detail. If the binding is successful, this command will show the information of connect to the resource.

+
$ drycc resources:describe redis
+=== scenic-icehouse resource redis
+plan:               redis:1000
+status:             Ready
+binding:            Ready
+
+REDISPORT:          6379
+REDIS_PASSWORD:     RzG87SJWG1
+SENTINELHOST:       172.16.0.2
+SENTINELPORT:       26379
+ + +

Update resources

+

You can use the drycc resources:update command to upgrade a new plan. +An example of how to upgrade the plan's capacity to 100MB:

+
$ drycc resources:update redis:10000 redis
+Updating redis to scenic-icehouse... done
+ + +

Remove the resource

+

If you don't need resources, use drycc resources:unbind to unbind the resource and then use drycc resources:destroy to delete the resource from the application. +Before deleting the resource, the resource must be unbinded.

+
$ drycc resources:unbind redis
+Unbinding resource... done
+
+$ drycc resources:destroy redis
+Deleting redis from scenic-icehouse... done
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/managing-app-volumes/index.html b/applications/managing-app-volumes/index.html new file mode 100644 index 000000000..c14385eb2 --- /dev/null +++ b/applications/managing-app-volumes/index.html @@ -0,0 +1,907 @@ + + + + + + + + + + + + + + + + + + Managing App Volumes - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Mounting volumes for an Application

+

We can use the blow command to create volumes and mount the created volumes. +Drycc create volume support ReadWriteMany, so before deploying drycc, you need to have a StorageClass ready which can support ReadWriteMany. +Deploying drycc, set controller.appStorageClass to this StorageClass.

+

Use drycc volumes to mount a volume for a deployed application's processes.

+
$ drycc help volumes
+Valid commands for volumes:
+
+volumes:create           create a volume for the application
+volumes:list             list volumes in the application
+volumes:delete           delete a volume from the application
+volumes:mount            mount a volume to process of the application
+volumes:unmount          unmount a volume from process of the application
+
+Use 'drycc help [command]' to learn more.
+ + +

Create a volume for the application

+

You can create a volume with the drycc volumes:create command

+
$ drycc volumes:create myvolume 200M
+Creating myvolumes to scenic-icehouse... done
+ + +

List volumes in the application

+

After volume is created, you can list the volumes in this application.

+
$ drycc volumes:list
+=== scenic-icehouse volumes
+--- myvolumes     200M
+ + +

Mount a volume

+

The volume which is named myvolumes is created, you can mount the volume with process of the application, +use the command of drycc volumes:mount. When volume is mounted, a new release will be created and deployed automatically.

+
$ drycc volumes:mount myvolumes web=/data/web
+Mounting volume... done
+ + +

And use drycc volumes:list show mount detail.

+
$ drycc volumes:list
+=== scenic-icehouse volumes
+--- myvolumes     200M
+web               /data/web
+ + +

If you don't need the volume, use drycc volumes:unmount to unmount the volume and then use drycc volumes:delete to delete the volume from the application. +Before deleting volume, the volume has to be unmounted.

+
$ drycc volumes:unmount myvolumes web
+Unmounting volume... done
+
+$ drycc volumes:delete myvolumes
+Deleting myvolumes from scenic-icehouse... done
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/managing-resource-limits/index.html b/applications/managing-resource-limits/index.html new file mode 100644 index 000000000..de8aec4b7 --- /dev/null +++ b/applications/managing-resource-limits/index.html @@ -0,0 +1,1021 @@ + + + + + + + + + + + + + + + + + + Resource Limits - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Managing Application Resource Limits

+

Drycc Workflow supports restricting memory and CPU shares of each process. Requests/Limits set on a per-process type are given to +Kubernetes as a requests and limits. Which means you guarantee <requests> amount of resource for a process as well as limit +the process from using more than <limits>. +By default, Kubernetes will set <requests> equal to <limit> if we don't explicitly set <requests> value. Please keep in mind that 0 <= requests <= limits.

+

Limiting Memory

+

If you set a requests/limits that is out of range for your cluster, Kubernetes will be unable to schedule your application +processes into the cluster!

+

Available units for memory are:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
UnitAmount
BBytes
KKiB (Power of 2)
MMiB (Power of 2)
GGiB (Power of 2)
+
+

Important

+

The minimum memory limit allowed is 4MiB.

+
+

Use drycc limits:set <type>=<value> to restrict memory by process type, where value can be <limit> or <request>/<limit> format :

+
$ drycc limits:set web=64M
+Applying limits... done
+
+=== indoor-whitecap Limits
+
+--- Memory
+web     64M
+
+--- CPU
+Unlimited
+
+$ drycc limits:set cmd=32M/64M
+Applying limits... done
+
+=== outdoor-whitecap Limits
+
+--- Memory
+cmd     32M/64M
+
+--- CPU
+Unlimited
+ + +

If you would like to remove any configured memory limits use drycc limits:unset web:

+
$ drycc limits:unset web
+Applying limits... done
+
+=== indoor-whitecap Limits
+
+--- Memory
+Unlimited
+
+--- CPU
+Unlimited
+ + +

Limiting CPU

+

You can also use drycc limits:set <type>=<value> --cpu to restrict CPU shares, where value can be <limit> or +<request>/<limit> format. CPU shares are tracked in milli-cores. One CPU core is equivalent to 1000 milli-cores. +To dedicate half a core to your process, you would need 500 milli-cores or 500m.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
UnitAmount
1000m1000 milli-cores == 100% CPU core
500m500 milli-cores == 50% CPU core
250m250 milli-cores == 25% CPU core
100m100 milli-cores == 10% CPU core
+
$ drycc limits:set web=250m --cpu
+Applying limits... done
+
+=== indoor-whitecap Limits
+
+--- Memory
+web     64M
+
+--- CPU
+web     250m
+
+$ drycc limits:set web=1500m/2000m --cpu
+Applying limits... done
+
+=== indoor-whitecap Limits
+
+--- Memory
+web     64M
+
+--- CPU
+web     1500m/2000m
+ + +

You can verify the CPU and memory limits by inspecting the application process Pod with kubectl:

+
$ drycc ps
+=== indoor-whitecap Processes
+--- web (started): 1
+indoor-whitecap-v14-web-8slcj up (v14)
+$ kubectl --namespace=indoor-whitecap describe po indoor-whitecap-v14-web-8slcj
+Name:       indoor-whitecap-v14-web-8slcj
+Containers:
+    QoS Tier:
+      cpu:     Guaranteed
+      memory:  Guaranteed
+    Limits:
+      cpu:     2000m
+      memory:  64Mi
+    Requests:
+      memory:  64Mi
+      cpu:     1500m
+ + +
+

Important

+

If you restrict resources to the point where containers do not start, +the limits:set command will hang. If this happens, use CTRL-C +to break out of limits:set and use limits:unset to revert.

+
+

To unset a CPU limit use drycc limits:unset web --cpu:

+
$ drycc limits:unset web --cpu
+Applying limits... done
+
+=== indoor-whitecap Limits
+
+--- Memory
+Unlimited
+
+--- CPU
+Unlimited
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/ssl-certificates/index.html b/applications/ssl-certificates/index.html new file mode 100644 index 000000000..f346efd2f --- /dev/null +++ b/applications/ssl-certificates/index.html @@ -0,0 +1,1014 @@ + + + + + + + + + + + + + + + + + + SSL Certificates - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Application SSL Certificates

+

SSL is a cryptographic protocol that provides end-to-end encryption and integrity for all web +requests. Apps that transmit sensitive data should enable SSL to ensure all information is +transmitted securely.

+

To enable SSL on a custom domain, e.g., www.example.com, use the SSL endpoint.

+
+

Note

+

drycc certs is only useful for custom domains. Default application domains are +SSL-enabled already and can be accessed simply by using https, +e.g. https://foo.dryccapp.com (provided that you have installed your wildcard +certificate on the routers or on the load balancer).

+
+

Overview

+

Because of the unique nature of SSL validation, provisioning SSL for your domain is a multi-step +process that involves several third-parties. You will need to:

+
    +
  1. Purchase an SSL certificate from your SSL provider
  2. +
  3. Upload the cert to Drycc
  4. +
+

Acquire SSL Certificate

+

Purchasing an SSL cert varies in cost and process depending on the vendor. RapidSSL offers a +simple way to purchase a certificate and is a recommended solution. If you’re able to use this +provider, see buy an SSL certificate with RapidSSL for instructions.

+

DNS and Domain Configuration

+

Once the SSL certificate is provisioned and your cert is confirmed, you must route requests for +your domain through Drycc. Unless you've already done so, add the domain specified when generating +the CSR to your app with:

+
$ drycc domains:add www.example.com -a foo
+Adding www.example.com to foo... done
+ + +

Add a Certificate

+

Add your certificate, any intermediate certificates, and private key to the endpoint with the +certs:add command.

+
$ drycc certs:add example-com server.crt server.key
+Adding SSL endpoint... done
+www.example.com
+ + +
+

Note

+

The name given to the certificate can only contain a-z (lowercase), 0-9 and hyphens

+
+

The Drycc platform will investigate the certificate and extract any relevant information from it +such as the Common Name, Subject Alt Names (SAN), fingerprint and more.

+

This allows for wildcard certificates and multiple domains in the SAN without uploading duplicates.

+

Add a Certificate Chain

+

Sometimes, your certificates (such as a self-signed or a cheap certificate) need additional +certificates to establish the chain of trust. What you need to do is bundle all the certificates +into one file and give that to Drycc. Importantly, your site’s certificate must be the first one:

+
$ cat server.crt server.ca > server.bundle
+ + +

After that, you can add them to Drycc with the certs:add command:

+
$ drycc certs:add example-com server.bundle server.key
+Adding SSL endpoint... done
+www.example.com
+ + +

Attach SSL certificate to a domain

+

Certificates are not automagically connected up to domains, instead you will have to attach a +certificate to a domain

+
$ drycc certs:attach example-com example.com
+ + +

Each certificate can be connected to many domains. There is no need to upload duplicates.

+

To remove an association

+
$ drycc certs:detach example-com example.com
+ + +

Endpoint overview

+

You can verify the details of your domain's SSL configuration with drycc certs.

+
$ drycc certs
+
+     Name     |    Common Name    | SubjectAltName    |         Expires         |   Fingerprint   |   Domains    |   Updated   |   Created
++-------------+-------------------+-------------------+-------------------------+-----------------+--------------+-------------+-------------+
+  example-com |     example.com   | blog.example.com  | 31 Dec 2017 (in 1 year) | 8F:8E[...]CD:EB |  example.com | 30 Jan 2016 | 29 Jan 2016
+ + +

or by looking at at each certificates detailed information

+
$ drycc certs:info example-com
+
+=== bar-com Certificate
+Common Name(s):     example.com
+Expires At:         2017-01-14 23:57:57 +0000 UTC
+Starts At:          2016-01-15 23:57:57 +0000 UTC
+Fingerprint:        7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0
+Subject Alt Name:   blog.example.com
+Issuer:             /C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=example.com/emailAddress=engineering@drycc.cc
+Subject:            /C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=example.com/emailAddress=engineering@drycc.cc
+
+Connected Domains:  example.com
+Owner:              admin-user
+Created:            2016-01-28 19:07:41 +0000 UTC
+Updated:            2016-01-30 00:10:02 +0000 UTC
+ + +

Testing SSL

+

Use a command line utility like curl to test that everything is configured correctly for your +secure domain.

+
+

Note

+

The -k option flag tells curl to ignore untrusted certificates.

+
+

Pay attention to the output. It should print SSL certificate verify ok. If it prints something +like common name: www.example.com (does not match 'www.somedomain.com') then something is not +configured correctly.

+

Enforcing SSL at the Router

+

To enforce all HTTP requests be redirected to HTTPS, TLS can be enforced at the router level by +running

+
$ drycc tls:force:enable -a foo
+Enabling https-only requests for foo... done
+ + +

Users hitting the HTTP endpoint for the application will now receive a 301 redirect to the HTTPS +endpoint.

+

To disable enforced TLS, run

+
$ drycc tls:force:disable -a foo
+Disabling https-only requests for foo... done
+ + +

Automated Certificate Management

+

With Automated Certificate Management (ACM), Drycc automatically manages TLS certificates for apps with Hobby and Professional dynos on the Common Runtime, and for apps in Private Spaces that enable the feature. +Certificates handled by ACM automatically renew one month before they expire, and new certificates are created automatically whenever you add or remove a custom domain. All applications with paid dynos include ACM for free. +Automated Certificate Management uses Let’s Encrypt, the free, automated, and open certificate authority for managing your application’s TLS certificates. Let’s Encrypt is run for the public benefit by the Internet Security Research Group (ISRG).

+

To enable ACM with the following command: + $ drycc tls:auto:enable -a foo

+

To disable ACM with the following command: + $ drycc tls:auto:disable -a foo

+

Remove Certificate

+

You can remove a certificate using the certs:remove command:

+
$ drycc certs:remove my-cert
+Removing www.example.com... Done.
+ + +

Swapping out certificates

+

Over the lifetime of an application an operator will have to acquire certificates with new expire +dates and apply it to all relevant applications, below is the recommended way to swap out certificates.

+

Be intentional with certificate names, name them example-com-2017 when possible, where the year +signifies the expiry year. This allows for example-com-2018 when a new certificate is purchased.

+

Assuming all applications are already using example-com-2017 the following commands can be ran, +chained together or otherwise:

+
$ drycc certs:detach example-com-2017 example.com
+$ drycc certs:attach example-com-2018 example.com
+ + +

This will take care of a singular domain which allows the operator to verify everything went +as planned and slowly roll it out to any other application using the same method.

+

Troubleshooting

+

Here are some steps you can follow if your SSL endpoint is not working as you'd expect.

+

Untrusted Certificate

+

In some cases when accessing the SSL endpoint, it may list your certificate as untrusted.

+

If this occurs, it may be because it is not trusted by Mozilla’s list of root CAs. If this is +the case, your certificate may be considered untrusted for many browsers.

+

If you have uploaded a certificate that was signed by a root authority but you get the message that +it is not trusted, then something is wrong with the certificate. For example, it may be missing +intermediary certificates. If so, download the intermediary certificates from your SSL provider, +remove the certificate from Drycc and re-run the certs:add command.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/using-buildpacks/index.html b/applications/using-buildpacks/index.html new file mode 100644 index 000000000..3549a5adc --- /dev/null +++ b/applications/using-buildpacks/index.html @@ -0,0 +1,1001 @@ + + + + + + + + + + + + + + + + + + Buildpacks - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Using Buildpacks

+

Drycc supports deploying applications via Cloud Native Buildpacks. Cloud Native Buildpacks are useful if you want to follow cnb's docs for building applications.

+

Add SSH Key

+

For Buildpack based application deploys via git push, Drycc Workflow identifies users via SSH keys. SSH keys are pushed to the platform and must be unique to each user.

+
    +
  • +

    See this document for instructions on how to generate an SSH key.

    +
  • +
  • +

    Run drycc keys:add to upload your SSH key to Drycc Workflow.

    +
  • +
+
$ drycc keys:add ~/.ssh/id_drycc.pub
+Uploading id_drycc.pub to drycc... done
+ + +

Read more about adding/removing SSH Keys here.

+

Prepare an Application

+

If you do not have an existing application, you can clone an example application that demonstrates the Heroku Buildpack workflow.

+
$ git clone https://github.com/drycc/example-go.git
+$ cd example-go
+ + +

Create an Application

+

Use drycc create to create an application on the Controller.

+
$ drycc create
+Creating application... done, created skiing-keypunch
+Git remote drycc added
+ + +

Push to Deploy

+

Use git push drycc master to deploy your application.

+
$ git push drycc master
+Counting objects: 75, done.
+Delta compression using up to 8 threads.
+Compressing objects: 100% (48/48), done.
+Writing objects: 100% (75/75), 18.28 KiB | 0 bytes/s, done.
+Total 75 (delta 30), reused 58 (delta 22)
+remote: --->
+Starting build... but first, coffee!
+---> Waiting podman running.
+---> Process podman started.
+---> Waiting caddy running.
+---> Process caddy started.
+---> Building pack
+---> Using builder registry.drycc.cc/drycc/buildpacks:bookworm
+Builder 'registry.drycc.cc/drycc/buildpacks:bookworm' is trusted
+Pulling image 'registry.drycc.cc/drycc/buildpacks:bookworm'
+Resolving "drycc/buildpacks" using unqualified-search registries (/etc/containers/registries.conf)
+Trying to pull registry.drycc.cc/drycc/buildpacks:bookworm...
+Getting image source signatures
+...
+---> Skip generate base layer
+---> Python Buildpack
+---> Downloading and extracting Python 3.10.0
+---> Installing requirements with pip
+Collecting Django==3.2.8
+Downloading Django-3.2.8-py3-none-any.whl (7.9 MB)
+Collecting gunicorn==20.1.0
+Downloading gunicorn-20.1.0-py3-none-any.whl (79 kB)
+Collecting sqlparse>=0.2.2
+Downloading sqlparse-0.4.2-py3-none-any.whl (42 kB)
+Collecting pytz
+Downloading pytz-2021.3-py2.py3-none-any.whl (503 kB)
+Collecting asgiref<4,>=3.3.2
+Downloading asgiref-3.4.1-py3-none-any.whl (25 kB)
+Requirement already satisfied: setuptools>=3.0 in /layers/drycc_python/python/lib/python3.10/site-packages (from gunicorn==20.1.0->-r requirements.txt (line 2)) (57.5.0)
+Installing collected packages: sqlparse, pytz, asgiref, gunicorn, Django
+Successfully installed Django-3.2.8 asgiref-3.4.1 gunicorn-20.1.0 pytz-2021.3 sqlparse-0.4.2
+---> Generate Launcher
+...
+Build complete.
+Launching App...
+...
+Done, skiing-keypunch:v2 deployed to Workflow
+
+Use 'drycc open' to view this application in your browser
+
+To learn more, use 'drycc help' or visit https://www.drycc.cc
+
+To ssh://git@drycc.staging-2.drycc.cc:2222/skiing-keypunch.git
+ * [new branch]      master -> master
+
+$ curl -s http://skiing-keypunch.example.com
+Powered by Drycc
+Release v2 on skiing-keypunch-v2-web-02zb9
+ + +

Because a Buildpacks-style application is detected, the web process type is automatically scaled to 1 on first deploy.

+

Use drycc scale web=3 to increase web processes to 3, for example. Scaling a +process type directly changes the number of pods running that process.

+

Included Buildpacks

+

For convenience, a number of buildpacks come bundled with Drycc:

+ +

Drycc will cycle through the bin/detect script of each buildpack to match the code you +are pushing.

+
+

Note

+

If you're testing against the [Scala Buildpack][], the Builder requires at least +512MB of free memory to execute the Scala Build Tool.

+
+

Using a Custom Buildpack

+

To use a custom buildpack, you need create a .pack_builder file in your root path app.

+
$  tee > .pack_builder << EOF
+   > registry.drycc.cc/drycc/buildpacks:bookworm
+   > EOF
+ + +

On your next git push, the custom buildpack will be used.

+

Using Private Repositories

+

To pull code from private repositories, set the SSH_KEY environment variable to a private key +which has access. Use either the path of a private key file or the raw key material:

+
$ drycc config:set SSH_KEY=/home/user/.ssh/id_rsa
+$ drycc config:set SSH_KEY="""-----BEGIN RSA PRIVATE KEY-----
+(...)
+-----END RSA PRIVATE KEY-----"""
+ + +

For example, to use a custom buildpack hosted at a private GitHub URL, ensure that an SSH public +key exists in your GitHub settings. Then set SSH_KEY to the corresponding SSH private key +and set .pack_builder to the builder image:

+
$  tee > .pack_builder << EOF
+   > registry.drycc.cc/drycc/buildpacks:bookworm
+   > EOF
+$ git add .buildpack
+$ git commit -m "chore(buildpack): modify the pack_builder"
+$ git push drycc master
+ + +

Builder selector

+

Which way to build a project conforms to the following principles:

+
    +
  • If Dockerfile exists in the project, the stack uses container
  • +
  • If Procfile exists in the project, the stack uses buildpack
  • +
  • If both exist, container is used by default
  • +
  • You can also set the DRYCC_STACK to container or buildpack determine which stack to use.
  • +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/using-container-images/index.html b/applications/using-container-images/index.html new file mode 100644 index 000000000..5d8e88513 --- /dev/null +++ b/applications/using-container-images/index.html @@ -0,0 +1,933 @@ + + + + + + + + + + + + + + + + + + Container Images - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Using Docker Images

+

Drycc supports deploying applications via an existing Docker Image. +This is useful for integrating Drycc into Docker-based CI/CD pipelines.

+

Prepare an Application

+

Start by cloning an example application:

+
$ git clone https://github.com/drycc/example-dockerfile-http.git
+$ cd example-dockerfile-http
+ + +

Next use your local docker client to build the image and push +it to DockerHub.

+
$ docker build -t <username>/example-dockerfile-http .
+$ docker push <username>/example-dockerfile-http
+ + +

Docker Image Requirements

+

In order to deploy Docker images, they must conform to the following requirements:

+
    +
  • The Dockerfile must use the EXPOSE directive to expose exactly one port.
  • +
  • That port must be listening for an HTTP connection.
  • +
  • The Dockerfile must use the CMD directive to define the default process that will run within the container.
  • +
  • The Docker image must contain bash to run processes.
  • +
+
+

Note

+

Note that if you are using a private registry of any kind (gcr or other) the application environment must include a $PORT config variable that matches the EXPOSE'd port, example: drycc config:set PORT=5000. See Configuring Registry for more info.

+
+

Create an Application

+

Use drycc create to create an application on the controller.

+
$ mkdir -p /tmp/example-dockerfile-http && cd /tmp/example-dockerfile-http
+$ drycc create example-dockerfile-http --no-remote
+Creating application... done, created example-dockerfile-http
+ + +
+

Note

+

For all commands except for drycc create, the drycc client uses the name of the current directory +as the app name if you don't specify it explicitly with --app.

+
+

Deploy the Application

+

Use drycc pull to deploy your application from DockerHub or +a public registry.

+
$ drycc pull <username>/example-dockerfile-http:latest
+Creating build...  done, v2
+
+$ curl -s http://example-dockerfile-http.local3.dryccapp.com
+Powered by Drycc
+ + +

Because you are deploying a Docker image, the cmd process type is automatically scaled to 1 on first deploy.

+

Use drycc scale cmd=3 to increase cmd processes to 3, for example. Scaling a +process type directly changes the number of Containers +running that process.

+

Private Registry

+

To deploy Docker images from a private registry or from a private repository, use drycc registry +to attach credentials to your application. These credentials are the same as you'd use when running +docker login at your private registry.

+

To deploy private Docker images, take the following steps:

+
    +
  • Gather the username and password for the registry, such as a Quay.io Robot Account or a GCR.io Long Lived Token
  • +
  • Run drycc registry:set username=<the-user> password=<secret> -a <application-name>
  • +
  • Now perform drycc pull as normal, against an image in the private registry
  • +
+

When using a GCR.io Long Lived Token, the JSON blob will have to be compacted first using a +tool like jq and then used in the password field in drycc registry:set. For the username, use +_json_key. For example:

+
drycc registry:set username=_json_key password="$(cat google_cloud_cred.json | jq -c .)"
+ + +

When using a private registry the docker images are no longer pulled into the Drycc Internal Registry via +the Drycc Workflow Controller but rather is managed by Kubernetes. This will increase security and overall speed, +however the application port information can no longer be discovered. Instead the application port information can be set via +drycc config:set PORT=80 prior to setting the registry information.

+
+

Note

+

Currently GCR.io and ECR in short lived auth token mode are not supported.

+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/using-dockerfiles/index.html b/applications/using-dockerfiles/index.html new file mode 100644 index 000000000..0891fc4bd --- /dev/null +++ b/applications/using-dockerfiles/index.html @@ -0,0 +1,981 @@ + + + + + + + + + + + + + + + + + + Dockerfiles - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Using Dockerfiles

+

Drycc supports deploying applications via Dockerfiles. A Dockerfile automates the steps for crafting a [Container Image][]. +Dockerfiles are incredibly powerful but require some extra work to define your exact application runtime environment.

+

Add SSH Key

+

For Dockerfile based application deploys via git push, Drycc Workflow identifies users via SSH keys. SSH keys are pushed to the platform and must be unique to each user.

+
    +
  • +

    See this document for instructions on how to generate an SSH key.

    +
  • +
  • +

    Run drycc keys:add to upload your SSH key to Drycc Workflow.

    +
  • +
+
$ drycc keys:add ~/.ssh/id_drycc.pub
+Uploading id_drycc.pub to drycc... done
+ + +

Read more about adding/removing SSH Keys here.

+

Prepare an Application

+

If you do not have an existing application, you can clone an example application that demonstrates the Dockerfile workflow.

+
$ git clone https://github.com/drycc/helloworld.git
+$ cd helloworld
+ + +

Dockerfile Requirements

+

In order to deploy Dockerfile applications, they must conform to the following requirements:

+
    +
  • The Dockerfile must use the EXPOSE directive to expose exactly one port.
  • +
  • That port must be listening for an HTTP connection.
  • +
  • The Dockerfile must use the CMD directive to define the default process that will run within the container.
  • +
  • The Container image must contain bash to run processes.
  • +
+
+

Note

+

Note that if you are using a private registry of any kind (gcr or other) the application environment must include a $PORT config variable that matches the EXPOSE'd port, example: drycc config:set PORT=5000. See Configuring Registry for more info.

+
+

Create an Application

+

Use drycc create to create an application on the Controller.

+
$ drycc create
+Creating application... done, created folksy-offshoot
+Git remote drycc added
+ + +

Push to Deploy

+

Use git push drycc master to deploy your application.

+
$ git push drycc master
+Counting objects: 13, done.
+Delta compression using up to 8 threads.
+Compressing objects: 100% (13/13), done.
+Writing objects: 100% (13/13), 1.99 KiB | 0 bytes/s, done.
+Total 13 (delta 2), reused 0 (delta 0)
+-----> Building Docker image
+Uploading context 4.096 kB
+Uploading context
+Step 0 : FROM drycc/base:latest
+ ---> 60024338bc63
+Step 1 : RUN wget -O /tmp/go1.2.1.linux-amd64.tar.gz -q https://go.googlecode.com/files/go1.2.1.linux-amd64.tar.gz
+ ---> Using cache
+ ---> cf9ef8c5caa7
+Step 2 : RUN tar -C /usr/local -xzf /tmp/go1.2.1.linux-amd64.tar.gz
+ ---> Using cache
+ ---> 515b1faf3bd8
+Step 3 : RUN mkdir -p /go
+ ---> Using cache
+ ---> ebf4927a00e9
+Step 4 : ENV GOPATH /go
+ ---> Using cache
+ ---> c6a276eded37
+Step 5 : ENV PATH /usr/local/go/bin:/go/bin:$PATH
+ ---> Using cache
+ ---> 2ba6f6c9f108
+Step 6 : ADD . /go/src/github.com/drycc/helloworld
+ ---> 94ab7f4b977b
+Removing intermediate container 171b7d9fdb34
+Step 7 : RUN cd /go/src/github.com/drycc/helloworld && go install -v .
+ ---> Running in 0c8fbb2d2812
+github.com/drycc/helloworld
+ ---> 13b5af931393
+Removing intermediate container 0c8fbb2d2812
+Step 8 : ENV PORT 80
+ ---> Running in 9b07da36a272
+ ---> 2dce83167874
+Removing intermediate container 9b07da36a272
+Step 9 : CMD ["/go/bin/helloworld"]
+ ---> Running in f7b215199940
+ ---> b1e55ce5195a
+Removing intermediate container f7b215199940
+Step 10 : EXPOSE 80
+ ---> Running in 7eb8ec45dcb0
+ ---> ea1a8cc93ca3
+Removing intermediate container 7eb8ec45dcb0
+Successfully built ea1a8cc93ca3
+-----> Pushing image to private registry
+
+       Launching... done, v2
+
+-----> folksy-offshoot deployed to Drycc
+       http://folksy-offshoot.local3.dryccapp.com
+
+       To learn more, use `drycc help` or visit https://www.drycc.cc
+
+To ssh://git@local3.dryccapp.com:2222/folksy-offshoot.git
+ * [new branch]      master -> master
+
+$ curl -s http://folksy-offshoot.local3.dryccapp.com
+Welcome to Drycc!
+See the documentation at http://docs.drycc.cc/ for more information.
+ + +

Because a Dockerfile application is detected, the cmd process type is automatically scaled to 1 on first deploy.

+

Use drycc scale cmd=3 to increase cmd processes to 3, for example. Scaling a +process type directly changes the number of containers +running that process.

+

Container Build Arguments

+

As of Workflow v2.13.0, users can inject their application config into the Container image using +Container build arguments. To opt into this, users must add a new environment variable +to their application:

+
$ drycc config:set DRYCC_DOCKER_BUILD_ARGS_ENABLED=1
+ + +

Every environment variable set with drycc config:set will then be available for use inside the +user's Dockerfile. For example, if a user runs drycc config:set POWERED_BY=Workflow, +the user can utilize that build argument in their Dockerfile:

+
ARG POWERED_BY
+RUN echo "Powered by $POWERED_BY" > /etc/motd
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 000000000..1400e29fb --- /dev/null +++ b/bower.json @@ -0,0 +1,8 @@ +{ + "name": "drycc workflow docs", + "dependencies": { + "headroom.js": "^0.9.3", + "font-awesome": "^4.6.3", + "foundation": "^5.5.3" + } +} diff --git a/changelogs/v1.0.1/index.html b/changelogs/v1.0.1/index.html new file mode 100644 index 000000000..d28b67e8a --- /dev/null +++ b/changelogs/v1.0.1/index.html @@ -0,0 +1,875 @@ + + + + + + + + + + + + + + + + + + v1.0.1 - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

The time has come for major release! We are proud to present Drycc Workflow 1.0.1 to the world. In this release, we've added a lot of new features.

+

You can download one of our pre-built binaries from our downloads page - make sure to select the correct platform! For further details on how to install, follow our installation guide.

+

We’d like to thank all of our backers on Open Collective, who are helping us deliver a better piece of software.

+

With that out of the way, here’s what’s new in Drycc version 1.0.1:

+
    +
  • substituting minio-mc for object-storage
  • +
  • using wal-g instead of wal-e
  • +
  • some scenarios use dep instead of glide
  • +
  • minio adds gateway mode
  • +
  • adding aliyun oss support
  • +
+

In the future, we have many exciting plans, for example:

+
    +
  • Use kubernetes ingress instead of drycc-router
  • +
  • Automatic certificate generation using cert-manager
  • +
  • Replace golang's package management glide with dep
  • +
  • Support for the latest version of the kubernetes API
  • +
+

Coming soon...

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/changelogs/v1.1.0/index.html b/changelogs/v1.1.0/index.html new file mode 100644 index 000000000..9557e0c98 --- /dev/null +++ b/changelogs/v1.1.0/index.html @@ -0,0 +1,906 @@ + + + + + + + + + + + + + + + + + + v1.1.0 - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Workflow ## v1.0.0 -> v1.1.0

+

Releases

+
    +
  • builder v1.0.0 -> v1.0.1
  • +
  • controller v1.0.0 -> v1.1.0
  • +
  • database v1.0.0 -> v1.0.1
  • +
  • monitor v1.0.0 -> v1.0.1
  • +
  • registry-proxy v1.0.0 -> v1.0.1
  • +
+

Features

+
    +
  • 69c8e12 (controller) - docker: use python:3.7-alpine replace drycc/base
  • +
  • 6a3e70c (controller) - gunicorn: use process replace threads
  • +
  • e63cbb5 (controller) - ingress: Improving the configuration of ingress
  • +
  • 76f75dc (controller) - charts: add rbac to cert-manager
  • +
  • 6807b2c (controller) - certificate: add cert-manager certificate api
  • +
+

Fixes

+
    +
  • f53d89e (controller) - controller: check_image_access only when using docker
  • +
  • 896775a (controller) - docker: multiprocess should not be used in docker
  • +
  • ecdaf9f (controller) - app: can't create app
  • +
  • e00af7e (controller) - tls: add migrations for certs_auto_enabled
  • +
+

Style

+
    +
  • bdbb7e6 (controller) - pep8: Use pep8-compliant code style
  • +
+

Test case

+
    +
  • c5b5a9d (controller) - ingress: add tests to ingress
  • +
+

Maintenance

+
    +
  • 62a9b7d (builder) - workflow: change experimental_native_ingress to use_native_ingress
  • +
  • 39e9cec (builder) - ingress: renmae use_native_ingress to use_ingress
  • +
  • 7fa8134 (builder) - ingress: change global.use_ingress to ingress.enabled
  • +
  • e245c31 (builder) - ingress: use ingressClass
  • +
  • 18b330d (builder) - service: no longer dependent on ingress switches
  • +
  • 95f4d3d (controller) - django: upgrade to django version 1.11.20 latest patch
  • +
  • 6bcd79b (controller) - workflow: change experimental_native_ingress to use_native_ingress
  • +
  • 781229a (controller) - ingress: renmae use_native_ingress to use_ingress
  • +
  • b96b4db (controller) - ingress: change global.use_ingress to ingress.enabled
  • +
  • e1b124f (controller) - ingress: use ingressClass
  • +
  • fee0554 (controller) - ingress: delete ingress judgment
  • +
  • 5cd10f3 (controller) - ingress: Ingress_class can be empty
  • +
  • fa312bb (database) - postgres: set max_connections = 1024
  • +
  • c1ee2a4 (monitor) - monitor: remove copyrights.tar.gz
  • +
  • e088da3 (registry-proxy) - ingress: renmae use_native_ingress to use_ingress
  • +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/changelogs/v1.2.0/index.html b/changelogs/v1.2.0/index.html new file mode 100644 index 000000000..7176d1573 --- /dev/null +++ b/changelogs/v1.2.0/index.html @@ -0,0 +1,896 @@ + + + + + + + + + + + + + + + + + + v1.2.0 - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Workflow ## v1.1.0 -> v1.2.0

+

Releases

+
    +
  • builder v1.0.1 -> v1.0.2
  • +
  • slugbuilder v1.0.0 -> v1.1.0
  • +
  • imagebuilder v1.0.0 -> v1.1.0
  • +
  • controller v1.1.0 -> v1.2.0
  • +
  • slugrunner v1.0.0 -> v1.1.0
  • +
  • registry v1.0.0 -> v1.0.1
  • +
  • registry-proxy v1.0.1 -> v1.0.2
  • +
+

Features

+
    +
  • e5584e3 (controller) - controller: add STACK support
  • +
  • ad34dc1 (imagebuilder) - kaniko: use kaniko replace docker-py
  • +
  • b81430e (imagebuilder) - imagebuilder: change image to image.json format
  • +
  • 60dde96 (slugbuilder) - slugbuilder: add STACK support
  • +
  • fe8b6e5 (slugrunner) - slugrunner: add STACK support
  • +
+

Maintenance

+
    +
  • 942f050 (builder) - registry: remove env DRYCC_REGISTRY_PROXY_PORT
  • +
  • ff7a16f (builder) - registry: remove ecr and gcr registry
  • +
  • ad13683 (builder) - builder: change DRYCC_BUILD_TYPE to DRYCC_STACK
  • +
  • 6def637 (builder) - registry: rename DRYCC_REGISTRY_SERVICE to DRYCC_REGISTRY_PROXY
  • +
  • 5044e22 (builder) - registry: remove registrySecretPrefix
  • +
  • 2ea39cc (builder) - controller-go-sdk: upgrade controller-go-sdk
  • +
  • 6aee0d7 (builder) - registry: optimizing variable naming
  • +
  • f9c62d9 (controller) - domain: added reserved domain check
  • +
  • f5a135b (controller) - migrations: clean old migrations
  • +
  • 4369b2c (controller) - registry: rename DRYCC_REGISTRY_SERVICE to DRYCC_REGISTRY_PROXY
  • +
  • 1057ca5 (controller) - registry: remove registrySecretPrefix
  • +
  • d114b3e (controller) - docker: update docker client
  • +
  • edbe963 (imagebuilder) - dockerfile: change base image to alpine
  • +
  • fb35baf (imagebuilder) - registry: rename DRYCC_REGISTRY_SERVICE to DRYCC_REGISTRY_PROXY
  • +
  • 946dbf6 (imagebuilder) - docker: remove insecure support
  • +
  • 628d853 (imagebuilder) - proxy: add registry proxy
  • +
  • ff27cbd (registry) - env: remove unused env
  • +
  • 7204d72 (registry-proxy) - registry: optimizing variable naming
  • +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/changelogs/v1.3.0/index.html b/changelogs/v1.3.0/index.html new file mode 100644 index 000000000..5fe5802cd --- /dev/null +++ b/changelogs/v1.3.0/index.html @@ -0,0 +1,896 @@ + + + + + + + + + + + + + + + + + + v1.3.0 - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Workflow ## v1.2.0 -> v1.3.0

+

Releases

+
    +
  • builder v1.0.2 -> v1.1.0
  • +
  • slugbuilder v1.1.0 -> v1.1.1
  • +
  • imagebuilder v1.1.0 -> v1.1.1
  • +
  • controller v1.2.0 -> v1.2.1
  • +
  • slugrunner v1.1.0 -> v1.1.1
  • +
  • database v1.0.0 -> v1.0.1
  • +
  • fluentd v1.0.0 -> v1.0.1
  • +
  • minio v1.0.0 -> v1.0.1
  • +
  • monitor v1.0.0 -> v1.0.1
  • +
  • registry v1.0.1 -> v1.0.2
  • +
+

Features

+
    +
  • 9c7cceb (builder) - builder: add app config to env
  • +
+

Fixes

+
    +
  • 7fe44fa (controller) - docker: docker timeout must be an int, float or None
  • +
  • b196550 (controller) - controller: revert release.check_image_access for now
  • +
+

Maintenance

+
    +
  • ef932c4 (builder) - controller-sdk-go: upgrade controller-sdk-go
  • +
  • 4654cf6 (controller) - django-rest-framework: upgrade to 3.9.3
  • +
  • 14121f1 (controller) - deps: bump djangorestframework from 3.9.3 to 3.9.4 in /rootfs
  • +
  • 385acdc (controller) - deps: bump django from 1.11.20 to 1.11.21 in /rootfs
  • +
  • fa312bb (database) - postgres: set max_connections = 1024
  • +
  • 7ebecdf (database) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z
  • +
  • b8878f6 (imagebuilder) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z
  • +
  • b097451 (fluentd) - fluent: upgrade fluent to v1.4
  • +
  • 4341f9a (minio) - mc: upgrade mc and minio
  • +
  • c1ee2a4 (monitor) - monitor: remove copyrights.tar.gz
  • +
  • 9854260 (registry) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z
  • +
  • acc5627 (slugbuilder) - slugbuilder: internal support for multi buildpack
  • +
  • d58907e (slugbuilder) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z
  • +
  • b39a0c2 (slugrunner) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z
  • +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/changelogs/v1.4.0/index.html b/changelogs/v1.4.0/index.html new file mode 100644 index 000000000..7e6aa6fcb --- /dev/null +++ b/changelogs/v1.4.0/index.html @@ -0,0 +1,1101 @@ + + + + + + + + + + + + + + + + + + v1.4.0 - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Workflow ## v1.3.0 -> v1.4.0

+

Releases

+
    +
  • builder v1.1.0 -> v1.2.0
  • +
  • slugbuilder v1.1.1 -> v1.2.0
  • +
  • imagebuilder v1.1.1 -> v1.1.2
  • +
  • controller v1.2.1 -> v1.3.0
  • +
  • slugrunner v1.1.1 -> v1.1.2
  • +
  • database v1.0.1 -> v1.0.2
  • +
  • fluentd v1.0.1 -> v1.1.0
  • +
  • redis v1.0.0 -> v1.1.0
  • +
  • logger v1.0.0 -> v1.1.0
  • +
  • minio v1.0.1 -> v1.1.0
  • +
  • monitor v1.0.1 -> v1.1.0
  • +
  • nsqd v1.0.0 -> v1.1.0
  • +
  • registry v1.0.2 -> v1.0.3
  • +
  • registry-proxy v1.0.0 -> v1.0.1
  • +
+

Features

+
    +
  • fc7d93f (builder) - builder: use go-dev
  • +
  • 0c2159e (builder) - builder: fmt code and add create_bucket script
  • +
  • 1b88340 (controller) - controller: remove deprecated api
  • +
  • a92fdeb (controller) - routable: ingress support routable
  • +
  • 1e3eab3 (controller) - maintenance: add maintenance support for ingress
  • +
  • 56b9dd0 (controller) - crt: support containerd-ctr
  • +
  • 5fc3b46 (controller) - controller: add ephemeral-storage restriction
  • +
  • d677e52 (controller) - controller: add a volume command
  • +
  • 5f1323a (controller) - controller:drycc run cmd add --mount para
  • +
  • 74c36a5 (controller) - tasks: add distributed async task
  • +
  • 139c3ca (controller) - tasks: change nsq reader to async
  • +
  • f237d74 (controller) - controller:add drycc resource cmd
  • +
  • 41b46d0 (controller) - controller:add drycc resource cmd improvement
  • +
  • c26f7d8 (controller) - controller: add LimitRanges support
  • +
  • 45b5d1b (controller) - users: add users status api
  • +
  • 4e16f9b (controller) - ps:add ps:stop/start command
  • +
  • c659fa9 (controller) - k8s: add k8s cluster domain
  • +
  • 31a625d (controller) - ps:add ps:stop/start command
  • +
  • 00a779a (fluentd) - fluentd: support containerd log format
  • +
  • f3f1bd4 (fluentd) - nsqd: add stateless nsqd cluster support
  • +
  • db7147c (fluentd) - mirrors: delete aliyun mirrors
  • +
  • 689c12e (logger) - nsqd: add stateless nsqd cluster support
  • +
  • 78ccc5d (logger) - redis: add redis client cluster support
  • +
  • 9843f2c (logger) - k8s: add k8s cluster domain
  • +
  • 6ba122e (minio) - minio: add pvc support
  • +
  • 6973550 (monitor) - monitor: add ingress for monitor
  • +
  • cd73305 (monitor) - charts: add volumeName support
  • +
  • 4769fe9 (monitor) - nsqd: add stateless nsqd cluster support
  • +
  • 87806df (monitor) - k8s: add k8s cluster domain
  • +
  • 4db40c4 (nsqd) - nsqd: add stateless nsqd cluster support
  • +
  • b6f3d4f (nsqd) - nsqd: add stateless nsqd cluster support
  • +
  • 74b85bb (redis) - redis: change redis to statefulset
  • +
  • ff98b50 (slugbuilder) - slugbuilder: delete build hook
  • +
  • b201c2f (slugbuilder) - buildpacks: use drycc buildpacks
  • +
+

Fixes

+
    +
  • 0ec042d (builder) - test: fix test case error
  • +
  • 4fb113b (builder) - build: base image replace by alpine
  • +
  • 443df48 (builder) - minio: fix not bucket error
  • +
  • 3dab5b0 (builder) - minio: create bucket error
  • +
  • 734fca6 (controller) - autoscale: Fix for autoscale on k8s-1.9+ without breaking manual scaling
  • +
  • a7dcd10 (controller) - controller: test pass
  • +
  • 93f0f2e (controller) - controller: fix migrations error
  • +
  • 4724375 (controller) - controller: fix test error
  • +
  • 7bacf29 (controller) - charts: fix clusterrole
  • +
  • 90957f7 (controller) - pod: sort events error
  • +
  • 440b13e (controller) - controller: review table structure
  • +
  • 0a470a6 (controller) - controller: bump tornado 5.1.1
  • +
  • e39218b (controller) - pynsq: no current event loop in thread
  • +
  • 1d8630e (controller) - tests: fix test_task.py run error
  • +
  • 1ff1202 (controller) - controller: fix test case
  • +
  • d8c0da3 (controller) - settings: fix env name
  • +
  • 6d8fd36 (database) - 003_restore_from_backup.sh: ignore script exit 1
  • +
  • e0394a9 (database) - minio: fix not bucket error
  • +
  • f35f252 (database) - mc: fix create_bucket error
  • +
  • 74d6886 (database) - postgres: recovery mode not run
  • +
  • e50d0c1 (imagebuilder) - caddy: fix caddy not start
  • +
  • f3bec7a (fluentd) - influxdb: fix influxdb host and port
  • +
  • bc19f27 (fluentd) - charts: skipped value for daemonEnvironment: Not a table
  • +
  • 338d623 (logger) - logger: logger not run in alpine
  • +
  • 7788302 (minio) - minio: bump minio version
  • +
  • 619eed0 (minio) - fix: use go mod replace dep
  • +
  • 3b42122 (monitor) - monitor: fix host error
  • +
  • 67998ef (monitor) - influxdb: replace drycc-monitor-influxapi to drycc-monitor-influx-api
  • +
  • 2cc361c (registry) - registry: fix test case
  • +
  • 548297a (registry) - minio: fix not bucket error
  • +
  • 5412ddb (registry) - minio: create bucket error
  • +
  • d0d629e (slugbuilder) - slugbuilder:fix normalize_storage path
  • +
  • d76ecbe (slugbuilder) - slugbuilder: use v3 api
  • +
  • c505e18 (slugbuilder) - shellcheck: SC2039
  • +
+

Style

+
    +
  • c893a17 (builder) - builder: fmt code
  • +
  • bba5795 (controller) - controller: format code
  • +
  • d36082b (controller) - controller: fix pep8
  • +
  • 66026f2 (controller) - resource: standardize the naming of resource
  • +
  • 03d7e2c (controller) - servicecatalog: change servicecatalog to svcat
  • +
  • 49dbb6d (controller) - controller: flake8 upgrade
  • +
  • cbfc108 (monitor) - monitor: format charts and dashboard
  • +
  • ee85954 (slugbuilder) - slugbuilder: use shellcheck
  • +
  • 3afed2e (slugbuilder) - docker: simplify dockerfile
  • +
  • 36b7f68 (slugrunner) - docker: simplify dockerfile
  • +
+

Maintenance

+
    +
  • 61bb0ef (builder) - aws: upgrade aws sdk version
  • +
  • 0f2e074 (builder) - chore: use go mode replace dep
  • +
  • e9a2219 (builder) - builder: delete glide up
  • +
  • bb8c518 (builder) - registry: del quay.io
  • +
  • fa6d02f (builder) - builder: upgrade go.sum
  • +
  • 9d61e8d (builder) - build: upgrade go.mod
  • +
  • d763a98 (builder) - charts: upgrade k8s newer API versions
  • +
  • d1bc1aa (builder) - pkg: upgrade to new drycc/pkg
  • +
  • 02b1e98 (builder) - builder: update go mod
  • +
  • 8e17d65 (builder) - builder: change alpine repositories
  • +
  • f32b723 (builder) - mirrors: delete aliyun mirrors
  • +
  • e33dc61 (builder) - minio: use bin mc replace docker images
  • +
  • 3ab4f1c (builder) - builder: update controller-sdk-go
  • +
  • b2adfac (builder) - heroku: remove heroku-16 support
  • +
  • f429ac8 (builder) - builder: set GIT_LOCK_TIMEOUT to 30 minutes
  • +
  • 7197c83 (builder) - go.mod:upgrade require pkg controller-sdk-go
  • +
  • 5f3e22d (controller) - deps: bump django from 1.11.21 to 1.11.22 in /rootfs
  • +
  • 1db645a (controller) - deps: bump django from 1.11.22 to 1.11.23 in /rootfs
  • +
  • fbe8067 (controller) - deps: bump django from 1.11.23 to 1.11.29 in /rootfs
  • +
  • 537d667 (controller) - registry: del quay.io
  • +
  • a23c65b (controller) - deps: update all deps to the latest version
  • +
  • 546337e (controller) - charts: upgrade k8s newer API versions
  • +
  • 06023f8 (controller) - workflow-manager: del workflow-manager
  • +
  • bba5736 (controller) - controller: change cluster-issuer location
  • +
  • 6c43661 (controller) - Certificatechange cluster-issuer location
  • +
  • 39a4728 (controller) - controller:change cluster-issuer location del controller-cluster-issuer.yaml
  • +
  • 9e96d3f (controller) - Certificate:upgrade version cert-manager.io/v1alpha2
  • +
  • 8e68049 (controller) - docker: use INDEX_URL replace index.docker.io
  • +
  • 8fda205 (controller) - cert_manager: change certManagerEnabled to global
  • +
  • 6fefb6d (controller) - charts: change platformDomain to global
  • +
  • 064b2ad (controller) - maintenance: remove maintenance support
  • +
  • b8797c9 (controller) - workflow: remove namespace
  • +
  • 1b20d76 (controller) - quota: add kube quota config
  • +
  • d780075 (controller) - pod: add pod default resources support
  • +
  • 3d72c08 (controller) - rename: rename ingress name
  • +
  • 0aa6ab9 (controller) - mirrors: delete aliyun mirrors
  • +
  • 7533a65 (controller) - heroku: remove heroku-16 support
  • +
  • e5a885d (controller) - controller:check mount volume path
  • +
  • 9014e74 (controller) - test: optimization Dockerfile.test
  • +
  • 0b6ebb2 (controller) - tasks: change apply_async parameters
  • +
  • 835f009 (controller) - wsgi: add tornado 6 support
  • +
  • 67a4ad7 (controller) - utils: use threads replace asyncio
  • +
  • a28949b (controller) - ldap: add AUTH_LDAP_USER_FLAGS_BY_GROUP
  • +
  • a903209 (controller) - charts: add custom controller environment variables support
  • +
  • e0e783e (controller) - ldap: change filter style
  • +
  • d760825 (controller) - scheduler: remove debug log
  • +
  • a25928e (controller) - wsgi: remove a wsgi.py file
  • +
  • 7b2696e (controller) - log: disable nsq.client info log
  • +
  • 8d5c07b (controller) - charts: add default environment
  • +
  • 025f4a2 (controller) - controller: change quota name
  • +
  • ebda60e (controller) - controller: review pvc code
  • +
  • 8832ba9 (controller) - controller: change status\binding model type and mount path check container_types
  • +
  • 7148d04 (controller) - controller: add overcommit cpu and ram support
  • +
  • 4d2087c (controller) - limits: modify limits unit verification
  • +
  • af36970 (controller) - api: check cpu/memory range for api
  • +
  • 329355b (controller) - volumes: modify the volume size
  • +
  • 9dfee09 (controller) - LimitRanges: modify the default limits
  • +
  • 5205bca (controller) - controller: improve the details of certificate
  • +
  • 7ebecdf (database) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z
  • +
  • 6415e2c (database) - postgres: upgrade to pg13
  • +
  • 12e6806 (database) - charts: upgrade k8s newer API versions
  • +
  • d294509 (database) - minio: use canary minio test
  • +
  • 1bad02e (database) - mirrors: delete aliyun mirrors
  • +
  • d51420b (database) - minio: use bin mc replace docker images
  • +
  • 4133d05 (imagebuilder) - imagebuilder: update caddy and kaniko
  • +
  • 6b4dd18 (imagebuilder) - minio: use bin mc replace docker images
  • +
  • 6df9b7c (fluentd) - deps-dev: update rake requirement from ~> 10.0 to ~> 12.3
  • +
  • c2490f8 (fluentd) - fluentd: upgrade fluentd
  • +
  • be4a56a (fluentd) - fluentd: add Gemfile.lock
  • +
  • 2237f75 (fluentd) - charts: upgrade k8s newer API versions
  • +
  • c574065 (fluentd) - charts: upgrade k8s newer API versions
  • +
  • 52b8084 (fluentd) - router: delete obsolete router code
  • +
  • 3b3cceb (fluentd) - fluentd: remove manifests dir
  • +
  • 25c6702 (fluentd) - nsqd: change var name
  • +
  • bd571be (fluentd) - nsqd: change DRYCC_NSQD_ADDRESSES to DRYCC_NSQD_ADDRS
  • +
  • 72aa4e6 (fluentd) - influxdb: change influxdb service name
  • +
  • bd61903 (logger) - logger: use go mod replace dep
  • +
  • 69c63a1 (logger) - logger: update go.mod
  • +
  • 3aa9cd7 (logger) - registry: del quay.io
  • +
  • f058496 (logger) - nsqd: change var name
  • +
  • 6d9787c (logger) - nsqd: change DRYCC_NSQD_ADDRESSES to DRYCC_NSQD_ADDRS
  • +
  • 85ed307 (logger) - logger: standard naming
  • +
  • d88e7b6 (minio) - minio: update minio api to v7
  • +
  • 43715d2 (minio) - minio: upgrade minio
  • +
  • 0e1239b (minio) - minio: use docker.io replace quay.io
  • +
  • f7f047b (minio) - registry: del quay.io
  • +
  • afa7128 (minio) - build: upgrade go.mod
  • +
  • aff2db5 (minio) - charts: upgrade k8s newer API versions
  • +
  • 4547f14 (minio) - pkg: upgrade to new drycc/pkg
  • +
  • 2769b85 (minio) - minio: use bin mc replace docker images
  • +
  • 35dde8d (monitor) - monitor: update grafana influxdb telegraf
  • +
  • 9e3a949 (monitor) - charts: upgrade k8s newer API versions
  • +
  • 6af0432 (monitor) - workflow-manager: remove workflow-manager
  • +
  • 0611c07 (monitor) - router: delete obsolete router code
  • +
  • be04824 (monitor) - cert_manager: change certManagerEnabled to global
  • +
  • 3780165 (monitor) - charts: change platformDomain to global
  • +
  • 50b04e1 (monitor) - influxdb: remove influxdb admin ui
  • +
  • 6ab4d68 (monitor) - influxdb: remove unuse port
  • +
  • f1510bd (monitor) - monitor: update grafana dashboard,telegraf inputs.kubernetes
  • +
  • f36de2c (monitor) - pvc: upgrade to new format
  • +
  • fc78a0a (monitor) - workflow: remove namespace
  • +
  • e85890f (monitor) - monitor: monitoring nsqd and redis separately
  • +
  • 694f6b1 (monitor) - mirrors: delete aliyun mirrors
  • +
  • 4aea36a (monitor) - grafana: add ldap support for grafana
  • +
  • 68fc30f (nsqd) - nsq: update nsq
  • +
  • 16f32aa (nsqd) - charts: upgrade k8s newer API versions
  • +
  • 04db389 (redis) - reids: update to redis 6
  • +
  • 3f01bab (redis) - charts: upgrade k8s newer API versions
  • +
  • 647e4be (registry) - registry: del quay.io
  • +
  • 0bbce99 (registry) - charts: upgrade k8s newer API versions
  • +
  • a982b50 (registry) - minio: use bin mc replace docker images
  • +
  • e088da3 (registry-proxy) - ingress: renmae use_native_ingress to use_ingress
  • +
  • 7e88337 (registry-proxy) - nginx: upgrade nginx to mainline
  • +
  • 7204d72 (registry-proxy) - registry: optimizing variable naming
  • +
  • 2eafc59 (registry-proxy) - registry-proxy: update nginx
  • +
  • 071bd86 (registry-proxy) - charts: upgrade k8s newer API versions
  • +
  • c72db96 (registry-proxy) - registry-proxy: change travis icon url
  • +
  • ca9f962 (slugbuilder) - slugbuilder: del BUILDPACK_URL support
  • +
  • 1b74dd5 (slugbuilder) - slugbuilder: add heroku-20 support
  • +
  • 54d4ad2 (slugbuilder) - slugbuilder: del quay.io
  • +
  • a78f37e (slugbuilder) - slugbuilder: add heroku-20 stack
  • +
  • 94ac94a (slugbuilder) - minio: use bin mc replace docker images
  • +
  • 53b4b8b (slugbuilder) - slugbuilder: modify stack priority
  • +
  • 58e2bd2 (slugbuilder) - dockerfile: add WORKDIR /tmp
  • +
  • b29cd04 (slugbuilder) - slugbuilder: add pre_build.sh
  • +
  • 9d319f6 (slugbuilder) - slugbuilder: silent mc command output
  • +
  • d1ec3c9 (slugbuilder) - heroku: remove heroku-16 support
  • +
  • 5048534 (slugbuilder) - slugbuilder: use drycc stack-images
  • +
  • a116537 (slugrunner) - slugrunner: add heroku-20 support
  • +
  • a1196bf (slugrunner) - slugrunner: del quay.io
  • +
  • 64c96d7 (slugrunner) - slugrunner: add heroku-20 stack
  • +
  • cc3e226 (slugrunner) - minio: use bin mc replace docker images
  • +
  • 9130bde (slugrunner) - shellcheck: shellcheck installer
  • +
  • 4ea33e1 (slugrunner) - slugrunner: modify stack priority
  • +
  • 5514e8b (slugrunner) - heroku: remove heroku-16 support
  • +
  • be829fb (slugrunner) - slugrunner: use drycc stack-images
  • +
  • e1e06be (slugrunner) - slugrunner: remove Dockerfile.heroku-16
  • +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/changelogs/v1.5.0/index.html b/changelogs/v1.5.0/index.html new file mode 100644 index 000000000..9e04d342b --- /dev/null +++ b/changelogs/v1.5.0/index.html @@ -0,0 +1,1169 @@ + + + + + + + + + + + + + + + + + + v1.5.0 - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Workflow ## v1.4.0 -> v1.5.0

+

Releases

+
    +
  • passport v1.0.0
  • +
  • rabbitmq v1.0.0
  • +
  • imagebuilder v1.0.0
  • +
  • builder v1.2.0 -> v1.3.0
  • +
  • controller v1.3.0 -> v1.4.0
  • +
  • database v1.0.2 -> v1.1.0
  • +
  • fluentd v1.1.0 -> v1.2.0
  • +
  • redis v1.1.0 -> v1.2.0
  • +
  • influxdb v1.0.1 -> v1.1.0
  • +
  • logger v1.1.0 -> v1.2.0
  • +
  • minio v1.1.0 -> v1.2.0
  • +
  • monitor v1.1.0 -> v1.2.0
  • +
  • nsqd v1.1.0 -> v1.2.0
  • +
  • registry v1.0.3 -> v1.1.0
  • +
  • registry-proxy v1.0.2 -> v1.1.0
  • +
+

Features

+
    +
  • 0f5f8e4 (builder) - builder: multi-platform support
  • +
  • f269d06 (builder) - build: add buildx supportjkjkk:q
  • +
  • 5e72fe8 (builder) - registry: use docker build
  • +
  • 25d8a4c (builder) - docker: dealing with the change of docker in kubenetes 1.20
  • +
  • 7a3e1c5 (builder) - charts: set the default chart version
  • +
  • 46b75ff (builder) - builder: add cloud native buildpacks support
  • +
  • 2db2054 (builder) - builder: unified build model
  • +
  • 4b7f9d9 (builder) - builder: add initContainers
  • +
  • b78c936 (controller) - token: add get token api
  • +
  • bac52a5 (controller) - tasks: use celery replace nsqd
  • +
  • b9b0c58 (controller) - build: add buildx support
  • +
  • 205dcb3 (controller) - influxdb: add influxdb client
  • +
  • ff15849 (controller) - influxdb: upgrade to influxdb 2.x
  • +
  • 4016244 (controller) - controller: push data to influx
  • +
  • fcfce2e (controller) - workflow-manager: add workflow-manager support
  • +
  • 00e9bfb (controller) - influxdb: review influxdb code
  • +
  • dd644d5 (controller) - docker: dealing with the change of docker in kubenetes 1.20
  • +
  • 118278b (controller) - charts: set the default chart version
  • +
  • 122a9cd (controller) - oauth2: add oauth2 support
  • +
  • 559a5b6 (controller) - controller: use cncf buildpacks replace slugrunner
  • +
  • 96130e6 (controller) - charts: database configuration optimization of passport and controller
  • +
  • 2ea8508 (controller) - oauth: using passport authentication
  • +
  • 868c437 (database) - database: multi-platform support
  • +
  • eadd5da (database) - build: add buildx support
  • +
  • b6eea4c (database) - docker: dealing with the change of docker in kubenetes 1.20
  • +
  • 04a88db (database) - charts: set the default chart version
  • +
  • 92ed309 (database) - database: add initContainer
  • +
  • ee6b78f (fluentd) - build: add buildx support
  • +
  • f523e30 (fluentd) - docker: dealing with the change of docker in kubenetes 1.20
  • +
  • ee47b53 (fluentd) - charts: set the default chart version
  • +
  • 80a51af (influxdb) - influxdb: modify influxdb naming rules
  • +
  • fb10030 (influxdb) - influxdb: use influxdb v2
  • +
  • 0e87ad8 (influxdb) - docker: dealing with the change of docker in kubenetes 1.20
  • +
  • 9d10801 (influxdb) - charts: set the default chart version
  • +
  • d825c9f (logger) - build: add buildx support
  • +
  • b139576 (logger) - docker: dealing with the change of docker in kubenetes 1.20
  • +
  • 88f84ea (logger) - charts: set the default chart version
  • +
  • 5ccae3e (logger) - dockerfile: remove chmod cmd
  • +
  • 193aefc (logger) - logger: add initContainers
  • +
  • baee330 (minio) - minio: multi-platform support
  • +
  • ad5d055 (minio) - build: add buildx support
  • +
  • 19868d4 (minio) - docker: dealing with the change of docker in kubenetes 1.20
  • +
  • 4bd84b8 (minio) - charts: set the default chart version
  • +
  • 79d1f2f (monitor) - database: multi-platform support
  • +
  • 88e5a7f (monitor) - build: add buildx support
  • +
  • 5672e99 (monitor) - influxdb: modify influxdb naming rules
  • +
  • 8672103 (monitor) - influxdb: use influxdb v2
  • +
  • 66cb4c8 (monitor) - docker: dealing with the change of docker in kubenetes 1.20
  • +
  • 9576eb3 (monitor) - charts: set the default chart version
  • +
  • 30809c9 (monitor) - monitor: add initContainers
  • +
  • 70d140c (nsqd) - nsqd: using self compiled nsq binary
  • +
  • 1073d4f (nsqd) - nsqd: use GOPATH replace /go
  • +
  • e498480 (nsqd) - build: add buildx support
  • +
  • cf9b7d5 (nsqd) - docker: dealing with the change of docker in kubenetes 1.20
  • +
  • c335856 (nsqd) - charts: set the default chart version
  • +
  • efba713 (redis) - build: add buildx support
  • +
  • c7a3b53 (redis) - docker: dealing with the change of docker in kubenetes 1.20
  • +
  • 4cdad7b (redis) - charts: set the default chart version
  • +
  • 652b443 (registry) - registry: multi-platform support
  • +
  • 4060176 (registry) - registry: use docker build
  • +
  • 7102a03 (registry) - docker: dealing with the change of docker in kubenetes 1.20
  • +
  • 6c8600d (registry) - charts: set the default chart version
  • +
  • 33a51c9 (registry) - registry: add initContainers
  • +
  • bef70dc (registry-proxy) - build: add buildx support
  • +
  • d2319c1 (registry-proxy) - docker: dealing with the change of docker in kubenetes 1.20
  • +
  • 02fafed (registry-proxy) - charts: set the default chart version
  • +
+

Fixes

+
    +
  • 5499c9a (controller) - gunicorn: gunicorn not running
  • +
  • 06e9e88 (controller) - controller: error loading shared library
  • +
  • 01b5bd0 (controller) - controller: upgrade celery config
  • +
  • 6e32d55 (controller) - controller: fix update resources bug
  • +
  • 0e0d53f (controller) - chart: set the domain depends certManagerEnabled
  • +
  • 2ac4ca8 (controller) - passport: error loading shared library libexpat.so.1
  • +
  • a0dd517 (fluentd) - fluentd: drone build
  • +
  • 6eca2a3 (logger) - logger: golang lint
  • +
  • 63b0aa0 (registry) - drone: charts url error
  • +
+

Docs

+
    +
  • 472cfcc (controller) - controller organize README.md document
  • +
  • d9d6e29 (redis) - redis: delete links that do not exist
  • +
+

Test case

+
    +
  • 1468f57 (controller) - controller: add command unittest
  • +
+

Maintenance

+
    +
  • 9999bfd (builder) - builder:replace the special words
  • +
  • cda8b58 (builder) - builder: remove docker keyword from charts
  • +
  • dc575dd (builder) - builder: use imagebuilder replace dockerbuilder
  • +
  • d3bb183 (builder) - docker: use the full name of registry
  • +
  • 5fe34d1 (builder) - travis: add DEV_REGISTRY
  • +
  • 7e36453 (builder) - CICD: use drone
  • +
  • 52b8d9d (builder) - drone: add image_registries volumes
  • +
  • 65963f4 (builder) - k8s: add privileged to dind
  • +
  • d345fcf (builder) - LICENSE: revert modifications to Apache license
  • +
  • 7975c99 (builder) - drone: always pull image
  • +
  • 59633dd (builder) - builder: modify launch imagebuild pod
  • +
  • 8d14e67 (builder) - builder: use Procfile in anywhere
  • +
  • 5357fa8 (builder) - go: bump go mod
  • +
  • 8d26ac0 (builder) - k8s: k8s deprecated api migration
  • +
  • 0af620d (builder) - chars: change org to imageTag
  • +
  • ae84303 (builder) - builder: run imagebuider replace pod with job
  • +
  • 3b2c496 (builder) - builder: change docs website
  • +
  • 5679a4c (builder) - builder: upgrade to golang1.17
  • +
  • a214503 (controller) - controller:replace whitelist with allowlist
  • +
  • 375ddcc (controller) - ps:drycc ps:list show autoscale num
  • +
  • c32e409 (controller) - ldap: canot register when ldap is enabled
  • +
  • c46580a (controller) - controller:modify redis config
  • +
  • fa9e87b (controller) - chart:modify controller charts
  • +
  • 6f9fd08 (controller) - nsq: remove nsq
  • +
  • 994b2dc (controller) - docker-buildx: add check-docker
  • +
  • a720c3a (controller) - controller: remove docker keyword from charts
  • +
  • e9a5c84 (controller) - docker: use the full name of registry
  • +
  • a26614a (controller) - controller: add rabbitmq env
  • +
  • 3df229d (controller) - controller: modify database config && remove redis port config && add env prefix with DRYCC
  • +
  • 257e94b (controller) - controller: CELERY_BROKER use rabbitmq and modify celery-deployment cronjob
  • +
  • f4d6ec3 (controller) - chart: pretty chart format
  • +
  • 63e6195 (controller) - influxdb: modify influxdb code
  • +
  • 0f6d408 (controller) - CICD: use drone
  • +
  • 87bad28 (controller) - python: upgrade to python3.9
  • +
  • e8f7560 (controller) - volumes: modify mount summary
  • +
  • 6cf6c6b (controller) - drone: add image_registries volumes
  • +
  • a9397e8 (controller) - oauth: modify token Authentication
  • +
  • c7f8c8b (controller) - deps: bump django from 2.2.14 to 2.2.18 in /rootfs
  • +
  • a1a08aa (controller) - deps: bump djangorestframework from 3.11.0 to 3.11.2 in /rootfs
  • +
  • efd78b4 (controller) - deps: bump django from 2.2.18 to 2.2.20 in /rootfs
  • +
  • 649b044 (controller) - deps: bump django from 2.2.20 to 2.2.22 in /rootfs
  • +
  • 41b742b (controller) - deps: bump django from 2.2.22 to 2.2.24 in /rootfs
  • +
  • 22ffe5d (controller) - LICENSE: revert modifications to Apache license
  • +
  • c98b468 (controller) - drone: always pull image
  • +
  • 20e6edb (controller) - chart: modify the problem of using buildpack
  • +
  • db16879 (controller) - controller: pretty pods list print
  • +
  • ba6f456 (controller) - test: pretty pods list print
  • +
  • 5fce4b7 (controller) - k8s: k8s deprecated api migration
  • +
  • e9e0bcb (controller) - oauth: using passport authentication
  • +
  • 0311172 (controller) - chars: change org to imageTag
  • +
  • 150eff1 (controller) - charts: update cert-manager api version
  • +
  • de8545a (controller) - controller: update requirements
  • +
  • 1442207 (controller) - controller: using django native JSONFiled
  • +
  • ab4e836 (controller) - oauth: modify passport api
  • +
  • 5c54e06 (controller) - controller: eliminate pip warnings
  • +
  • 870328d (controller) - controller: remove entrypoint
  • +
  • 5e5e6ae (controller) - controller: upgrade celery config
  • +
  • 607778f (controller) - controller: add initContainer
  • +
  • 23dc016 (controller) - chart: set the domain depends certManagerEnabled
  • +
  • f3cf20b (controller) - controller: remove default bash env
  • +
  • 73f2636 (controller) - controller: modify alpinelinux repositories
  • +
  • 498e9f2 (controller) - chart: change certManagerEnabled to boolean type
  • +
  • 27f5308 (controller) - passport: exclude cryptography
  • +
  • 370b75d (controller) - controller: use sh env
  • +
  • 07585b4 (database) - postgres:replace the special words
  • +
  • 20172dc (database) - database: remove docker keyword from charts
  • +
  • abb9b88 (database) - docker: use the full name of registry
  • +
  • e72f58f (database) - chart: modify the off-cluster database
  • +
  • a91f64f (database) - travis: add DEV_REGISTRY
  • +
  • 614fb76 (database) - tests: use add-host replace link
  • +
  • a3428f3 (database) - CICD: use drone
  • +
  • 239fef1 (database) - drone: add image_registries volumes
  • +
  • 42858e1 (database) - LICENSE: revert modifications to Apache license
  • +
  • d0fe850 (database) - drone: always pull image
  • +
  • 34a36ad (database) - charts: Nn secret is generated during off-cluster
  • +
  • 064ccf4 (database) - database: create database
  • +
  • 9228992 (database) - chars: change org to imageTag
  • +
  • 9f7810c (database) - database: upgrade to wal-g v1.1
  • +
  • 05783f4 (fluentd) - fluentd:replace the special words
  • +
  • 0739809 (fluentd) - influxdb:replace monitor-influx with influx
  • +
  • f02487c (fluentd) - fluentd: remove docker keyword from charts
  • +
  • 2c96cc0 (fluentd) - docker: use the full name of registry
  • +
  • b20c429 (fluentd) - charts: remove port config
  • +
  • 6dd0197 (fluentd) - travis: add DEV_REGISTRY
  • +
  • c5bec51 (fluentd) - CICD: use drone
  • +
  • f8524b7 (fluentd) - drone: add image_registries volumes
  • +
  • a50878a (fluentd) - LICENSE: revert modifications to Apache license
  • +
  • 14fe20e (fluentd) - drone: always pull image
  • +
  • 4a2f660 (fluentd) - k8s: k8s deprecated api migration
  • +
  • de2dd91 (fluentd) - chars: change org to imageTag
  • +
  • a9f1944 (fluentd) - fluentd: upgrade to fluentd1.14
  • +
  • 7cb4e95 (influxdb) - influxdb: change username to user
  • +
  • 0fdc21b (influxdb) - influxdb: remove docker keyword from charts
  • +
  • b2acddb (influxdb) - influxdb: change default path
  • +
  • ba88919 (influxdb) - influxdb: add check_env function
  • +
  • 9117401 (influxdb) - influxdb: modify init_influxdb has_bucket
  • +
  • 092a3e6 (influxdb) - chart: pod not readiness
  • +
  • 51de380 (influxdb) - travis: add DEV_REGISTRY
  • +
  • 66d7667 (influxdb) - docker: replace influxdb base image
  • +
  • 3aa3094 (influxdb) - CICD: use drone
  • +
  • 14b9c24 (influxdb) - drone: add image_registries volumes
  • +
  • 02b4cd1 (logger) - logger:replace the special words
  • +
  • 114b5d5 (logger) - reids: delete the logger prefix of redis
  • +
  • 639278a (logger) - redis: remove logger from redis conf
  • +
  • 90195e2 (logger) - go: remove GOOS and GOARCH
  • +
  • 31e2e27 (logger) - logger: remove docker keyword from charts
  • +
  • 8fbd9fa (logger) - docker: use the full name of registry
  • +
  • b39df2d (logger) - charts: remove redis\nsqd port config
  • +
  • 35d6d07 (logger) - travis: add DEV_REGISTRY
  • +
  • 69aabf5 (logger) - tests: remove docker link
  • +
  • e916644 (logger) - CICD: use drone
  • +
  • d6872b7 (logger) - drone: add image_registries volumes
  • +
  • 37801da (logger) - LICENSE: revert modifications to Apache license
  • +
  • cfb4b38 (logger) - drone: always pull image
  • +
  • 8bda3bf (logger) - go: bump go mod
  • +
  • e13ebfc (logger) - chars: change org to imageTag
  • +
  • 38e6d8d (minio) - minio:replace the special words
  • +
  • d6925dd (minio) - minio: remove docker keyword from charts
  • +
  • d56bc39 (minio) - docker: use the full name of registry
  • +
  • e4696cc (minio) - travis: add DEV_REGISTRY
  • +
  • 70c5c79 (minio) - minio: use latest version
  • +
  • 773cf6c (minio) - Makefile: remove DEV_REGISTRY ?=
  • +
  • 5ce5bc6 (minio) - CICD: use drone
  • +
  • 5da8be3 (minio) - drone: add image_registries volumes
  • +
  • c1f0611 (minio) - LICENSE: revert modifications to Apache license
  • +
  • b73f792 (minio) - drone: always pull image
  • +
  • 79d1c93 (minio) - go: bump go mod
  • +
  • c448899 (minio) - chars: change org to imageTag
  • +
  • 15ee49e (minio) - minio: migrate deprecated warning
  • +
  • 9968a1a (minio) - minio: upgrade to golang1.7
  • +
  • 14fedd2 (monitor) - monitor:replace the special works
  • +
  • 52c431a (monitor) - reids: delete the logger prefix of redis
  • +
  • 2c95b47 (monitor) - redis: remove logger from redis conf
  • +
  • da9bc56 (monitor) - monitor:remove influxdb
  • +
  • 53f47b9 (monitor) - grafana: use grafana docker image
  • +
  • 5bdb188 (monitor) - grafana: use grafana docker image
  • +
  • c0586dd (monitor) - monitor: remove docker keyword from charts
  • +
  • 87d02b6 (monitor) - charts: add nodes and persistentvolumes rule
  • +
  • 1b5598f (monitor) - monitor: modify grafana dashboard with FLUX and pretty config.toml
  • +
  • bcbc0d5 (monitor) - docker: use the full name of registry
  • +
  • 9418c9e (monitor) - monitor: fix upload dashboard error and modify INFLUXDB input
  • +
  • 589f29a (monitor) - travis: add DEV_REGISTRY
  • +
  • f776f8a (monitor) - CICD: use drone
  • +
  • 6ca3060 (monitor) - drone: add image_registries volumes
  • +
  • 6a9ffb2 (monitor) - LICENSE: revert modifications to Apache license
  • +
  • 45e41ed (monitor) - drone: always pull image
  • +
  • 654d407 (monitor) - k8s: k8s deprecated api migration
  • +
  • 41e9b9c (monitor) - chars: change org to imageTag
  • +
  • 99c10d3 (monitor) - charts: update cert-manager api version
  • +
  • 9bf83c4 (monitor) - oauth: user oauth passport
  • +
  • a128f6d (monitor) - chart: change certManagerEnabled to boolean type
  • +
  • 8f897fe (monitor) - chart: set the domain depends certManagerEnabled
  • +
  • ba6d793 (nsqd) - README:update travis build status
  • +
  • 49879c4 (nsqd) - nsqd: minimum git clone code
  • +
  • c5e2680 (nsqd) - nsqd: remove docker keyword from charts
  • +
  • 21dd17b (nsqd) - docker: use the full name of registry
  • +
  • 7d86b3c (nsqd) - charts: remove port config
  • +
  • c073d95 (nsqd) - travis: add DEV_REGISTRY
  • +
  • 55c297c (nsqd) - CICD: use drone
  • +
  • 165c2ae (nsqd) - drone: add image_registries volumes
  • +
  • 9c6a1f8 (nsqd) - LICENSE: revert modifications to Apache license
  • +
  • 9283098 (nsqd) - drone: always pull image
  • +
  • 46acf8a (nsqd) - k8s: k8s deprecated api migration
  • +
  • 43caf80 (nsqd) - chars: change org to imageTag
  • +
  • 6897471 (nsqd) - nsqd: use official image
  • +
  • 297bc05 (redis) - redis:replace the special words
  • +
  • f5f8b5e (redis) - reids: delete the logger prefix of redis
  • +
  • af7b657 (redis) - redis: change logger-redis to redis
  • +
  • 8dca154 (redis) - redis: remove logger from redis conf
  • +
  • eaeda2d (redis) - redis: remove docker keyword from charts
  • +
  • 53c6358 (redis) - docker: use the full name of registry
  • +
  • ae37416 (redis) - charts: remove port config
  • +
  • e985656 (redis) - travis: add DEV_REGISTRY
  • +
  • 423336a (redis) - CICD: use drone
  • +
  • be64ab4 (redis) - drone: add image_registries volumes
  • +
  • 3bec735 (redis) - LICENSE: revert modifications to Apache license
  • +
  • 4f934f6 (redis) - drone: always pull image
  • +
  • 359b878 (redis) - chars: change org to imageTag
  • +
  • 83b8ac2 (registry) - workflow:replace the special words
  • +
  • 869b280 (registry) - registry: remove docker keyword from charts
  • +
  • 999c1e9 (registry) - docker: use the full name of registry
  • +
  • 5652da9 (registry) - travis: add DEV_REGISTRY
  • +
  • cc8c6c2 (registry) - CICD: use drone
  • +
  • c7bdbd0 (registry) - CICD: pretty .drone.yaml format
  • +
  • 5c55a38 (registry) - test: use add-host replace link
  • +
  • f8866f3 (registry) - drone: add image_registries volumes
  • +
  • 6c8292f (registry) - LICENSE: revert modifications to Apache license
  • +
  • 1d50f2c (registry) - drone: always pull image
  • +
  • efbca6d (registry) - chars: change org to imageTag
  • +
  • 2eafc59 (registry-proxy) - registry-proxy: update nginx
  • +
  • 071bd86 (registry-proxy) - charts: upgrade k8s newer API versions
  • +
  • c72db96 (registry-proxy) - registry-proxy: change travis icon url
  • +
  • 63ffb92 (registry-proxy) - registry-proxy:replace the special works
  • +
  • 1d904a6 (registry-proxy) - registry-proxy: remove docker keyword from charts
  • +
  • c8200b1 (registry-proxy) - docker: use the full name of registry
  • +
  • d3fa939 (registry-proxy) - travis: add DEV_REGISTRY
  • +
  • 5a8b353 (registry-proxy) - CICD: use drone
  • +
  • 703d05a (registry-proxy) - drone: add image_registries volumes
  • +
  • aa71db1 (registry-proxy) - LICENSE: revert modifications to Apache license
  • +
  • 710c126 (registry-proxy) - drone: always pull image
  • +
  • 2dcc5e6 (registry-proxy) - chars: change org to imageTag
  • +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/changelogs/v1.6.0/index.html b/changelogs/v1.6.0/index.html new file mode 100644 index 000000000..0c37fd3a8 --- /dev/null +++ b/changelogs/v1.6.0/index.html @@ -0,0 +1,1313 @@ + + + + + + + + + + + + + + + + + + V1.6.0 - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Workflow ## v1.5.0 -> v1.6.0

+

Releases

+
    +
  • builder v1.3.0 -> v1.4.0
  • +
  • controller v1.4.0 -> v1.5.0
  • +
  • passport v1.0.0 -> v1.1.0
  • +
  • database v1.1.0 -> v1.2.0
  • +
  • imagebuilder v1.0.1 -> v1.1.0
  • +
  • fluentd v1.2.0 -> v1.3.0
  • +
  • logger v1.2.0 -> v1.3.0
  • +
  • storage v1.2.0 -> v1.3.0
  • +
  • monitor v1.2.0 -> v1.3.0
  • +
  • redis v1.2.0 -> v1.3.0
  • +
  • influxdb v1.1.0 -> v1.2.0
  • +
  • rabbitmq v1.0.0 -> v1.1.0
  • +
  • registry v1.1.0 -> v1.2.0
  • +
  • registry-proxy v1.1.0 -> v1.2.0
  • +
+

Features

+
    +
  • 52517d9 (builder) - builder: update controller-sdk-go
  • +
  • 1d78ca0 (builder) - builder: add affinity
  • +
  • 26b6980 (builder) - builder: switch charts to oci
  • +
  • bfd4385 (controller) - controller: add get manager user status
  • +
  • 874208d (controller) - controller: unified measurement model
  • +
  • cadf98f (controller) - controller: add admission webhook
  • +
  • e0050c2 (controller) - controller: new measurement model
  • +
  • a11ba58 (controller) - controller: multi pod restart uses async
  • +
  • fb3c15d (controller) - controller: add check app owner status
  • +
  • 3d78b76 (controller) - controller: add resource services api
  • +
  • 3d6a201 (controller) - controller: add search apps api
  • +
  • 01c443a (controller) - controller: add KUBERNETES_CPU_MEMORY_RATIO parameter
  • +
  • 7c26232 (controller) - controller: add volume size limit
  • +
  • 3bee749 (controller) - controller: add annotations support
  • +
  • 23cd97c (controller) - controller: traefik v2 support
  • +
  • e37b7db (controller) - controller: add affinity
  • +
  • b3b367b (controller) - controller: add volume expand support
  • +
  • a4e154a (controller) - controller: add database replica support
  • +
  • 2f37216 (controller) - controller: switch wsgi to asgi
  • +
  • b3314a5 (controller) - controller: add pod exec api
  • +
  • 75df2dc (controller) - controller: add stream support for app logs
  • +
  • 4229bad (controller) - ccontroller: switch charts to oci
  • +
  • 89bb19b (database) - database: upgrade to pg14
  • +
  • 9f45a5d (database) - database: add hugepages support
  • +
  • c4008c9 (database) - database: add affinity
  • +
  • 411a7b2 (database) - postgres: use patroni
  • +
  • 64e5cb0 (database) - database: switch charts to oci
  • +
  • 2bab823 (fluentd) - fluentd: switch charts to oci
  • +
  • 337ba62 (imagebuilder) - imagebuilder: run podman as rootless
  • +
  • 4396ffa (imagebuilder) - imagebuilder: switch to oci charts
  • +
  • f37ae09 (influxdb) - influxdb: add affinity
  • +
  • 04503b2 (influxdb) - influxdb: add influxdb ha
  • +
  • 41ddad5 (influxdb) - influxdb: switch charts to oci
  • +
  • 2006480 (logger) - logger: use redis stream replace nsqd
  • +
  • ab23d17 (logger) - logger: add affinity
  • +
  • 81d4e9d (logger) - logger: switch charts to oci
  • +
  • c3d9796 (monitor) - monitor: add affinity
  • +
  • cd9de3c (monitor) - monitor: switch to oci charts
  • +
  • 318a73f (passport) - passport: add change user confirm
  • +
  • 79ef100 (passport) - passport: add re login at authorize
  • +
  • 6927bb5 (passport) - passport: add affinity
  • +
  • 3146a09 (passport) - passport: add google reCAPTCHA
  • +
  • 802abcd (passport) - passport: add replica database support
  • +
  • a0dcd1b (passport) - passport: switch wsgi to asgi
  • +
  • 4c9dbba (passport) - passport: switch charts to oci
  • +
  • 74825f7 (rabbitmq) - rabbitmq: add rabbitmq managentment ingress
  • +
  • 12cf7d6 (rabbitmq) - rabbitmq: add affinity
  • +
  • 103417d (rabbitmq) - rabbitmq: switch charts to oci
  • +
  • 5d428bb (redis) - redis: add affinity
  • +
  • a88c1a9 (redis) - redis: switch charts to oci
  • +
  • 541585d (registry) - registry: add affinity
  • +
  • e9ca9d4 (registry) - registry: add garbage-collect cronjob
  • +
  • ec62a59 (registry) - registry: switch charts to oci
  • +
  • fde0b07 (registry-proxy) - registry-proxy: switch charts to oci
  • +
  • be14eb4 (storage) - minio: add affinity
  • +
  • 51af696 (storage) - storage: add k8s csi support
  • +
  • 76a75d9 (storage) - storage: add cluster health checker
  • +
  • a17dc8c (storage) - storage: switch charts to oci
  • +
+

Fixes

+
    +
  • e4f44fb (builder) - builder: no error return
  • +
  • e38dfc7 (builder) - builderControllerHost/ControllerPort init error
  • +
  • ff9069f (controller) - controller: influxdb query error
  • +
  • f7f5069 (controller) - controller: authentication 500
  • +
  • 7e297a8 (controller) - controller: add check remote user status
  • +
  • 9db28e1 (controller) - controller: celery MaxRetriesExceededError
  • +
  • 4bcff08 (controller) - controller: wrong name
  • +
  • d69fde2 (controller) - controller: traefik ingress create error
  • +
  • a3ad743 (controller) - fixup(controller: user login error
  • +
  • 662c8dd (controller) - controller: change influxdb port
  • +
  • 957bdf6 (controller) - controller: validate rsa key pairing before storage
  • +
  • 419ec4c (controller) - controller: kubernetes pod/exec cluster role
  • +
  • a67edaa (controller) - controller: Cannot routing:disable
  • +
  • e09e214 (controller) - controller: allowlist cannot remove
  • +
  • 318b126 (controller) - controller: domains update error
  • +
  • 92855eb (database) - database: premission denied
  • +
  • bde945a (database) - fixup(postgres: support arm, fix Failed to build psutil
  • +
  • 7854d45 (database) - fixup(postgres: user name converted to lowercase letters
  • +
  • 57b2a07 (fluentd) - fluentd: ifconfig_path not found
  • +
  • 20e72b9 (imagebuilder) - imagebuilder: upgrade pack version
  • +
  • 651db8a (imagebuilder) - imagebuilder: chown uid gid order
  • +
  • d2e9164 (influxdb) - influxdb: proxy not running
  • +
  • 3a1d361 (monitor) - monitor: charts naming
  • +
  • d754ae0 (monitor) - monitor: telegraf init error
  • +
  • 63f9e34 (monitor) - monitor: affinity error
  • +
  • 95ae1e5 (passport) - passport: yarn build fail
  • +
  • 3f5365e (passport) - passport: wrong name
  • +
  • 907f17b (passport) - passport: change uid gid to 1001
  • +
  • e3911e0 (passport) - passport: 'registration_done' not found
  • +
  • 2ace5f0 (passport) - passport: ui style
  • +
  • b3ba1e1 (passport) - passport privacy policy link
  • +
  • 172e9c8 (passport) - passport: check databaseReplicaUrl error
  • +
  • a3aeb70 (rabbitmq) - passport: change uid gid to 1001
  • +
  • 5c73dcf (redis) - reids: DRYCC_REGISTY misspelling
  • +
  • d7e3baf (redis) - redis: env miss
  • +
  • cadaa91 (registry) - registry: set gid uid to 1001
  • +
  • d524217 (registry) - registry: storage run error
  • +
  • 854f912 (registry) - registry: chown uid gid order
  • +
  • e642bb7 (registry-proxy) - registry-proxy: containerPort error
  • +
  • 8dfd029 (registry-proxy) - registry-proxy: chown uid gid order
  • +
  • bbea364 (storage) - minio: premission denied
  • +
  • 97deba1 (storage) - storage: node unimplemented error
  • +
  • b9bdeff (storage) - storage: pd can not connect each other
  • +
+

Style

+
    +
  • 1edb10c (controller) - controller: database convention over configuration
  • +
  • 1960cc3 (database) - database: database name convention over configuration
  • +
  • 06d1f5d (imagebuilder) - imagebuilder: URL to Url
  • +
  • b8a8941 (passport) - passport: database convention over configuration
  • +
+

Maintenance

+
    +
  • 8e9a199 (builder) - builder: upgrade controller-sdk-go
  • +
  • 4840151 (builder) - builder: use exec runner replace docker runner
  • +
  • 68ccfb1 (builder) - builder: canonical charts naming
  • +
  • 8f971cb (builder) - builder: provide any additional service annotations
  • +
  • fe2c55d (builder) - dockerfile: use drycc/base image
  • +
  • 2b5e706 (builder) - dockerfile: change user and workdir
  • +
  • 7a6c8d3 (builder) - builder: set gid uid to 1001
  • +
  • fe494f7 (builder) - dockerfile: use uid gid
  • +
  • a7c8752 (builder) - builder: change nodes to pod affinity
  • +
  • eb2e94c (builder) - database: bump mc 2022.04.01.23.44.48
  • +
  • cfaae66 (builder) - builder: use registry.drycc.cc replace docker.io
  • +
  • d7d2890 (builder) - builder: change default imagebuilder registry
  • +
  • ecfdb19 (builder) - imagebuilder: change python-dev registry
  • +
  • 6da17f4 (builder) - builder: https://github.com/minio/minio/issues/14331
  • +
  • 1a57e5b (builder) - builder: https://github.com/minio/minio/issues/14331
  • +
  • f1464fa (builder) - builder: https://github.com/minio/minio/issues/13799
  • +
  • b1e1c4f (builder) - builder: use env replace creds volume
  • +
  • 71a4145 (builder) - builder: bump go.mod
  • +
  • 3567688 (builder) - builder: fine management affinity
  • +
  • 73ea38b (builder) - builder: change storage to minio
  • +
  • 1f91321 (builder) - builder: use testify replace assert
  • +
  • d148b9c (builder) - builder: add check storage health
  • +
  • b768101 (builder) - builder: change initContainers
  • +
  • 1b3bec3 (builder) - builder: add replicas
  • +
  • 5cb0d61 (builder) - builder: upgrade to latest controller-sdk-go
  • +
  • 98b9d58 (builder) - builder: upgrade new require
  • +
  • 65817c3 (builder) - builder: change drycc.cc to www.drycc.cc
  • +
  • 4e3f9d0 (controller) - controller: add celery retry mechanism
  • +
  • f6716fe (controller) - controller: change cronjob name
  • +
  • eb60693 (controller) - controller: refine celery task priority
  • +
  • 66905e9 (controller) - controller: change manager auth
  • +
  • ea20c41 (controller) - controller: remove start/stop api
  • +
  • 4c8fc80 (controller) - controller: improve tasks error handling
  • +
  • cf7402e (controller) - controller: add blocklist api
  • +
  • 80f14dd (controller) - controller: use get_user_model replace auth.User
  • +
  • ffc7bb7 (controller) - controller: use JSONField replace ArrayField
  • +
  • 370df8c (controller) - controller: add validate metric
  • +
  • 29084ce (controller) - controller: use user id request manager api
  • +
  • 718fe12 (controller) - controller change urlpatterns order
  • +
  • 71f4042 (controller) - controller: measurements uses lowercase letters
  • +
  • e5123ea (controller) - controller: change resource unit to number
  • +
  • 18fee9a (controller) - deps: bump celery from 5.1.2 to 5.2.2 in /rootfs
  • +
  • ffca6c1 (controller) - controller: use exec runner replace docker runner
  • +
  • 9ec12e1 (controller) - controller: simplify drone configuration
  • +
  • 4b4749e (controller) - controller: set default CSRF_COOKIE_SECURE false
  • +
  • 2ef6338 (controller) - deps: bump django from 3.2.5 to 3.2.10 in /rootfs
  • +
  • c7570d0 (controller) - deps: bump django from 3.2.10 to 3.2.11 in /rootfs
  • +
  • 8b17bc1 (controller) - controller: canonical charts naming
  • +
  • c928fb0 (controller) - controller: use rabbitmq cluster
  • +
  • f917185 (controller) - controller: provide any additional service annotations
  • +
  • 22a8f63 (controller) - deps: bump django from 3.2.11 to 3.2.12 in /rootfs
  • +
  • 3cc3b00 (controller) - dockerfile: use drycc/base image
  • +
  • ee274f6 (controller) - controller: set venv profile
  • +
  • ce6b069 (controller) - controller: set gid uid to 1001
  • +
  • 3a105d3 (controller) - dockerfile: use uid gid
  • +
  • 15f9b0e (controller) - controller: code review
  • +
  • 01e6fd9 (controller) - controller: use passport user id
  • +
  • 893ee31 (controller) - oauth2: update user info pipline
  • +
  • 3028fb4 (controller) - user: set AnonymousUser username
  • +
  • 5daf82d (controller) - controller: set worker_cancel_long_running_tasks_on_connection_loss
  • +
  • 61f2c53 (controller) - controller: change nodes to pod affinity
  • +
  • 88feb1d (controller) - imagebuilder: python=3.10.4 rabbitmq=3.9.14
  • +
  • 914e03f (controller) - controller: use registry.drycc.cc replace docker.io
  • +
  • a5bb548 (controller) - controller: change python-dev registry
  • +
  • 3ecdd7c (controller) - controller: add a separate rabbitmqUrl configuration
  • +
  • 967cb11 (controller) - controller: remove APP_STORAGE
  • +
  • 473d2b5 (controller) - controller: use env replace creds volume
  • +
  • e410d4c (controller) - deps: bump django from 3.2.12 to 3.2.13 in /rootfs
  • +
  • c6ef777 (controller) - controller: simplified passport config
  • +
  • 0fd3233 (controller) - controller: remove settings hardcode
  • +
  • a64e99c (controller) - controller: change passport config
  • +
  • 62aba25 (controller) - controller: set cronjob timezone to utc
  • +
  • 760b70b (controller) - controller: change default ratio
  • +
  • 8dffc3a (controller) - controller: fine management affinity
  • +
  • 26043c4 (controller) - controller: change default app storage
  • +
  • 608bd8d (controller) - deps: bump django from 3.2.13 to 3.2.14 in /rootfs
  • +
  • 18ed0c2 (controller) - controller: remove conjob affinity
  • +
  • add6712 (controller) - controller: add volume expand support use patch
  • +
  • cc1ad13 (controller) - controller: add startupProbe
  • +
  • 0e9a603 (controller) - controller: add clearsocial cronjob
  • +
  • eb6f05d (controller) - controller: change initContainers
  • +
  • 762c676 (controller) - controller: change replicas
  • +
  • abd7e8c (controller) - deps: bump django from 3.2.14 to 3.2.15 in /rootfs
  • +
  • 07fdf1b (controller) - controller: remove database conn_max_age
  • +
  • ef8e41f (controller) - controller: add database replica check
  • +
  • 79143f2 (controller) - controller: upgrade new require
  • +
  • a624048 (controller) - controller: add app.refresh func annotation
  • +
  • b22d367 (controller) - controller: optimize app refresh timing
  • +
  • fe98f0c (database) - database: use exec runner replace docker runner
  • +
  • 5e00c11 (database) - database: canonical charts naming
  • +
  • d2cb860 (database) - database: disable huge_pages
  • +
  • 197d80d (database) - database: add persistence
  • +
  • 1c3e645 (database) - database: provide any additional service annotations
  • +
  • 37730ab (database) - dockerfile: use drycc/base image
  • +
  • 5014112 (database) - dockerfile: change entrypoint
  • +
  • 29b538e (database) - database: change nodes to pod affinity
  • +
  • c2bb074 (database) - database: bump python 3.10.4 and mc 2022.04.01.23.44.48
  • +
  • 077a4e9 (database) - database: use registry.drycc.cc replace docker.io
  • +
  • 560bdb9 (database) - database: change python-dev registry
  • +
  • 1e54b55 (database) - database: https://github.com/minio/minio/issues/14331
  • +
  • d646672 (database) - database: https://github.com/minio/minio/issues/13799
  • +
  • a6ac4e3 (database) - database: use env replace creds volume
  • +
  • 9618d87 (database) - database: fine management affinity
  • +
  • b823273 (database) - database: change minio to storage
  • +
  • 7bd5a90 (database) - database: add check storage health
  • +
  • 20c6d96 (database) - database: fix storage run error
  • +
  • 8bde830 (database) - database: upgrade to pg 14.5
  • +
  • a33b5e5 (fluentd) - fluentd: update plugins
  • +
  • eed7a78 (fluentd) - fluentd: update filter kubernetes setting
  • +
  • cc83dd8 (fluentd) - fluentd: update elasticsearch store setting and support exclude specific container logs
  • +
  • ba2feb2 (fluentd) - fluentd: use exec runner replace docker runner
  • +
  • d528676 (fluentd) - fluentd: simplify drone configuration
  • +
  • dece82d (fluentd) - fluentd: canonical charts naming
  • +
  • 4e0a802 (fluentd) - fluend: replace nsqd with redis
  • +
  • 15ceca0 (fluentd) - dockerfile: use drycc/base image
  • +
  • a7f619f (fluentd) - dockerfile: change workdir
  • +
  • 9adf5ed (fluentd) - database: bump fluentd 1.14.6
  • +
  • 50c14c2 (fluentd) - fluentd: use registry.drycc.cc replace docker.io
  • +
  • 83171b1 (fluentd) - fluentd: change python-dev registry
  • +
  • ec83581 (fluentd) - fluentd: unified reids declaration
  • +
  • 07c63e2 (fluentd) - fluentd: upgrade fluentd 1.15.2
  • +
  • 65df9be (imagebuilder) - imagebuilder: update pack version
  • +
  • 66cab35 (imagebuilder) - imagebuilder: use dind replace go-dev
  • +
  • 0c82060 (imagebuilder) - imagebuilder: use exec runner replace docker runner
  • +
  • 8146da9 (imagebuilder) - imagebuilder: canonical charts naming
  • +
  • 7d97241 (imagebuilder) - dockerfile: use drycc/base image
  • +
  • 07e805c (imagebuilder) - imagebuilder: change default buildpack
  • +
  • 8d1038d (imagebuilder) - imagebuilder: upgrade podman to 4.0.1
  • +
  • 62d3687 (imagebuilder) - imagebuilder: change workdir to /workspace
  • +
  • da8bfb0 (imagebuilder) - imagebuilder: change uid gid to 1001
  • +
  • d44e3bc (imagebuilder) - imagebuilder: upgrade stack
  • +
  • 5b0c7e6 (imagebuilder) - imagebuilder: use registry.drycc.cc replace docker.io
  • +
  • f74cbf6 (imagebuilder) - imagebuilder: add defaultBuildpacksURL
  • +
  • 941d493 (imagebuilder) - imagebuilder: https://github.com/minio/minio/issues/14331
  • +
  • 449be91 (imagebuilder) - imagebuilder: https://github.com/minio/minio/issues/13799
  • +
  • 63b0523 (imagebuilder) - imagebuilder: use env replace creds volume
  • +
  • 4e8a6e5 (imagebuilder) - imagebuilder: add imagebuilder config
  • +
  • 2d891f5 (imagebuilder) - imagebuilder: change minio to storage
  • +
  • addceda (imagebuilder) - imagebuilder: upgrade new require
  • +
  • a6e569f (imagebuilder) - imagebuilder: pack_build add --env-file parameter
  • +
  • 6191ff5 (influxdb) - influxdb: use exec runner replace docker runner
  • +
  • dc3f8c7 (influxdb) - influxdb: canonical charts naming
  • +
  • 6b5c819 (influxdb) - influxdb: new ingress style
  • +
  • 68b381d (influxdb) - influxdb: provide any additional service annotations
  • +
  • ea20eb8 (influxdb) - dockerfile: use drycc/base image
  • +
  • 64c0a71 (influxdb) - influxdb: set gid uid to 1001
  • +
  • a709ca1 (influxdb) - influxdb: use DRYCC_UID DRYCC_GID env
  • +
  • 740dff0 (influxdb) - influxdb: use common affinity template
  • +
  • e035673 (influxdb) - influxdb: change nodes to pod affinity
  • +
  • f1cefbd (influxdb) - influxdb: use registry.drycc.cc replace docker.io
  • +
  • a00100e (influxdb) - influxdb: fine management affinity
  • +
  • 9d165ef (influxdb) - influxdb: add probe
  • +
  • bee7fff (influxdb) - influxdb: upgrade to influxdb 2.4.0
  • +
  • 254914c (logger) - logger: use exec runner replace docker runner
  • +
  • 8d91c68 (logger) - logger: canonical charts naming
  • +
  • b6d2182 (logger) - logger: provide any additional service annotations
  • +
  • c35e59a (logger) - dockerfile: use drycc/base image
  • +
  • a63c070 (logger) - logger: change workdir to /workspace
  • +
  • a594b28 (logger) - logger: set gid uid to 1001
  • +
  • 9a90e22 (logger) - dockerfile: use uid gid
  • +
  • 36493b4 (logger) - logger: use common affinity template
  • +
  • 897a3a5 (logger) - logger: change nodes to pod affinity
  • +
  • 03b32ab (logger) - logger: use registry.drycc.cc replace docker.io
  • +
  • a50ba5f (logger) - logger: change python-dev registry
  • +
  • 23187a3 (logger) - logger: unified reids declaration
  • +
  • aaa129a (logger) - logger: fine management affinity
  • +
  • be4f656 (logger) - logger: add replicas
  • +
  • 7c25459 (logger) - charts: add NetworkPolicy
  • +
  • 6810149 (logger) - logger: remove memory storage
  • +
  • a918c50 (logger) - logger: add .vscode to .gitignore
  • +
  • a415210 (logger) - logger: add log follow support
  • +
  • 59b1da3 (logger) - logger: upgrade new require
  • +
  • 27cc151 (monitor) - monitor: use exec runner replace docker runner
  • +
  • 07d6a9d (monitor) - monitor: canonical charts naming
  • +
  • 1054357 (monitor) - monitor: use redis default port
  • +
  • e3673df (monitor) - monitor: remove nsqd
  • +
  • fc9dd3e (monitor) - monitor: new ingress style
  • +
  • 856a898 (monitor) - monitor: add default user env
  • +
  • 9857535 (monitor) - monitor: add random user
  • +
  • 38b5a04 (monitor) - grafana: oauth auto login
  • +
  • 5dfc579 (monitor) - monitor: upgrade version
  • +
  • e121b5a (monitor) - monitor: provide any additional service annotations
  • +
  • 84462a0 (monitor) - dockerfile: use drycc/base image
  • +
  • b9e8ce8 (monitor) - monitor: chore(imagebuilder): change uid gid to 1001
  • +
  • 05ee8ab (monitor) - dockerfile: use uid gid
  • +
  • e1fa68e (monitor) - monitor: use common affinity template
  • +
  • b8f302b (monitor) - monitor: change nodes to pod affinity
  • +
  • 4fc991f (monitor) - database: bump telegraf 1.22.0 and grafana 8.4.5
  • +
  • 21a2f6a (monitor) - monitor: use registry.drycc.cc replace docker.io
  • +
  • acc976f (monitor) - monitor: change python-dev registry
  • +
  • 62d76c1 (monitor) - monitor: unified reids declaration
  • +
  • b3c57ad (monitor) - monitor: optimize oauth2 configuration
  • +
  • 70af6b0 (monitor) - monitor: change passport config
  • +
  • 69f9a88 (monitor) - monitor: fine management affinity
  • +
  • 2fb278f (monitor) - monitor: rename influxdb port
  • +
  • 17548ff (monitor) - grafana: update dashborad
  • +
  • 69d7bbd (monitor) - grafana: influx dashborad disk size
  • +
  • 75db1b0 (monitor) - monitor: upgrade new grafana/telegraf
  • +
  • 80504a1 (monitor) - grafana: update influx and redis dashboard
  • +
  • f7078cb (monitor) - monitor:chown use env
  • +
  • 91ae0dd (passport) - passport: optimize login display
  • +
  • 2d3bbbc (passport) - passport: change drycc logo
  • +
  • 59790a7 (passport) - passport: make user email unique
  • +
  • faea034 (passport) - passport: use strtobool
  • +
  • 1fbf2bc (passport) - passport: use yarn replace npm
  • +
  • 119cac8 (passport) - passport: use exec runner replace docker runner
  • +
  • cff5062 (passport) - passport: set default CSRF_COOKIE_SECURE false
  • +
  • 9cc0210 (passport) - passport: canonical charts naming
  • +
  • 9ab3896 (passport) - passport: new ingress style
  • +
  • 259ccc9 (passport) - passport: provide any additional service annotations
  • +
  • af1bbcd (passport) - dockerfile: use drycc/base image
  • +
  • 9ae5373 (passport) - passport: set venv profile
  • +
  • 8f61090 (passport) - dockerfile: use uid gid
  • +
  • fcaf72d (passport) - passport: upgrade npm package
  • +
  • 546dcd5 (passport) - passport: add license
  • +
  • 4bda2d6 (passport) - passport: use minify
  • +
  • 73b0fd1 (passport) - passport: use common affinity template
  • +
  • 278fe7a (passport) - passport: change nodes to pod affinity
  • +
  • 3cd93d3 (passport) - passport: add reactive
  • +
  • 370b493 (passport) - passport: add footer
  • +
  • 483cbd6 (passport) - passport: use h_captcha replace re_captcha
  • +
  • 3d1675e (passport) - database: bump python 3.10.4 and node 16.14.2
  • +
  • 86a7835 (passport) - passport: use registry.drycc.cc replace docker.io
  • +
  • 2d65355 (passport) - passport: change python-dev registry
  • +
  • 90c1444 (passport) - passport: unified reids declaration
  • +
  • 2e0e417 (passport) - passport: fix firefox footer
  • +
  • ad274be (passport) - passport: use bulecss
  • +
  • f986d8b (passport) - passport: add main footer
  • +
  • 3e52867 (passport) - passport: dynamic settings for vue
  • +
  • 38adabc (passport) - passport: change passport config
  • +
  • f8d6b60 (passport) - passport: fine management affinity
  • +
  • 2cbd79d (passport) - passport: remove database conn_max_age
  • +
  • 7122797 (passport) - passport: change drycc.cc to www.drycc.cc
  • +
  • 8cc84cd (rabbitmq) - rabbitmq: use exec runner replace docker runner
  • +
  • f35930f (rabbitmq) - rabbitmq: add rabbitmq cluster support
  • +
  • fbfa3ba (rabbitmq) - rabbitmq: canonical charts naming
  • +
  • ca60701 (rabbitmq) - rabbitmq: use volumeClaimTemplates
  • +
  • fe5d1b4 (rabbitmq) - rabbitmq: add sharding support
  • +
  • 9c4ab97 (rabbitmq) - rabbitmq: provide any additional service annotations
  • +
  • 348a88a (rabbitmq) - dockerfile: use drycc/base image
  • +
  • 2388be1 (rabbitmq) - rabbitmq: upgrade erlang to 24.2.2
  • +
  • db2eaa5 (rabbitmq) - dockerfile: use uid gid
  • +
  • 772afd1 (rabbitmq) - rabbitmq: change to wait pid file
  • +
  • 2bfc25e (rabbitmq) - rabbitmq: use common affinity template
  • +
  • 11d505e (rabbitmq) - rabbitmq: change nodes to pod affinity
  • +
  • 69d63f1 (rabbitmq) - database: bump erlang 24.3.3 and rabbitmq 3.9.14
  • +
  • 8380299 (rabbitmq) - rabbitmq: use registry.drycc.cc replace docker.io
  • +
  • b3f69f1 (rabbitmq) - rabbitmq: add check rabbitmqLocaltion
  • +
  • 5327c76 (rabbitmq) - rabbitmq: fine management affinity
  • +
  • 5c66b5a (rabbitmq) - rabbitmq: change probe
  • +
  • 27bebf9 (rabbitmq) - rabbitmq: add start-rabbitmq script
  • +
  • 86ee6a7 (rabbitmq) - rabbitmq: upgrade to rabbitmq 3.10.7
  • +
  • 1f29683 (redis) - redis: use exec runner replace docker runner
  • +
  • a5041fc (redis) - redis: canonical charts naming
  • +
  • 64468c2 (redis) - redis: add redis persistence
  • +
  • de5d753 (redis) - redis: provide any additional service annotations
  • +
  • f644639 (redis) - dockerfile: use drycc/base image
  • +
  • 98051d2 (redis) - redis: premission denied
  • +
  • bcb548e (redis) - dockerfile: use uid gid
  • +
  • 524aa41 (redis) - redis: use common affinity template
  • +
  • 26c9466 (redis) - redis: change nodes to pod affinity
  • +
  • b67d7a2 (redis) - redis: use registry.drycc.cc replace docker.io
  • +
  • 839ec50 (redis) - redis: use env replace creds volume
  • +
  • 237ca86 (redis) - redis: fine management affinity
  • +
  • bdd968d (redis) - redis: upgrade neew require
  • +
  • 8b2910f (registry) - registry: use exec runner replace docker runner
  • +
  • eedbe78 (registry) - registry: canonical charts naming
  • +
  • 0241615 (registry) - registry: provide any additional service annotations
  • +
  • 9b58da4 (registry) - dockerfile: use drycc/base image
  • +
  • ab6acb7 (registry) - registry: change workdir to /workspace
  • +
  • f368bf7 (registry) - registry: use DRYCC_UID DRYCC_GID env
  • +
  • f4b9041 (registry) - registry: use common affinity template
  • +
  • c2e87ca (registry) - registry: change nodes to pod affinity
  • +
  • feb6aba (registry) - database: bump mc 2022.04.01.23.44.48
  • +
  • 956932b (registry) - rregistry: use registry.drycc.cc replace docker.io
  • +
  • deda8d8 (registry) - registry: move registry-secret.yaml from workflow to registry
  • +
  • f52c7bf (registry) - registry: change python-dev registry
  • +
  • 007fe03 (registry) - registry: https://github.com/minio/minio/issues/14331
  • +
  • d620c6d (registry) - registry: https://github.com/minio/minio/issues/13799
  • +
  • 85e6b73 (registry) - registry: use env replace creds volume
  • +
  • 6a1155d (registry) - registry: fine management affinity
  • +
  • 7b8ebae (registry) - registry: change minio to storage
  • +
  • 1338951 (registry) - registry: add check storage health
  • +
  • 2fa769d (registry) - registry: change probe
  • +
  • f187cbf (registry) - registry: add replicas
  • +
  • 09d8a7b (registry) - registry: upgrade to mc 2022.08.28.20.08.11
  • +
  • 4b187b8 (registry-proxy) - registry-proxy: use exec runner replace docker runner
  • +
  • 29ffbbe (registry-proxy) - registry-proxy: canonical charts naming
  • +
  • 6d783ba (registry-proxy) - registry-proxy: remove use_cni
  • +
  • 8cf05cf (registry-proxy) - dockerfile: use drycc/base image
  • +
  • 090e286 (registry-proxy) - registry-proxy: chore(imagebuilder): change uid gid to 1001
  • +
  • 7cf6120 (registry-proxy) - registry-proxy: use DRYCC_UID DRYCC_GID env
  • +
  • 3a00697 (registry-proxy) - registry-proxy: use registry.drycc.cc replace docker.io
  • +
  • 30e69e8 (registry-proxy) - registry-proxy: add registry basic auth proxy
  • +
  • 942abce (registry-proxy) - registry-proxy: upgrade to nginx 1.23.1
  • +
  • 5ea3297 (storage) - minio: use exec runner replace docker runner
  • +
  • 8306add (storage) - minio: canonical charts naming
  • +
  • c917e9f (storage) - minio: provide any additional service annotations
  • +
  • 042c732 (storage) - dockerfile: use drycc/base image
  • +
  • 7b47b82 (storage) - minio: change workdir to /workspace
  • +
  • 6f3531e (storage) - minio: use DRYCC_UID DRYCC_GID env
  • +
  • 9795fb1 (storage) - minio: use common affinity template
  • +
  • a7b09c5 (storage) - minio: change nodes to pod affinity
  • +
  • 7607342 (storage) - database: bump mc 2022.04.01.23.44.48 and minio 2022.04.01.03.41.39
  • +
  • ea2b2f1 (storage) - minio: use registry.drycc.cc replace docker.io
  • +
  • 445b501 (storage) - minio: https://github.com/minio/minio/issues/14331
  • +
  • f19fbc7 (storage) - minio: use env replace creds volume
  • +
  • 8982e2e (storage) - minio: use minio to distributed
  • +
  • 06bec73 (storage) - minio: fine management affinity
  • +
  • 9b8f006 (storage) - storage: remove assert
  • +
  • 59d64b9 (storage) - storage: change listen to POD_IP
  • +
  • 60044ee (storage) - storage: add juicefs mount options
  • +
  • 189f944 (storage) - storage: remove volumeName
  • +
  • 302fe89 (storage) - storage: mv to minio dir
  • +
  • 6ec586d (storage) - storage: change readinessProbee andlivenessProbe
  • +
  • 0e028df (storage) - storage: add minio pdb
  • +
  • cf9bd2d (storage) - storage: add check storage health svc
  • +
  • 2dd5c9f (storage) - storage: add volumeBindingMode
  • +
  • fa2effc (storage) - storage: remove databaseBucket
  • +
  • d166cc7 (storage) - charts: format network-policy name
  • +
  • d06bcce (storage) - storage: upgrade to golang 1.19
  • +
  • c2ca05c (storage) - storage: upgrade new require
  • +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contributing/community/index.html b/contributing/community/index.html new file mode 100644 index 000000000..8c4678acd --- /dev/null +++ b/contributing/community/index.html @@ -0,0 +1,863 @@ + + + + + + + + + + + + + + + + + + Community - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Community

+

Drycc software is fully open source. As such, the "Drycc community" consists of anyone who uses the Drycc software and participates in its evolution, whether by answering questions, finding bugs, suggesting enhancements, or writing documentation or code.

+

Drycc development is coordinated through numerous project repositories on GitHub. Anyone can check out the source code for any Drycc component, fork it, make improvements, and create a pull request to offer those changes back to the Drycc community.

+

Engine Yard maintains the numerous Drycc projects, and as such, decides what ends up in the official GitHub repositories. Drycc depends on the contributions of the community; the maintainers will not ignore pull requests or issues.

+

Drycc uses the timeless, highly efficient, and totally unfair system known as "Benevolent Dictator for Life" (BDFL). Gabriel Monroy, the creator of Drycc, is our BDFL and has final say over all decisions related to Drycc.

+

Open Source Bounties

+

Drycc projects are bounty-friendly. We believe open source bounty sites can be constructive tools in the development of open source software. Community members are encouraged to a) offer bounties and b) receive bounties for open source contributions that benefit everyone. The Drycc maintainers, however, will not accept bounties on this project but are more than happy to help community members attempting bounties.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contributing/conduct/index.html b/contributing/conduct/index.html new file mode 100644 index 000000000..cb8551b74 --- /dev/null +++ b/contributing/conduct/index.html @@ -0,0 +1,879 @@ + + + + + + + + + + + + + + + + + + Conduct - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Conduct

+

The Drycc community welcomes and encourages participation by everyone.

+

No matter how you identify yourself or how others perceive you: we welcome you. We welcome contributions from everyone as long as they interact constructively with our community.

+

The Drycc developer community continues to grow, and it is inevitable that disagreements and conflict will arise. We ask that participants conduct themselves according to these principles:

+
    +
  1. +

    Be welcoming, friendly, and patient.

    +
  2. +
  3. +

    Be considerate.

    +
  4. +
+

Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language.

+
    +
  1. Be respectful.
  2. +
+

Not all of us will agree all the time, but disagreement is no excuse for poor behavior and bad manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one.

+
    +
  1. Be careful in the words that you choose.
  2. +
+

Be kind to others. Do not insult or put down other participants. Behave professionally. Remember that harassment and sexist, racist, or exclusionary jokes are never appropriate for the community.

+

(Thanks to the Debian and Django communities for their text and +their inspiration.)

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contributing/design-documents/index.html b/contributing/design-documents/index.html new file mode 100644 index 000000000..aa22f9df4 --- /dev/null +++ b/contributing/design-documents/index.html @@ -0,0 +1,881 @@ + + + + + + + + + + + + + + + + + + Design Documents - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Design Documents

+

Before submitting a pull request which will significantly alter the behavior of any Drycc component, such as a new feature or major refactoring, contributors should first open an issue representing a design document.

+

Goals

+

Design documents help ensure project contributors:

+
    +
  • Involve stakeholders as early as possible in a feature's development
  • +
  • Ensure code changes accomplish the original motivations and design goals
  • +
  • Establish clear acceptance criteria for a feature or change
  • +
  • Enforce test-driven design methodology and automated test coverage
  • +
+

Contents

+

Design document issues should be named Design Doc: <change description> and contain the following sections:

+

Goal

+

This section should briefly describe the proposed change and the motivations behind it. Tests will be written to ensure this design goal is met by the change.

+

This section should also reference a separate GitHub issue tracking the feature or change, which will typically be assigned to a release milestone.

+

Code Changes

+

This section should detail the code changes necessary to accomplish the change, as well as the proposed implementation. This should be as detailed as necessary to help reviewers understand the change.

+

Tests

+

All changes should be covered by automated tests, either unit or integration tests (ideally both). This section should detail how tests will be written to validate that the change accomplishes the design goals and doesn't introduce any regressions.

+

If a change cannot be sufficiently covered by automated testing, the design should be reconsidered. If there is no test coverage whatsoever for an affected section of code, a separate issue should be filed to integrate automated testing with that section of the codebase.

+

The tests described here also form the acceptance criteria for the change, so that when it's completed maintainers can merge the pull request after confirming the tests pass CI.

+

Approval

+

A design document follows the same merge approval review process as final pull requests do, and maintainers will take extra care to ensure that any stakeholders for the change are included in the discussion and review of the design document.

+

Once the design is accepted, the author can complete the change and submit a pull request for review. The pull request should close both the design document for the change as well as any issues that either track the issue or are closed as a result of the change.

+

See Submitting a Pull Request for more information on pull request and commit message formatting.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contributing/development-environment/index.html b/contributing/development-environment/index.html new file mode 100644 index 000000000..fbcce8f9d --- /dev/null +++ b/contributing/development-environment/index.html @@ -0,0 +1,999 @@ + + + + + + + + + + + + + + + + + + Development Environment - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Development Environment

+

This document is for developers who are interested in working directly on the Drycc codebase. In this guide, we walk you through the process of setting up a development environment that is suitable for hacking on most Drycc components.

+

We try to make it simple to hack on Drycc components. However, there are necessarily several moving pieces and some setup required. We welcome any suggestions for automating or simplifying this process.

+
+

Note

+

The Drycc team is actively engaged in containerizing Go and Python based development environments tailored specifically for Drycc development in order to minimize the setup required. This work is ongoing. Refer to the drycc/router project for a working example of a fully containerized development environment.

+
+

If you're just getting into the Drycc codebase, look for GitHub issues with the label easy-fix. These are more straightforward or low-risk issues and are a great way to become more familiar with Drycc.

+

Prerequisites

+

In order to successfully compile and test Drycc binaries and build Container images of Drycc components, the following are required:

+
    +
  • git
  • +
  • Go 1.5 or later, with support for compiling to linux/amd64
  • +
  • glide
  • +
  • golint
  • +
  • shellcheck
  • +
  • Podman (in a non-Linux environment, you will additionally want [Podman Machine][machine])
  • +
+

For drycc/controller, in particular, you will also need:

+
    +
  • Python 2.7 or later (with pip)
  • +
  • virtualenv (sudo pip install virtualenv)
  • +
+

In most cases, you should simply install according to the instructions. There are a few special cases, though. We cover these below.

+

Configuring Go

+

If your local workstation does not support the linux/amd64 target environment, you will have to install Go from source with cross-compile support for that environment. This is because some of the components are built on your local machine and then injected into a container.

+

Homebrew users can just install with cross compiling support:

+
$ brew install go --with-cc-common
+ + +

It is also straightforward to build Go from source:

+
$ sudo su
+$ curl -sSL https://golang.org/dl/go1.5.src.tar.gz | tar -v -C /usr/local -xz
+$ cd /usr/local/go/src
+$ # compile Go for our default platform first, then add cross-compile support
+$ ./make.bash --no-clean
+$ GOOS=linux GOARCH=amd64 ./make.bash --no-clean
+ + +

Once you can compile to linux/amd64, you should be able to compile Drycc components as normal.

+

Fork the Repository

+

Once the prerequisites have been met, we can begin to work with Drycc components.

+

Begin at Github by forking whichever Drycc project you would like to contribute to, then clone that fork locally. Since Drycc is predominantly written in Go, the best place to put it is under $GOPATH/src/github.com/drycc/.

+
$ mkdir -p  $GOPATH/src/github.com/drycc
+$ cd $GOPATH/src/github.com/drycc
+$ git clone git@github.com:<username>/<component>.git
+$ cd <component>
+ + +
+

Note

+

By checking out the forked copy into the namespace github.com/drycc/<component>, we are tricking the Go toolchain into seeing our fork as the "official" source tree.

+
+

If you are going to be issuing pull requests to the upstream repository from which you forked, we suggest configuring Git such that you can easily rebase your code to the upstream repository's main branch. There are various strategies for doing this, but the most common is to add an upstream remote:

+
$ git remote add upstream https://github.com/drycc/<component>.git
+ + +

For the sake of simplicity, you may want to point an environment variable to your Drycc code - the directory containing one or more Drycc components:

+
$ export DRYCC=$GOPATH/src/github.com/drycc
+ + +

Throughout the rest of this document, $DRYCC refers to that location.

+

Alternative: Forking with a Pushurl

+

A number of Drycc contributors prefer to pull directly from drycc/<component>, but push to <username>/<component>. If that workflow suits you better, you can set it up this way:

+
$ git clone git@github.com:drycc/<component>.git
+$ cd drycc
+$ git config remote.origin.pushurl git@github.com:<username>/<component>.git
+ + +

In this setup, fetching and pulling code will work directly with the upstream repository, while pushing code will send changes to your fork. This makes it easy to stay up to date, but also make changes and then issue pull requests.

+

Make Your Changes

+

With your development environment set up and the code you wish to work on forked and cloned, you can begin making your changes.

+

Test Your Changes

+

Drycc components each include a comprehensive suite of automated tests, mostly written in Go. See testing for instructions on running the tests.

+

Deploying Your Changes

+

Although writing and executing tests are critical to ensuring code quality, most contributors will also want to deploy their changes to a live environment, whether to make use of those changes or to test them further. The remainder of this section documents the procedure for running officially released Drycc components in a development cluster and replacing any one of those with your customizations.

+

Running a Kubernetes Cluster for Development

+

To run a Kubernetes cluster locally or elsewhere to support your development activities, refer to Drycc installation instructions here.

+

Using a Development Registry

+

To facilitate deploying Container images containing your changes to your Kubernetes cluster, you will need to make use of a Container registry. This is a location to where you can push your custom-built images and from where your Kubernetes cluster can retrieve those same images.

+

If your development cluster runs locally (in Minikube, for instance), the most efficient and economical means of achieving this is to run a Container registry locally as a Container container.

+

To facilitate this, most Drycc components provide a make target to create such a registry:

+
$ make dev-registry
+ + +

In a Linux environment, to begin using the registry:

+
export DRYCC_REGISTRY=<IP of the host machine>:5000
+ + +

In non-Linux environments:

+
export DRYCC_REGISTRY=<IP of the drycc Container Machine VM>:5000
+ + +

If your development cluster runs on a cloud provider such as Google Container Engine, a local registry such as the one above will not be accessible to your Kubernetes nodes. In such cases, a public registry such as [DockerHub][dh] or quay.io will suffice.

+

To use DockerHub for this purpose, for instance:

+
$ export DRYCC_REGISTRY="registry.drycc.cc"
+$ export IMAGE_PREFIX=<your DockerHub username>
+ + +

To use quay.io:

+
$ export DRYCC_REGISTRY=quay.io
+$ export IMAGE_PREFIX=<your quay.io username>
+ + +

Note the importance of the trailing slash.

+

Dev / Deployment Workflow

+

With a functioning Kubernetes cluster and the officially released Drycc components installed onto it, deployment and further testing of any Drycc component you have made changes to is facilitated by replacing the officially released component with a custom built image that contains your changes. Most Drycc components include Makefiles with targets specifically intended to facilitate this workflow with minimal friction.

+

In the general case, this workflow looks like this:

+
    +
  1. Update source code and commit your changes using git
  2. +
  3. Use make build to build a new Container image
  4. +
  5. Use make dev-release to generate Kubernetes manifest(s)
  6. +
  7. Use make deploy to restart the component using the updated manifest
  8. +
+

This can be shortened to a one-liner using just the deploy target:

+
$ make deploy
+ + +

Useful Commands

+

Once your customized Drycc component has been deployed, here are some helpful commands that will allow you to inspect your cluster and to troubleshoot, if necessary:

+

See All Drycc Pods

+
$ kubectl --namespace=drycc get pods
+ + +

Describe a Pod

+

This is often useful for troubleshooting pods that are in pending or crashed states:

+
$ kubectl --namespace=drycc describe -f <pod name>
+ + +

Tail Logs

+
$ kubectl --namespace=drycc logs -f <pod name>
+ + +

Django Shell

+

Specific to drycc/controller

+
$ kubectl --namespace=drycc exec -it <pod name> -- python manage.py shell
+ + +

Have commands other Drycc contributors might find useful? Send us a PR!

+

Pull Requests

+

Satisfied with your changes? Share them!

+

Please read Submitting a Pull Request. It contains a checklist of +things you should do when proposing a change to any Drycc component.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contributing/maintainers/index.html b/contributing/maintainers/index.html new file mode 100644 index 000000000..a736f882d --- /dev/null +++ b/contributing/maintainers/index.html @@ -0,0 +1,922 @@ + + + + + + + + + + + + + + + + + + Maintainers - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Drycc Maintainers

+

This document serves to describe the leadership structure of the Drycc project, and list the current +project maintainers.

+

What is a maintainer?

+

(Unabashedly stolen from the Podman project)

+

There are different types of maintainers, with different responsibilities, but +all maintainers have 3 things in common:

+
    +
  1. They share responsibility in the project's success.
  2. +
  3. They have made a long-term, recurring time investment to improve the project.
  4. +
  5. They spend that time doing whatever needs to be done, not necessarily what +is the most interesting or fun.
  6. +
+

Maintainers are often under-appreciated, because their work is harder to appreciate. +It's easy to appreciate a really cool and technically advanced feature. It's harder +to appreciate the absence of bugs, the slow but steady improvement in stability, +or the reliability of a release process. But those things distinguish a good +project from a great one.

+

Drycc maintainers

+

Drycc has two groups of maintainers in addition to our beloved Benevolent Dictator for Life.

+

BDFL

+

Drycc follows the timeless, highly efficient and totally unfair system known as Benevolent dictator +for life.

+

Gabriel Monroy (@gabrtv), as creator of the Drycc project, serves as our +project's BDFL. While the day-to-day project management is carried out by the maintainers, Gabriel +serves as the final arbiter of any disputes and has the final say on project direction.

+

Core maintainers

+

Core maintainers are exceptionally knowledgeable about all areas of Drycc. Some maintainers work on Drycc +full-time, although this is not a requirement.

+

The duties of a core maintainer include:

+
    +
  • Classify and respond to GitHub issues and review pull requests
  • +
  • Help to shape the Drycc roadmap and lead efforts to accomplish roadmap milestones
  • +
  • Participate actively in feature development and bug fixing
  • +
  • Answer questions and help users in the Drycc #community Slack channel
  • +
+

The current list of core maintainers can be seen here.

+

No pull requests can be merged until at least one core maintainer signs off with an +LGTM. The other LGTM can +come from either a core maintainer or contributing maintainer.

+

Contributing maintainers

+

Contributing maintainers are exceptionally knowledgeable about some but not necessarily all areas +of Drycc, and are often selected due to specific domain knowledge that complements the project (but +a willingness to continually contribute to the project is most important!). Often, +core maintainers will ask a contributing maintainer to weigh in on issues, pull requests, or +conversations where the contributing maintainer is knowledgeable.

+

The duties of a contributing maintainer are very similar to those of a core maintainer, but they are limited to areas of the Drycc project where the contributing maintainer is knowledgeable.

+

Contributing maintainers are defined in practice as those who have write access to the Drycc repository. All maintainers can review pull requests and add LGTM labels as appropriate.

+

Becoming a maintainer

+

The Drycc project wouldn't be where it is today without its community. Many of the project's +community members embody the spirit of maintainership, and have contributed substantially to +the project.

+

The contributing maintainers group was created in part so that exceptional members of the community +who have an interest in the continued success of the project have the opportunity to join the +core maintainers in guiding the future of Drycc.

+

Generally, potential contributing maintainers are selected by the Drycc core maintainers based in +part on the following criteria:

+
    +
  • Sustained contributions to the project over a period of time (usually months)
  • +
  • A willingness to help Drycc users on GitHub and in the Drycc #community Slack channel
  • +
  • A friendly attitude :)
  • +
+

The Drycc core maintainers must unanimously agree before inviting a community member to join as a +contributing maintainer, although in many cases the candidate has already been acting in the +capacity of a contributing maintainer for some time, and has been consulted on issues, pull requests, +etc.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contributing/overview/index.html b/contributing/overview/index.html new file mode 100644 index 000000000..be2f0d3f2 --- /dev/null +++ b/contributing/overview/index.html @@ -0,0 +1,874 @@ + + + + + + + + + + + + + + + + + + Overview - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Contributor Overview

+

Interested in contributing to a Drycc project? There are lots of ways to help.

+

File Bugs & Enhancements

+

Find a bug? Want to see a new feature? Have a request for the maintainers? Open a Github issue in the applicable repository and we’ll get the conversation started.

+

Our official support channel is the Drycc #community Slack channel.

+

Don't know what the applicable repository for an issue is? Open up in issue in workflow or chat with a maintainer in the Drycc #community Slack channel and we'll make sure it gets to the right place.

+

Additionally, take a look at the troubleshooting documentation for common issues.

+

Before opening a new issue, it's helpful to search and see if anyone else has already reported the problem. You can search through a list of issues for all Drycc projects here.

+

Write Documentation

+

We are always looking to improve and expand our documentation. Most docs reside in the drycc/workflow repository. Simply fork the project, update docs and send us a pull request.

+

Contribute Code

+

We are always looking for help improving the core platform, other workloads, tooling, and test coverage. Interested in contributing code? Let’s chat in the Drycc #community Slack channel. Make sure to check out issues tagged easy fix or help wanted.

+

When you're ready to begin writing code, review Design Documents and get your Development Environment set up.

+

By contributing to any Drycc project you agree to its Developer Certificate of Origin (DCO). This document was created by the Linux Kernel community and is a simple statement that you, as a contributor, have the legal right to make the contribution.

+

Triage Issues

+

If you don't have time to code, consider helping with triage. The community will thank you for saving them time by spending some of yours. See Triaging Issues for more info.

+

Share your Experience

+

Interact with the community on our user mailing list or live in our Drycc #community Slack channel, where you can chat with other Drycc Workflow users any time of day.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contributing/submitting-a-pull-request/index.html b/contributing/submitting-a-pull-request/index.html new file mode 100644 index 000000000..20e8abf70 --- /dev/null +++ b/contributing/submitting-a-pull-request/index.html @@ -0,0 +1,931 @@ + + + + + + + + + + + + + + + + + + Submitting a Pull Request - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Submitting a Pull Request

+

Proposed changes to Drycc projects are made as GitHub pull requests.

+

Design Document

+

Before opening a pull request, ensure your change also references a design document if the contribution is substantial. For more information, see Design Documents.

+

Single Issue

+

It's hard to reach agreement on the merit of a PR when it isn't focused. When fixing an issue or implementing a new feature, resist the temptation to refactor nearby code or to fix that potential bug you noticed. Instead, open a separate issue or pull request. Keeping concerns separated allows pull requests to be tested, reviewed, and merged more quickly.

+

Squash and rebase the commit or commits in your pull request into logical units of work with git. Include tests and documentation changes in the same commit, so that a revert would remove all traces of the feature or fix.

+

Most pull requests will reference a GitHub issue. In the PR description - not in the commit itself - include a line such as "closes #1234". The issue referenced will automatically be closed when your PR is merged.

+

Include Tests

+

If you significantly alter or add functionality to a component that impacts the broader Drycc Workflow PaaS, you should submit a complementary PR to modify or amend end-to-end integration tests. These integration tests can be found in the drycc/workflow-e2e repository.

+

See testing for more information.

+

Include Docs

+

Changes to any Drycc Workflow component that could affect a user's experience also require a change or addition to the relevant documentation. For most Drycc components, this involves updating the component's own documentation. In some cases where a component is tightly integrated into drycc/workflow, its documentation must also be updated.

+

Cross-repo commits

+

If a pull request is part of a larger piece of work involving one or more additional commits in other Workflow repositories, these commits can be referenced in the last PR to be submitted. The downstream e2e test job will then supply every referenced commit (derived from PR issue number supplied) to the test runner so it can source the necessary Container images for inclusion in the generated Workflow chart to be tested.

+

For example, consider paired commits in drycc/controller and drycc/workflow-e2e. The commit body for the first PR in drycc/workflow-e2e would look like:

+
feat(foo_test): add e2e test for feature foo
+
+[skip e2e] test for controller#42
+ + +

Adding [skip e2e] forgoes the e2e tests on this commit. This and any other required PRs aside from the final PR should be submitted first, so that their respective build and image push jobs run.

+

Lastly, the final PR in drycc/controller should be created with the required PR number(s) listed, in the form of [Rr]equires <repoName>#<pullRequestNumber>, for use by the downstream e2e run.

+
feat(foo): add feature foo
+
+Requires workflow-e2e#42
+ + +

Code Standards

+

Drycc components are implemented in Go and Python. For both languages, we agree with The Zen of Python, which emphasizes simple over clever. Readability counts.

+

Go code should always be run through gofmt on the default settings. Lines of code may be up to 99 characters long. Documentation strings and tests are required for all exported functions. Use of third-party go packages should be minimal, but when doing so, such dependencies should be managed via the glide tool.

+

Python code should always adhere to PEP8, the python code style guide, with the exception that lines of code may be up to 99 characters long. Docstrings and tests are required for all public methods, although the flake8 tool used by Drycc does not enforce this.

+

Commit Style

+

We follow a convention for commit messages borrowed from CoreOS, who borrowed theirs +from AngularJS. This is an example of a commit:

+
feat(scripts/test-cluster): add a cluster test command
+
+this uses tmux to setup a test cluster that you can easily kill and
+start for debugging.
+ + +

To make it more formal, it looks something like this:

+
{type}({scope}): {subject}
+<BLANK LINE>
+{body}
+<BLANK LINE>
+{footer}
+ + +

The allowed {types} are as follows:

+
    +
  • feat -> feature
  • +
  • fix -> bug fix
  • +
  • docs -> documentation
  • +
  • style -> formatting
  • +
  • ref -> refactoring code
  • +
  • test -> adding missing tests
  • +
  • chore -> maintenance
  • +
+

The {scope} can be anything specifying the location(s) of the commit change(s).

+

The {subject} needs to be an imperative, present tense verb: “change”, not “changed” nor +“changes”. The first letter should not be capitalized, and there is no dot (.) at the end.

+

Just like the {subject}, the message {body} needs to be in the present tense, and includes +the motivation for the change, as well as a contrast with the previous behavior. The first +letter in a paragraph must be capitalized.

+

All breaking changes need to be mentioned in the {footer} with the description of the +change, the justification behind the change and any migration notes required.

+

Any line of the commit message cannot be longer than 72 characters, with the subject line +limited to 50 characters. This allows the message to be easier to read on GitHub as well +as in various git tools.

+

Merge Approval

+

Any code change - other than a simple typo fix or one-line documentation change - requires at least two Drycc maintainers to accept it. Maintainers tag pull requests with "LGTM1" and "LGTM2" (Looks Good To Me) labels to indicate acceptance.

+

No pull requests can be merged until at least one core maintainer signs off with an LGTM. The other LGTM can come from either a core maintainer or contributing maintainer.

+

If the PR is from a Drycc maintainer, then he or she should be the one to close it. This keeps the commit stream clean and gives the maintainer the benefit of revisiting the PR before deciding whether or not to merge the changes.

+

An exception to this is when an errant commit needs to be reverted urgently. If necessary, a PR that only reverts a previous commit can be merged without waiting for LGTM approval.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contributing/testing/index.html b/contributing/testing/index.html new file mode 100644 index 000000000..23342b16b --- /dev/null +++ b/contributing/testing/index.html @@ -0,0 +1,882 @@ + + + + + + + + + + + + + + + + + + Testing - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Testing Drycc

+

Each Drycc component is one among an ecosystem of such components - many of which integrate with one another - which makes testing each component thoroughly a matter of paramount importance.

+

Each Drycc component includes its own suite of style checks, unit tests, and black-box type functional tests.

+

Integration tests verify the behavior of the Drycc components together as a system and are provided separately by the drycc/workflow-e2e project.

+

GitHub pull requests for all Drycc components are tested automatically by the Travis CI continuous integration system. Contributors should run the same tests locally before proposing any changes to the Drycc codebase.

+

Set Up the Environment

+

Successfully executing the unit and functional tests for any Drycc component requires that the Development Environment is set up first.

+

Run the Tests

+

The style checks, unit tests, and functional tests for each component can all be executed via make targets:

+

To execute style checks:

+
$ make test-style
+ + +

To execute unit tests:

+
$ make test-unit
+ + +

To execute functional tests:

+
$ make test-functional
+ + +

To execute style checks, unit tests, and functional tests all in one shot:

+
$ make test
+ + +

To execute integration tests, refer to drycc/workflow-e2e documentation.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contributing/triaging-issues/index.html b/contributing/triaging-issues/index.html new file mode 100644 index 000000000..13dba8317 --- /dev/null +++ b/contributing/triaging-issues/index.html @@ -0,0 +1,946 @@ + + + + + + + + + + + + + + + + + + Triaging Issues - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Triaging Issues

+

Issue triage provides an important way to contribute to an open source project. Triage helps ensure issues resolve quickly by:

+
    +
  • Describing the issue's intent and purpose is conveyed precisely. This is necessary because it can be difficult for an issue to explain how an end user experiences an problem and what actions they took.
  • +
  • Giving a contributor the information they need before they commit to resolving an issue.
  • +
  • Lowering the issue count by preventing duplicate issues.
  • +
  • Streamlining the development process by preventing duplicate discussions.
  • +
+

If you don't have time to code, consider helping with triage. The community will thank you for saving them time by spending some of yours.

+

Ensure the Issue Contains Basic Information

+

Before triaging an issue very far, make sure that the issue's author provided the standard issue information. This will help you make an educated recommendation on how this to categorize the issue. Standard information that should be included in most issues are things such as:

+
    +
  • the version(s) of Drycc this issue affects
  • +
  • a reproducible case if this is a bug
  • +
  • page URL if this is a docs issue or the name of a man page
  • +
+

Depending on the issue, you might not feel all this information is needed. Use your best judgment. If you cannot triage an issue using what its author provided, explain kindly to the author that they must provide the above information to clarify the problem.

+

If the author provides the recommended information but you are still unable to triage the issue, request additional information. Do this kindly and politely because you are asking for more of the author's time.

+

If the author does not respond requested information within the timespan of a week, close the issue with a kind note stating that the author can request for the issue to be reopened when the necessary information is provided.

+

Classifying the Issue

+

An issue can have multiple of the following labels:

+

Issue Kind

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KindDescription
bugBugs are bugs. The cause may or may not be known at triage time so debugging should be taken account into the time estimate.
docsWriting documentation, man pages, articles, blogs, or other significant word-driven task.
enhancementEnhancements can drastically improve usability or performance of a component.
questionContains a user or contributor question requiring a response.
securitySecurity-related issues such as TLS encryption, network segregation, authn/authz features, etc.
+

Functional Area

+
    +
  • builder
  • +
  • cache
  • +
  • contrib and provisioning
  • +
  • client
  • +
  • controller
  • +
  • database
  • +
  • docs
  • +
  • kubernetes
  • +
  • registry
  • +
  • router
  • +
  • store (Ceph)
  • +
  • tests
  • +
+

Easy Fix

+

"Easy Fix" issues are a way for a new contributor to find issues that are fit for their experience level. These issues are typically for users who are new to Drycc, and possibly Go, and is looking to help while learning the basics.

+

Prioritizing issues

+

When attached to a specific milestone, an issue can be attributed one of the following labels to indicate their degree of priority.

+ + + + + + + + + + + + + + + + + +
PriorityDescription
priority 0Urgent: Security, critical bugs, blocking issues. Drop everything and fix this today, then consider creating a patch release.
priority 1Serious: Impedes user actions or is a regression. Fix this before the next planned release.
+

And that's it. That should be all the information required for a new or existing contributor to come in an resolve an issue.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dependency_update.py b/dependency_update.py new file mode 100644 index 000000000..af634b286 --- /dev/null +++ b/dependency_update.py @@ -0,0 +1,27 @@ +import sys +import yaml +import requests +from contextlib import closing + + +def load_index(url): + with closing(requests.get(url)) as response: + return yaml.load(response.text, Loader=yaml.Loader) + +def load_requirements(requirements_file): + with open(requirements_file) as f: + return yaml.load(f, Loader=yaml.Loader) + +def dump_requirements(requirements_file, requirements): + with open(requirements_file, "w") as f: + return yaml.dump(requirements, stream=f, Dumper=yaml.Dumper) + +def update_dependencies(requirements, url): + for dependency in requirements["dependencies"]: + dependency["repository"] = url + +if __name__ == "__main__": + requirements = load_requirements(sys.argv[2]) + update_dependencies(requirements, sys.argv[1]) + dump_requirements(sys.argv[2], requirements) + diff --git a/diagrams/Application_Layout.png b/diagrams/Application_Layout.png new file mode 100644 index 000000000..46ef57fa4 Binary files /dev/null and b/diagrams/Application_Layout.png differ diff --git a/diagrams/Diagrams.graffle b/diagrams/Diagrams.graffle new file mode 100644 index 000000000..ccea9786a Binary files /dev/null and b/diagrams/Diagrams.graffle differ diff --git a/diagrams/Document_Overview.png b/diagrams/Document_Overview.png new file mode 100644 index 000000000..0fbc8ef07 Binary files /dev/null and b/diagrams/Document_Overview.png differ diff --git a/diagrams/Ecosystem_Basic.png b/diagrams/Ecosystem_Basic.png new file mode 100644 index 000000000..fe525f5f0 Binary files /dev/null and b/diagrams/Ecosystem_Basic.png differ diff --git a/diagrams/Ecosystem_Complex.png b/diagrams/Ecosystem_Complex.png new file mode 100644 index 000000000..5ee46dd88 Binary files /dev/null and b/diagrams/Ecosystem_Complex.png differ diff --git a/diagrams/Git_Push_Flow.png b/diagrams/Git_Push_Flow.png new file mode 100644 index 000000000..096bcfe68 Binary files /dev/null and b/diagrams/Git_Push_Flow.png differ diff --git a/diagrams/Workflow_Detail.png b/diagrams/Workflow_Detail.png new file mode 100644 index 000000000..fe4980009 Binary files /dev/null and b/diagrams/Workflow_Detail.png differ diff --git a/diagrams/Workflow_Overview.png b/diagrams/Workflow_Overview.png new file mode 100644 index 000000000..eee9c1b4e Binary files /dev/null and b/diagrams/Workflow_Overview.png differ diff --git a/diagrams/index.html b/diagrams/index.html new file mode 100644 index 000000000..32cb719e8 --- /dev/null +++ b/diagrams/index.html @@ -0,0 +1,871 @@ + + + + + + + + + + + + + + + + + + Architecture Diagrams - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Architecture Diagrams

+

This is an OmniGraffle file which holds the source materials for the following +images.

+

To update a chart:

+
    +
  1. Make your modification!
  2. +
  3. Select "File > Export"
  4. +
  5. Select "Entire Document
  6. +
  7. Choose: Scale: 100%
  8. +
  9. Set Bitmap Resolution to 72 dpi (for web)
  10. +
  11. Uncheck "Transparent Background"
  12. +
  13. Select "images" directory
  14. +
  15. Click "Export"
  16. +
+

This should update all of the graphics in one go! Commit and pull-request.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 000000000..04f26d64e Binary files /dev/null and b/favicon.ico differ diff --git a/generate_cache.sh b/generate_cache.sh new file mode 100755 index 000000000..a0bd1d0c1 --- /dev/null +++ b/generate_cache.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -eo pipefail +shopt -s expand_aliases + +tmp=$(mktemp -d) + +function clean_before_exit { + # delay before exiting, so stdout/stderr flushes through the logging system + rm -rf $tmp + sleep 3 +} +trap clean_before_exit EXIT +cd $tmp + +helm repo add cilium https://helm.cilium.io/ +helm repo add metallb https://metallb.github.io/metallb +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm fetch cilium/cilium +helm fetch metallb/metallb +helm fetch jetstack/cert-manager + +# remove v from cert-manager version +filename=$(find cert-manager-v* 2>/dev/null || echo "") +if [[ ! -z $filename ]]; then + tar -xvzf $filename + rm -rf $filename + version=${filename#cert-manager-v} + version=${version%.tgz} + helm package -u cert-manager --version $version + rm -rf cert-manager +fi + +for tar in `ls $tmp | grep .tgz` +do + helm push $tar oci://$DRYCC_REGISTRY/$([ -z $CI_COMMIT_TAG ] && echo charts-testing || echo charts) +done diff --git a/gutenbuild b/gutenbuild new file mode 100755 index 000000000..d1ce9ad0c --- /dev/null +++ b/gutenbuild @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e +set -x + +build_dest=$1 + +# ensure we are on the master branch before building +git checkout master + +PATH=$HOME/.local/bin:$PATH BUILDDIR=${build_dest} make deps build + +# build again, this time to /en/dev +dev_build_dest=$1/en/dev +PATH=$HOME/.local/bin:$PATH BUILDDIR=${dev_build_dest} make deps build + +# also build each version of the docs out to /en/ +# NOTE(bacongobbler): do not build any pre-release tags +for tag in $(git tag | grep -v -- "-alpha\|-beta\|-rc"); do + tag_build_dest="$build_dest/en/$tag" + git checkout $tag + PATH=$HOME/.local/bin:$PATH BUILDDIR=${tag_build_dest} make deps build +done diff --git a/index.html b/index.html new file mode 100644 index 000000000..9604a001a --- /dev/null +++ b/index.html @@ -0,0 +1,872 @@ + + + + + + + + + + + + + + + + + + Home - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Welcome to Drycc

+

Drycc Workflow is an open source container cloud platform.

+

Usually we also call it Container as a Service(CaaS) that adds a developer-friendly layer +to any Kubernetes cluster, making it easy to deploy and manage applications.

+

Drycc Workflow includes capabilities for building and deploying from source via git push, simple +application configuration, creating and rolling back releases, managing domain names and SSL +certificates, providing seamless edge routing, aggregating logs, and sharing applications with +teams. All of this is exposed through a simple REST API and command line interface.

+

Getting Started

+

To get started with Workflow, follow our Quick Start guide.

+

Take a deep dive into Drycc Workflow in our Concepts, Architecture, and +Components sections.

+

Feel like contibuting some code or want to get started as a maintainer? Pick an issue tagged as an +easy fix or help wanted and start contributing!

+

Service and Support

+

Coming soon.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/install-cli.sh b/install-cli.sh new file mode 100755 index 000000000..760cdf61c --- /dev/null +++ b/install-cli.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +set -eo pipefail +shopt -s expand_aliases + +check_platform_arch() { + local supported="darwin-amd64 darwin-arm64 linux-amd64 linux-386 linux-arm linux-arm64 windows-386 windows-amd64" + + if ! echo "${supported}" | tr ' ' '\n' | grep -q "${PLATFORM}-${ARCH}"; then + cat < + + old_lang=$LANG + LANG=C + + old_lc_collate=$LC_COLLATE + LC_COLLATE=C + + local length="${#1}" + for (( i = 0; i < length; i++ )); do + local c="${1:i:1}" + case $c in + [a-zA-Z0-9.~_-]) printf "$c" ;; + *) printf '%%%02X' "'$c" ;; + esac + done + + LANG=$old_lang + LC_COLLATE=$old_lc_collate +} + +function install_helm { + if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then + version=$(curl -Ls https://drycc-mirrors.drycc.cc/helm/helm/releases|grep /helm/helm/releases/tag/ | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1) + tar_name="helm-${version}-linux-${ARCH}.tar.gz" + helm_download_url="https://drycc-mirrors.drycc.cc/helm/${tar_name}" + else + version=$(curl -Ls https://github.com/helm/helm/releases|grep /helm/helm/releases/tag/ | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1) + tar_name="helm-${version}-linux-${ARCH}.tar.gz" + helm_download_url="https://get.helm.sh/${tar_name}" + fi + curl -fsSL -o "${tar_name}" "${helm_download_url}" + tar -zxvf "${tar_name}" + mv "linux-${ARCH}/helm" /usr/local/bin/helm + rm -rf "${tar_name}" "linux-${ARCH}" +} + +function configure_os { + echo -e "\\033[32m---> Start configuring kernel parameters\\033[0m" + if [[ "$(command -v iptables)" != "" ]] ; then + iptables -F + iptables -X + iptables -F -t nat + iptables -X -t nat + iptables -P FORWARD ACCEPT + fi + swapoff -a + sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab + mount bpffs -t bpf /sys/fs/bpf + rmem_max=$(sysctl -ne net.core.rmem_max) + if [ ! -n "$rmem_max" ] || [ 2500000 -gt $rmem_max ] ;then + echo 'net.core.rmem_max = 2500000' >> /etc/sysctl.conf + fi + nr_hugepages=$(sysctl -ne vm.nr_hugepages) + if [ ! -n "$nr_hugepages" ] || [ 1024 -gt $nr_hugepages ] ;then + echo 'vm.nr_hugepages = 1024' >> /etc/sysctl.conf + fi + max_user_instances=$(sysctl -ne fs.inotify.max_user_instances) + if [ ! -n "$max_user_instances" ] || [ 65535 -gt $max_user_instances ] ;then + echo 'fs.inotify.max_user_instances = 65535' >> /etc/sysctl.conf + fi + sysctl -p + + cpufreq=$(ls /sys/devices/system/cpu/cpu*/cpufreq >/dev/null 2>&1 || echo "false") + if [[ $cpufreq != "false" ]]; then + for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do + echo performance > $cpu + done + fi + echo -e "\\033[32m---> Configuring kernel parameters finish\\033[0m" +} + +function configure_registries { + if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]]; then + if [[ "$1" == "runtime" ]] ; then + cat << EOF >> "/var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl" +[plugins.cri.registry.mirrors] +[plugins.cri.registry.mirrors."docker.io"] + endpoint = ["https://docker-mirror.drycc.cc", "https://registry-1.docker.io"] +EOF + else + cat << EOF >> "/var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl" +[plugins.cri.registry.mirrors] +[plugins.cri.registry.mirrors."docker.io"] + endpoint = ["https://docker-mirror.drycc.cc", "https://registry-1.docker.io"] +[plugins.cri.registry.mirrors."quay.io"] + endpoint = ["https://quay-mirror.drycc.cc", "https://quay.io"] +[plugins.cri.registry.mirrors."gcr.io"] + endpoint = ["https://quay-mirror.drycc.cc", "https://gcr.io"] +[plugins.cri.registry.mirrors."k8s.gcr.io"] + endpoint = ["https://k8s-mirror.drycc.cc", "https://registry.k8s.io"] +[plugins.cri.registry.mirrors."registry.k8s.io"] + endpoint = ["https://k8s-mirror.drycc.cc", "https://registry.k8s.io"] +EOF + fi + fi +} + +function download_runtime { + # download crun + if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then + crun_base_url="https://drycc-mirrors.drycc.cc/containers" + else + crun_base_url="https://github.com/containers" + fi + crun_version=$(curl -Ls ${crun_base_url}/crun/releases|grep /containers/crun/releases/tag/ | sed -E 's/.*\/containers\/crun\/releases\/tag\/([0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1) + crun_download_url=${crun_base_url}/crun/releases/download/${crun_version}/crun-${crun_version}-linux-${ARCH} + curl -sfL "${crun_download_url}" -o /usr/local/bin/crun + chmod a+rx /usr/local/bin/crun + + # download runsc + gvisor_download_url=https://storage.googleapis.com/gvisor/releases/release/latest/$(uname -m) + curl -sfL "${gvisor_download_url}/runsc" -o /usr/local/bin/runsc + curl -sfL "${gvisor_download_url}/containerd-shim-runsc-v1" -o /usr/local/bin/containerd-shim-runsc-v1 + chmod a+rx /usr/local/bin/runsc /usr/local/bin/containerd-shim-runsc-v1 +} + +function configure_runtime { + cat << EOF > "/var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl" +[plugins.cri.containerd] + snapshotter = "overlayfs" + default_runtime_name = "crun" + disable_snapshot_annotations = true + +[plugins.cri.containerd.runtimes.crun] + runtime_type = "io.containerd.runc.v2" + +[plugins.cri.containerd.runtimes.crun.options] + SystemdCgroup = true + +[plugins.cri.containerd.runtimes.runc] + runtime_type = "io.containerd.runc.v2" + +[plugins.cri.containerd.runtimes.runc.options] + SystemdCgroup = true + +[plugins.cri.containerd.runtimes.runsc] + runtime_type = "io.containerd.runsc.v1" + +[plugins.cri.containerd.runtimes.runsc.options] + SystemdCgroup = true +EOF +} + +function configure_containerd { + mkdir -p /var/lib/rancher/k3s/agent/etc/containerd + if [[ -f "${CONTAINERD_FILE}" ]]; then + cat "${CONTAINERD_FILE}" > /var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl + else + configure_runtime + configure_registries $1 + fi +} + +function configure_mirrors { + echo -e "\\033[32m---> Start configuring mirrors\\033[0m" + configure_containerd + if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then + INSTALL_K3S_MIRROR="${INSTALL_DRYCC_MIRROR}" + k3s_install_url="https://get-k3s.drycc.cc" + K3S_RELEASE_URL=https://drycc-mirrors.drycc.cc/k3s-io/k3s/releases + export INSTALL_K3S_MIRROR + else + k3s_install_url="https://get.k3s.io" + K3S_RELEASE_URL=github.com/k3s-io/k3s/releases + fi + if [ -z "${INSTALL_K3S_VERSION}" ]; then + INSTALL_K3S_VERSION=$(curl -Ls "$K3S_RELEASE_URL" | grep /k3s-io/k3s/releases/tag/ | sed -E 's/.*\/k3s-io\/k3s\/releases\/tag\/(v[0-9\.]{1,}[rc0-9\-]{0,}%2Bk3s[0-9])".*/\1/g' | head -1) + else + INSTALL_K3S_VERSION=$(urlencode "$INSTALL_K3S_VERSION") + fi + export INSTALL_K3S_VERSION + echo -e "\\033[32m---> Configuring mirrors finish\\033[0m" +} + +function install_k3s_server { + configure_os + download_runtime + configure_mirrors + INSTALL_K3S_EXEC="server ${INSTALL_K3S_EXEC} --flannel-backend=none --disable-network-policy --disable=traefik --disable=servicelb --disable-kube-proxy --cluster-cidr=${CLUSTER_CIDR} --cluster-domain=${CLUSTER_DOMAIN}" + if [[ -n "${K3S_DATA_DIR}" ]] ; then + INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC --data-dir=${K3S_DATA_DIR}/rancher/k3s" + fi + if [[ -z "${K3S_URL}" ]] ; then + INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC --cluster-init" + fi + curl -sfL "${k3s_install_url}" |INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC" sh -s - + kubectl apply -f - < The path ${METALLB_CONFIG_FILE} does not exist...\\033[0m" + exit 1 + fi +} + +function install_network() { + echo -e "\\033[32m---> Start installing network...\\033[0m" + api_server_address=(`ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p'`) + helm install cilium $CHARTS_URL/cilium \ + --set operator.replicas=1 \ + --set bpf.masquerade=true \ + --set bandwidthManager.enabled=true \ + --set bandwidthManager.bbr=true \ + --set kubeProxyReplacement=strict \ + --set hubble.enabled=false \ + --set hostPort.enabled=true \ + --set k8sServiceHost=${KUBE_API_SERVER_ADDRESS:-$api_server_address} \ + --set k8sServicePort=${KUBE_API_SERVER_PORT:-"6443"} \ + --namespace kube-system --wait + echo -e "\\033[32m---> Network installed!\\033[0m" +} + +function install_metallb() { + check_metallb + echo -e "\\033[32m---> Start installing metallb...\\033[0m" + helm install metallb $CHARTS_URL/metallb \ + --set speaker.frr.enabled=true \ + --namespace metallb \ + --create-namespace + + echo -e "\\033[32m---> Waiting metallb pods ready...\\033[0m" + kubectl wait pods -n metallb --all --for condition=Ready --timeout=600s + echo -e "\\033[32m---> Waiting metallb webhook ready...\\033[0m" + sleep 30s + + if [[ -z "${METALLB_CONFIG_FILE}" ]] ; then + echo -e "\\033[32m---> Metallb using the default configuration.\\033[0m" + kubectl apply -n metallb -f - < Metallb installed!\\033[0m" +} + +function install_gateway() { + echo -e "\\033[32m---> Start installing gateway...\\033[0m" + + if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then + gateway_api_url=https://drycc-mirrors.drycc.cc/kubernetes-sigs/gateway-api + else + gateway_api_url=https://github.com/kubernetes-sigs/gateway-api + fi + version=$(curl -Ls $gateway_api_url/releases|grep /kubernetes-sigs/gateway-api/releases/tag/ | sed -E 's/.*\/kubernetes-sigs\/gateway-api\/releases\/tag\/(v[0-9\.]{1,}(-rc[0-9]{1,})?)".*/\1/g' | head -1) + + helm repo add istio https://drycc-mirrors.drycc.cc/istio-charts + helm repo update + kubectl apply -f $gateway_api_url/releases/download/${version}/experimental-install.yaml + helm install istio-base istio/base -n istio-system --set defaultRevision=default --create-namespace --wait + helm install istio-istiod istio/istiod -n istio-system --wait + helm install istio-gateway istio/gateway -n istio-gateway --create-namespace --wait + echo -e "\\033[32m---> Gateway installed!\\033[0m" +} + +function install_cert_manager() { + echo -e "\\033[32m---> Start installing cert-manager...\\033[0m" + helm install cert-manager $CHARTS_URL/cert-manager \ + --namespace cert-manager \ + --create-namespace \ + --set clusterResourceNamespace=drycc \ + --set "extraArgs={--feature-gates=ExperimentalGatewayAPISupport=true}" \ + --set installCRDs=true --wait + echo -e "\\033[32m---> Cert-manager installed!\\033[0m" +} + +function install_catalog() { + echo -e "\\033[32m---> Start installing catalog...\\033[0m" + helm install catalog $CHARTS_URL/catalog \ + --set asyncBindingOperationsEnabled=true \ + --set image=registry.drycc.cc/drycc-addons/service-catalog:canary \ + --namespace catalog \ + --create-namespace --wait + echo -e "\\033[32m---> Catalog installed!\\033[0m" +} + +function install_components { + install_network + install_metallb + install_gateway + install_cert_manager + install_catalog +} + +function check_drycc { + if [[ -z "${PLATFORM_DOMAIN}" ]] ; then + echo -e "\\033[33m---> Please set the PLATFORM_DOMAIN variable.\\033[0m" + echo -e "\\033[33m---> For example:\\033[0m" + echo -e "\\033[33m---> export PLATFORM_DOMAIN=drycc.cc\\033[0m" + echo -e "\\033[33m---> And confirm that wildcard domain name resolution has been set.\\033[0m" + echo -e "\\033[33m---> For example, the current server IP is 8.8.8.8\\033[0m" + echo -e "\\033[33m---> Please point *.drycc.cc to 8.8.8.8\\033[0m" + exit 1 + fi + + if [[ -z "${DRYCC_ADMIN_USERNAME}" || -z "${DRYCC_ADMIN_PASSWORD}" ]] ; then + echo -e "\\033[33m---> Please set the DRYCC_ADMIN_USERNAME and DRYCC_ADMIN_PASSWORD variable.\\033[0m" + echo -e "\\033[33m---> For example:\\033[0m" + echo -e "\\033[33m---> export DRYCC_ADMIN_USERNAME=admin\\033[0m" + echo -e "\\033[33m---> export DRYCC_ADMIN_PASSWORD=admin\\033[0m" + echo -e "\\033[33m---> This password is used by end users to log in and manage drycc.\\033[0m" + echo -e "\\033[33m---> Please set a high security string!!!\\033[0m" + exit 1 + fi +} + +function install_drycc { + check_drycc + echo -e "\\033[32m---> Start installing workflow...\\033[0m" + RABBITMQ_USERNAME=$(cat /proc/sys/kernel/random/uuid) + RABBITMQ_PASSWORD=$(cat /proc/sys/kernel/random/uuid) + +cat << EOF > "/tmp/drycc-values.yaml" +global: + clusterDomain: ${CLUSTER_DOMAIN} + platformDomain: ${PLATFORM_DOMAIN} + certManagerEnabled: ${CERT_MANAGER_ENABLED} + gatewayClass: ${GATEWAY_CLASS} + +builder: + replicas: ${BUILDER_REPLICAS:-1} + imageRegistry: ${DRYCC_REGISTRY} + +database: + replicas: ${DATABASE_REPLICAS:-2} + imageRegistry: ${DRYCC_REGISTRY} + limitsMemory: "256Mi" + limitsHugepages2Mi: "256Mi" + persistence: + enabled: true + size: ${DATABASE_PERSISTENCE_SIZE:-5Gi} + storageClass: ${DATABASE_PERSISTENCE_STORAGE_CLASS:-""} + +timeseries: + replicas: ${TIMESERIES_REPLICAS:-1} + imageRegistry: ${DRYCC_REGISTRY} + limitsMemory: "256Mi" + limitsHugepages2Mi: "256Mi" + persistence: + enabled: true + size: ${TIMESERIES_PERSISTENCE_SIZE:-5Gi} + storageClass: ${TIMESERIES_PERSISTENCE_STORAGE_CLASS:-""} + +fluentbit: + imageRegistry: ${DRYCC_REGISTRY} + +controller: + apiReplicas: ${CONTROLLER_API_REPLICAS:-1} + celeryReplicas: ${CONTROLLER_CELERY_REPLICAS:-1} + webhookReplicas: ${CONTROLLER_WEBHOOK_REPLICAS:-1} + imageRegistry: ${DRYCC_REGISTRY} + appRuntimeClass: ${CONTROLLER_APP_RUNTIME_CLASS:-""} + appStorageClass: ${CONTROLLER_APP_STORAGE_CLASS:-"drycc-storage"} + +redis: + replicas: ${REDIS_REPLICAS:-1} + imageRegistry: ${DRYCC_REGISTRY} + persistence: + enabled: true + size: ${REDIS_PERSISTENCE_SIZE:-5Gi} + storageClass: ${REDIS_PERSISTENCE_STORAGE_CLASS:-""} + +storage: + csi: + statefulset: + replicas: ${STORAGE_CSI_STATEFULSET_REPLICAS:-1} + mainnode: + tipd: + replicas: ${STORAGE_MAINNODE_TIPD_REPLICAS:-1} + persistence: + enabled: true + size: ${STORAGE_MAINNODE_TIPD_PERSISTENCE_SIZE:-5Gi} + storageClass: "${STORAGE_MAINNODE_TIPD_PERSISTENCE_STORAGE_CLASS}" + weed: + replicas: ${STORAGE_MAINNODE_WEED_REPLICAS:-1} + persistence: + enabled: true + size: ${STORAGE_MAINNODE_WEED_PERSISTENCE_SIZE:-5Gi} + storageClass: "${STORAGE_MAINNODE_WEED_PERSISTENCE_STORAGE_CLASS}" + metanode: + tikv: + replicas: ${STORAGE_METANODE_TIKV_REPLICAS:-1} + persistence: + enabled: true + size: ${STORAGE_METANODE_TIKV_PERSISTENCE_SIZE:-5Gi} + storageClass: "${STORAGE_METANODE_TIKV_PERSISTENCE_STORAGE_CLASS}" + weed: + replicas: ${STORAGE_METANODE_WEED_REPLICAS:-1} + persistence: + enabled: true + size: ${STORAGE_METANODE_WEED_PERSISTENCE_SIZE:-5Gi} + storageClass: "${STORAGE_METANODE_WEED_PERSISTENCE_STORAGE_CLASS}" + datanode: + weed: + replicas: ${STORAGE_DATANODE_WEED_REPLICAS:-3} + persistence: + hdd: + enabled: true + size: ${STORAGE_DATANODE_WEED_PERSISTENCE_SIZE:-10Gi} + storageClass: "${STORAGE_DATANODE_WEED_PERSISTENCE_STORAGE_CLASS}" + +rabbitmq: + replicas: ${RABBITMQ_REPLICAS:-1} + imageRegistry: ${DRYCC_REGISTRY} + username: "${RABBITMQ_USERNAME}" + password: "${RABBITMQ_PASSWORD}" + persistence: + enabled: true + size: ${RABBITMQ_PERSISTENCE_SIZE:-5Gi} + storageClass: ${RABBITMQ_PERSISTENCE_STORAGE_CLASS:-""} + +imagebuilder: + imageRegistry: ${DRYCC_REGISTRY} + +logger: + replicas: ${LOGGER_REPLICAS:-1} + imageRegistry: ${DRYCC_REGISTRY} + +monitor: + grafana: + imageRegistry: ${DRYCC_REGISTRY} + persistence: + enabled: true + size: ${MONITOR_GRAFANA_PERSISTENCE_SIZE:-5Gi} + storageClass: ${MONITOR_GRAFANA_PERSISTENCE_STORAGE_CLASS:-""} + telegraf: + imageRegistry: ${DRYCC_REGISTRY} + +prometheus: + prometheus-server: + retention: ${PROMETHEUS_SERVER_RETENTION:-"15d"} + persistence: + enabled: true + accessMode: ReadWriteOnce + size: ${PROMETHEUS_SERVER_PERSISTENCE_SIZE:-10Gi} + storageClass: ${PROMETHEUS_SERVER_PERSISTENCE_STORAGE_CLASS:-""} + +passport: + replicas: ${PASSPORT_REPLICAS:-1} + imageRegistry: ${DRYCC_REGISTRY} + adminUsername: ${DRYCC_ADMIN_USERNAME} + adminPassword: ${DRYCC_ADMIN_PASSWORD} + +registry: + replicas: ${REGISTRY_REPLICAS:-1} + imageRegistry: ${DRYCC_REGISTRY} + +registry-proxy: + imageRegistry: ${DRYCC_REGISTRY} + +acme: + server: ${ACME_SERVER:-"https://acme-v02.api.letsencrypt.org/directory"} + externalAccountBinding: + keyID: ${ACME_EAB_KEY_ID:-""} + keySecret: ${ACME_EAB_KEY_SECRET:-""} +EOF + + if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then + cat << EOF > "/tmp/drycc-mirror-values.yaml" +imagebuilder: + container_registries: | + unqualified-search-registries = ["docker.io"] + short-name-mode="permissive" + [[registry]] + prefix = "docker.io" + location = "registry-1.docker.io" + [[registry.mirror]] + prefix = "docker.io" + location = "hub-mirror.c.163.com" +EOF + else + cat << EOF > "/tmp/drycc-mirror-values.yaml" +imagebuilder: + container_registries: | + unqualified-search-registries = ["docker.io"] + short-name-mode="permissive" +EOF + fi + + helm install drycc $CHARTS_URL/workflow \ + --namespace drycc \ + --values /tmp/drycc-values.yaml \ + --values /tmp/drycc-mirror-values.yaml \ + --create-namespace --wait --timeout 30m0s + echo -e "\\033[32m---> Rabbitmq username: $RABBITMQ_USERNAME\\033[0m" + echo -e "\\033[32m---> Rabbitmq password: $RABBITMQ_PASSWORD\\033[0m" +} + +function install_helmbroker { + if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then + addons_url="https://drycc-mirrors.drycc.cc/drycc-addons/addons/releases/download/latest/index.yaml" + else + addons_url="https://github.com/drycc-addons/addons/releases/download/latest/index.yaml" + fi + HELMBROKER_USERNAME=$(cat /proc/sys/kernel/random/uuid) + HELMBROKER_PASSWORD=$(cat /proc/sys/kernel/random/uuid) + + echo -e "\\033[32m---> Start installing helmbroker...\\033[0m" + + helm install helmbroker $CHARTS_URL/helmbroker \ + --set global.rabbitmqLocation="off-cluster" \ + --set global.gatewayClass=${GATEWAY_CLASS} \ + --set global.clusterDomain=${CLUSTER_DOMAIN} \ + --set global.platformDomain=${PLATFORM_DOMAIN} \ + --set global.certManagerEnabled=${CERT_MANAGER_ENABLED} \ + --set persistence.size=${HELMBROKER_PERSISTENCE_SIZE:-5Gi} \ + --set persistence.storageClass=${HELMBROKER_PERSISTENCE_STORAGE_CLASS:-"drycc-storage"} \ + --set username=${HELMBROKER_USERNAME} \ + --set password=${HELMBROKER_PASSWORD} \ + --set replicas=${HELMBROKER_REPLICAS} \ + --set celeryReplicas=${HELMBROKER_CELERY_REPLICAS} \ + --set rabbitmqUrl="amqp://${RABBITMQ_USERNAME}:${RABBITMQ_PASSWORD}@drycc-rabbitmq.drycc.svc.${CLUSTER_DOMAIN}:5672/drycc" \ + --namespace drycc-helmbroker --create-namespace --wait -f - < Helmbroker username: $HELMBROKER_USERNAME\\033[0m" + echo -e "\\033[32m---> Helmbroker password: $HELMBROKER_PASSWORD\\033[0m" +} + +export KUBECONFIG=/etc/rancher/k3s/k3s.yaml + +if [[ -z "$@" ]] ; then + check_drycc + check_metallb + install_k3s_server + install_helm + install_components + install_drycc + install_helmbroker + echo -e "\\033[32m---> Installation complete, enjoy life...\\033[0m" +else + for command in "$@" + do + $command + echo -e "\\033[32m---> Execute $command complete, enjoy life...\\033[0m" + done +fi diff --git a/installing-workflow/configuring-object-storage/index.html b/installing-workflow/configuring-object-storage/index.html new file mode 100644 index 000000000..965d1f4c4 --- /dev/null +++ b/installing-workflow/configuring-object-storage/index.html @@ -0,0 +1,892 @@ + + + + + + + + + + + + + + + + + + Configuring Object Storage - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Configuring Object Storage

+

A variety of Drycc Workflow components rely on an object storage system to do their work including storing application slugs, Container images and database logs.

+

Drycc Workflow ships with Storage by default, which provides in-cluster.

+

Configuring off-cluster Object Storage

+

Every component that relies on object storage uses two inputs for configuration:

+
    +
  1. You must use object storage services that are compatible with S3 API
  2. +
  3. Access credentials stored as a Kubernetes secret named storage-creds
  4. +
+

The helm chart for Drycc Workflow can be easily configured to connect Workflow components to off-cluster object storage. Drycc Workflow currently supports Google Compute Storage, Amazon S3, Azure Blob Storage and OpenStack Swift Storage.

+

Step 1: Create storage buckets

+

Create storage buckets for each of the Workflow subsystems: builder, registry, and database.

+

Depending on your chosen object storage you may need to provide globally unique bucket names. If you are using S3, use hyphens instead of periods in the bucket names. Using periods in the bucket name will cause an ssl certificate validation issue with S3.

+

If you provide credentials with sufficient access to the underlying storage, Workflow components will create the buckets if they do not exist.

+

Step 2: Generate storage credentials

+

If applicable, generate credentials that have create and write access to the storage buckets created in Step 1.

+

If you are using AWS S3 and your Kubernetes nodes are configured with appropriate IAM API keys via InstanceRoles, you do not need to create API credentials. Do, however, validate that the InstanceRole has appropriate permissions to the configured buckets!

+

Step 3: Configure Workflow Chart

+

Operators should configure object storage by editing the Helm values file before running helm install. To do so:

+
    +
  • Fetch the Helm values by running helm inspect values oci://registry.drycc.cc/charts/workflow > values.yaml
  • +
  • Update the global/storage parameter to reference the platform you are using, e.g. s3, azure, gcs, or swift
  • +
  • Find the corresponding section for your storage type and provide appropriate values including region, bucket names, and access credentials.
  • +
  • Save your changes.
  • +
+
+

Note

+

All values will be automatically (base64) encoded except the key_json values under gcs/gcr. These must be base64-encoded. This is to support cleanly passing said encoded text via helm --set cli functionality rather than attempting to pass the raw JSON data. For example:

+
$ helm install drycc oci://registry.drycc.cc/charts/workflow \
+    --namespace drycc \
+    --set global.platformDomain=youdomain.com
+    --set global.storage=gcs,gcs.key_json="$(cat /path/to/gcs_creds.json | base64 -w 0)"
+ + +
+

You are now ready to run helm install drycc oci://registry.drycc.cc/charts/workflow --namespace drycc -f values.yaml using your desired object storage.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/installing-workflow/configuring-postgres/index.html b/installing-workflow/configuring-postgres/index.html new file mode 100644 index 000000000..fe27a36dc --- /dev/null +++ b/installing-workflow/configuring-postgres/index.html @@ -0,0 +1,892 @@ + + + + + + + + + + + + + + + + + + Configuring Postgres - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Configuring Postgres

+

Drycc Workflow's controller and passport component rely on a PostgreSQL database to store platform state.

+

By default, Drycc Workflow ships with the database component, which provides an in-cluster PostgreSQL database backed up to in-cluster or off-cluster object storage. Currently, for object storage, which is utilized by several Workflow components, only off-cluster solutions such as S3 or GCS are recommended in production environments. Experience has shown that many operators already opting for off-cluster object storage similarly prefer to host Postgres off-cluster as well, using Amazon RDS or similar. When excercising both options, a Workflow installation becomes entirely stateless, and is thus restored or rebuilt with greater ease should the need ever arise.

+

Provisioning off-cluster Postgres

+

First, provision a PostgreSQL RDBMS using the cloud provider or other infrastructure of your choice. Take care to ensure that security groups or other firewall rules will permit connectivity from your Kubernetes worker nodes, any of which may play host to the Workflow controller component.

+

Take note of the following:

+
    +
  1. The hostname or public IP of your PostgreSQL RDBMS
  2. +
  3. The port on which your PostgreSQL RDBMS runs-- typically 5432
  4. +
+

Within the off-cluster RDBMS, manually provision the following:

+
    +
  1. A database user (take note of the username and password)
  2. +
  3. A database owned by that user (take note of its name)
  4. +
+

If you are able to log into the RDBMS as a superuser or a user with appropriate permissions, this process will typically look like this:

+
$ psql -h <host> -p <port> -d postgres -U <"postgres" or your own username>
+> create user <drycc username; typically "drycc"> with password '<password>';
+> create database <database name; typically "drycc"> with owner <drycc username>;
+> \q
+ + +

Configuring Workflow

+

The Helm chart for Drycc Workflow can be easily configured to connect the Workflow controller component to an off-cluster PostgreSQL database.

+
    +
  • Step 1: If you haven't already fetched the values, do so with helm inspect values drycc/workflow > values.yaml
  • +
  • Step 2: Update database connection details by modifying values.yaml:
      +
    • Update the databaseLocation parameter to off-cluster.
    • +
    • Update the values in the [database] configuration section to properly reflect all connection details.
    • +
    • Update the values in the [controller] configuration section to properly reflect platformDomain details.
    • +
    • Save your changes.
    • +
    • Note: you do not need to (and must not) base64 encode any values, as the Helm chart will automatically handle encoding as necessary.
    • +
    +
  • +
+

You are now ready to helm install drycc oci://registry.drycc.cc/charts/workflow --namespace drycc -f values.yaml as usual.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/installing-workflow/configuring-registry/index.html b/installing-workflow/configuring-registry/index.html new file mode 100644 index 000000000..2d55dd897 --- /dev/null +++ b/installing-workflow/configuring-registry/index.html @@ -0,0 +1,913 @@ + + + + + + + + + + + + + + + + + + Configuring the Registry - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Configuring Registry

+

Drycc Workflow's builder component relies on a registry for storing application container images.

+

Drycc Workflow ships with a registry component by default, which provides an in-cluster Container registry backed by the platform-configured object storage. Operators might want to use an off-cluster registry for performance or security reasons.

+

Configuring Off-Cluster Private Registry

+

Every component that relies on a registry uses two inputs for configuration:

+
    +
  1. Registry Location environment variable named DRYCC_REGISTRY_LOCATION
  2. +
  3. Access credentials stored as a Kubernetes secret named registry-secret
  4. +
+

The Helm chart for Drycc Workflow can be easily configured to connect Workflow components to off-cluster registry. Drycc Workflow supports external registries which provide either short-lived tokens that are valid only for a specified amount of time or long-lived tokens (basic username/password) which are valid forever for authenticating to them. For those registries which provide short lived tokens for authentication, Drycc Workflow will generate and refresh them such that the deployed apps will only have access to the short-lived tokens and not to the actual credentials for the registries.

+

When using a private registry the container images are no longer pulled by Drycc Workflow Controller but rather are managed by Kubernetes. This will increase security and overall speed, however the port information can no longer be discovered. Instead the port information can be set via drycc config:set PORT=<port> prior to deploying the application.

+

Drycc Workflow currently supports:

+
    +
  1. off-cluster: Any provider which supports long-lived username/password authentication, such as Azure Container Registry, Docker Hub, quay.io, or a self-hosted Container registry.
  2. +
+

Configuration

+
    +
  1. If you haven't already fetched the values file, do so with helm inspect values drycc/workflow > values.yaml
  2. +
  3. Update registry location details by modifying the values file:
      +
    • Update the registryLocation parameter to reference the registry location you are using: off-cluster, ecr, gcr
    • +
    • Update the values in the section which corresponds to your registry location type.
    • +
    +
  4. +
+

You are now ready to helm install drycc oci://registry.drycc.cc/charts/workflow --namespace drycc -f values.yaml using your desired registry.

+

Examples

+

Here we show how the relevant parts of the fetched values.yaml file might look like after configuring for a particular off-cluster registry:

+

Azure Container Registry (ACR)

+

After following the docs and creating a registry, e.g. myregistry, with its corresponding login server of myregistry.azurecr.io, the following values should be supplied:

+
global:
+...
+  registryLocation: "off-cluster"
+...
+registry-token-refresher:
+...
+  registry:
+    hostname: "myregistry.azurecr.io"
+    organization: "myorg"
+    username: "myusername"
+    password: "mypassword"
+...
+ + +

Note: The mandatory organization field (here myorg) will be created as an ACR repository if it does not already exist.

+

Quay.io

+
global:
+...
+  registryLocation: "off-cluster"
+...
+registry-token-refresher:
+...
+  registry:
+    hostname: "quay.io"
+    organization: "myorg"
+    username: "myusername"
+    password: "mypassword"
+...
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/installing-workflow/download-linux-brightgreen.svg b/installing-workflow/download-linux-brightgreen.svg new file mode 100644 index 000000000..a8a6a50be --- /dev/null +++ b/installing-workflow/download-linux-brightgreen.svg @@ -0,0 +1 @@ +downloaddownloadLinuxLinux \ No newline at end of file diff --git a/installing-workflow/download-osx-brightgreen.svg b/installing-workflow/download-osx-brightgreen.svg new file mode 100644 index 000000000..477afbf52 --- /dev/null +++ b/installing-workflow/download-osx-brightgreen.svg @@ -0,0 +1 @@ +downloaddownloadMac OS XMac OS X \ No newline at end of file diff --git a/installing-workflow/gateway/index.html b/installing-workflow/gateway/index.html new file mode 100644 index 000000000..76075c67a --- /dev/null +++ b/installing-workflow/gateway/index.html @@ -0,0 +1,945 @@ + + + + + + + + + + + + + + + + + + Installing Gateway - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Specify Gateway

+

Install Drycc Workflow (Specify gateway)

+

Now that Helm is installed and the repository has been added, install Workflow with a native gateway by running:

+
$ helm install drycc oci://registry.drycc.cc/charts/workflow \
+    --namespace drycc \
+    --set global.gatewayClass=istio \
+    --set global.platformDomain=drycc.cc \
+    --set builder.service.type=LoadBalancer
+ + +

Of course, if you deploy it on a bare machine, you probably do not have Load Balancer. You need to use NodePort:

+
$ helm install drycc oci://registry.drycc.cc/charts/workflow \
+    --namespace drycc \
+    --set global.gatewayClass=istio \
+    --set global.platformDomain=drycc.cc \
+    --set builder.service.type=NodePort \
+    --set builder.service.nodePort=32222
+ + +

If you want to use Load Balancer on a bare machine, you can look at metallb

+

Where global.platformDomain is a required parameter that is traditionally not required for Workflow that is explained in the next section. In this example we are using drycc.cc for $hostname.

+

Helm will install a variety of Kubernetes resources in the drycc namespace. +Wait for the pods that Helm launched to be ready. Monitor their status by running:

+
$ kubectl --namespace=drycc get pods
+ + +

You should also notice that several Kubernetes gatewayclass has been installed on your cluster. You can view it by running:

+
$ kubectl get gatewayclass --namespace drycc
+ + +

Depending on the order in which the Workflow components initialize, some pods may restart. This is common during the +installation: if a component's dependencies are not yet available, that component will exit and Kubernetes will +automatically restart it.

+

Here, it can be seen that the controller, builder and registry all took a few loops waiting for storage before they were able to start:

+
$ kubectl --namespace=drycc get pods
+NAME                          READY     STATUS    RESTARTS   AGE
+drycc-builder-hy3xv            1/1       Running   5          5m
+drycc-controller-g3cu8         1/1       Running   5          5m
+drycc-controller-celery-cmxxn  3/3       Running   0          5m
+drycc-database-rad1o           1/1       Running   0          5m
+drycc-logger-fluentbit-1v8uk   1/1       Running   0          5m
+drycc-logger-fluentbit-esm60   1/1       Running   0          5m
+drycc-logger-sm8b3             1/1       Running   0          5m
+drycc-storage-4ww3t            1/1       Running   0          5m
+drycc-registry-asozo           1/1       Running   1          5m
+drycc-rabbitmq-0               1/1       Running   0          5m
+ + +

Install a Kubernetes Gateway

+

Now that Workflow has been deployed with the global.gatewayClass , we will need a Kubernetes gateway in place to begin routing traffic.

+

Here is an example of how to use istio as an gateway for Workflow. Of course, you are welcome to use any controller you wish.

+
$ helm repo add istio https://istio-release.storage.googleapis.com/charts
+$ helm repo update
+$ kubectl create namespace istio-system
+$ helm install istio-base istio/base -n istio-system
+$ helm install istiod istio/istiod -n istio-system --wait
+$ kubectl create namespace istio-ingress
+$ helm install istio-ingress istio/gateway -n istio-ingress --wait
+ + +

Configure DNS

+

User must install drycc and then set up a hostname, and assumes the *.$host convention.

+

We need to point the *.$host record to the public IP address of your gateway. You can get the public IP using the following command. A wildcard entry is necessary here as apps will use the same rule after they are deployed.

+
$ kubectl get gateway --namespace drycc
+NAME      CLASS   ADDRESS         PROGRAMMED   AGE
+gateway   istio   138.91.243.152  True         36d
+ + +

If we were using drycc.cc as a hostname, we would need to create the following A DNS records.

+ + + + + + + + + + + + + + + +
NameTypeValue
*.drycc.ccA138.91.243.152
+

Once all of the pods are in the READY state, and *.$host resolves to the external IP found above, the preparation of gateway has been completed!

+

After installing Workflow, register a user and deploy an application.

+

If your k8s does not provide public network loadblance, you need to install TCP proxy services such as haproxy on machines that can +access both internal and external networks, and then expose 80 and 443.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/installing-workflow/index.html b/installing-workflow/index.html new file mode 100644 index 000000000..c71c7e30f --- /dev/null +++ b/installing-workflow/index.html @@ -0,0 +1,970 @@ + + + + + + + + + + + + + + + + + + Installing Workflow - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Installing Drycc Workflow

+

This document is aimed at those who have already provisioned a Kubernetes v1.16.15+ cluster +and want to install Drycc Workflow. If help is required getting started with Kubernetes and +Drycc Workflow, follow the quickstart guide for assistance.

+

Prerequisites

+
    +
  1. Verify the Kubernetes system requirements
  2. +
  3. Install Helm and Drycc Workflow CLI tools
  4. +
+

Check Your Setup

+

Check that the helm command is available and the version is v2.5.0 or newer.

+
$ helm version
+Client: &version.Version{SemVer:"v2.5.0", GitCommit:"012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6", GitTreeState:"clean"}
+Server: &version.Version{SemVer:"v2.5.0", GitCommit:"012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6", GitTreeState:"clean"}
+ + +

Choose Your Deployment Strategy

+

Drycc Workflow includes everything it needs to run out of the box. However, these defaults are aimed at simplicity rather than +production readiness. Production and staging deployments of Workflow should, at a minimum, use off-cluster storage +which is used by Workflow components to store and backup critical data. Should an operator need to completely re-install +Workflow, the required components can recover from off-cluster storage. See the documentation for configuring object +storage for more details.

+

More rigorous installations would benefit from using outside sources for the following things: +* Postgres - For example AWS RDS. +* Registry - This includes quay.io, dockerhub, Amazon ECR, and Google GCR. +* Redis - Such as AWS Elasticache +* Grafana

+

Gateway

+

Now, workflow requires that gateway and cert-manager must be installed. Any compatible Kubernetes entry controller can be used.

+

Install Drycc Workflow

+

If the version of helm is 3.0 +; you need to create the namespace in advance:

+
kubectl create ns drycc
+ + +

If you want to change it, set the variable when using helm.

+
$ helm install drycc oci://registry.drycc.cc/charts/workflow \
+    --namespace drycc \
+    --set builder.imageRegistry=quay.io \
+    --set imagebuilder.imageRegistry=quay.io \
+    --set controller.imageRegistry=quay.io \
+    --set database.imageRegistry=quay.io \
+    --set fluentbit.imageRegistry=quay.io \
+    --set redis.imageRegistry=quay.io \
+    --set rabbitmq.imageRegistry=quay.io \
+    --set logger.imageRegistry=quay.io \
+    --set storage.imageRegistry=quay.io \
+    --set monitor.imageRegistry=quay.io \
+    --set registry.imageRegistry=quay.io \
+    --set registry-proxy.imageRegistry=quay.io \
+    --set global.platformDomain=drycc.cc
+ + +

Helm will install a variety of Kubernetes resources in the drycc namespace. +Wait for the pods that Helm launched to be ready. Monitor their status by running:

+
$ kubectl --namespace=drycc get pods
+ + +

If it's preferred to have kubectl automatically update as the pod states change, run (type Ctrl-C to stop the watch):

+
$ kubectl --namespace=drycc get pods -w
+ + +

Depending on the order in which the Workflow components initialize, some pods may restart. This is common during the +installation: if a component's dependencies are not yet available, that component will exit and Kubernetes will +automatically restart it.

+

Here, it can be seen that the controller, builder and registry all took a few loops before they were able to start:

+
$ kubectl --namespace=drycc get pods
+NAME                                     READY     STATUS    RESTARTS   AGE
+drycc-builder-574483744-l15zj             1/1       Running   0          4m
+drycc-controller-3953262871-pncgq         1/1       Running   2          4m
+drycc-controller-celery-cmxxn             3/3       Running   0          4m
+drycc-database-83844344-47ld6             1/1       Running   0          4m
+drycc-logger-176328999-wjckx              1/1       Running   4          4m
+drycc-logger-fluentbit-zxnqb              1/1       Running   0          4m
+drycc-redis-304849759-1f35p               1/1       Running   0          4m
+drycc-storage-676004970-nxqgt             1/1       Running   0          4m
+drycc-monitor-grafana-432627134-lnl2h     1/1       Running   0          4m
+drycc-monitor-telegraf-wmcmn              1/1       Running   1          4m
+drycc-registry-756475849-lwc6b            1/1       Running   1          4m
+drycc-registry-proxy-96c4p                1/1       Running   0          4m
+drycc-rabbitmq-0                          1/1       Running   0          4m
+ + +

Once all of the pods are in the READY state, Drycc Workflow is up and running!

+

For more installation parameters, please check the values.yaml file of workflow.

+

After installing Workflow, register a user and deploy an application.

+

Configure DNS

+

User must to set up a hostname, and assumes the drycc-builder.$host convention.

+

We need to point the drycc-builder.$host record to the public IP address of your builder. You can get the public IP using the following command. A wildcard entry is necessary here as apps will use the same rule after they are deployed.

+
$ kubectl get svc drycc-builder --namespace drycc
+NAME              CLUSTER-IP   EXTERNAL-IP      PORT(S)                      AGE
+drycc-builder     10.0.25.3    138.91.243.152   2222:31625/TCP               33m
+ + +

If we were using drycc.cc as a hostname, we would need to create the following A DNS records.

+ + + + + + + + + + + + + + + +
NameTypeValue
drycc-builder.drycc.ccA138.91.243.152
+

Once all of the pods are in the READY state, and drycc-builder.$host resolves to the external IP found above, Workflow is up and running!

+

After installing Workflow, register a user and deploy an application.

+

If your k8s does not provide public network loadblance, you need to install TCP proxy services such as haproxy on machines that can +access both internal and external networks, and then expose 80 and 443.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/installing-workflow/system-requirements/index.html b/installing-workflow/system-requirements/index.html new file mode 100644 index 000000000..12b035b47 --- /dev/null +++ b/installing-workflow/system-requirements/index.html @@ -0,0 +1,887 @@ + + + + + + + + + + + + + + + + + + System Requirements - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Requirements

+

To run Drycc Workflow on a Kubernetes cluster, there are a few requirements to keep in mind.

+

Kubernetes Versions

+

Drycc Workflow requires Kubernetes v1.16.15 or later.

+

Components Requirements

+

Drycc uses gateway as a routing implementation, so you have to choose an gateway. We recommend using istio or kong.

+

Workflow supports the use of ACME to manage automatic certificates, cert-manager is also one of the necessary components, if you use cert-manager EAB, you need to set the clusterResourceNamespace to the namespace of drycc.

+

Workflow supports stateful apps. You can create and use them through the 'drycc volumes' command. If you want to use this feature, you must have a StorageClass that supports ReadWriteMany.

+

Workflow also supports the OSB API through the 'drycc resources' command. If you want to use this function, you need to install service-catalog.

+

Storage Requirements

+

A variety of Drycc Workflow components rely on an object storage system to do their work, including storing application +slugs, Container images and database logs.

+

Drycc Workflow ships with drycc storage by default, which provides in-cluster.

+

Workflow supports Amazon Simple Storage Service (S3), Google Cloud Storage (GCS), OpenShift Swift, and Azure Blob +Storage. See configuring object storage for setup instructions.

+

Resource Requirements

+

When deploying Drycc Workflow, it's important to provision machines with adequate resources. Drycc is a highly-available +distributed system, which means that Drycc components and your deployed applications will move around the cluster onto +healthy hosts as hosts leave the cluster for various reasons (failures, reboots, autoscalers, etc.). Because of this, +you should have ample spare resources on any machine in your cluster to withstand the additional load of running +services for failed machines.

+

Drycc Workflow components use about 2.5GB of memory across the cluster, and require approximately 30GB of hard disk +space. Because it may need to handle additional load if another one fails, each machine has minimum requirements of:

+
    +
  • At least 4GB of RAM (more is better)
  • +
  • At least 40GB of hard disk space
  • +
+

Note that these estimates are for Drycc Workflow and Kubernetes only. Be sure to leave enough spare capacity for your +application footprint as well.

+

Running smaller machines will likely result in increased system load and has been known to result in component failures +and instability.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/managing-workflow/configuring-dns/index.html b/managing-workflow/configuring-dns/index.html new file mode 100644 index 000000000..d465a6148 --- /dev/null +++ b/managing-workflow/configuring-dns/index.html @@ -0,0 +1,948 @@ + + + + + + + + + + + + + + + + + + Configuring DNS - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Configure DNS

+

The Drycc Workflow controller and all applications deployed via Workflow are intended (by default) to be accessible as subdomains of the Workflow cluster's domain. For example, assuming example.com were a cluster's domain:

+
    +
  • The controller should be accessible at drycc.example.com
  • +
  • Applications should be accessible (by default) at <application name>.example.com
  • +
+

Given that this is the case, the primary objective in configuring DNS is that traffic for all subdomains of a cluster's domain be directed to the cluster node(s) hosting the platform's router component, which is capable of directing traffic within the cluster to the correct endpoints.

+

With a Load Balancer

+

Generally, it is recommended that a [load balancer][] be used to direct inbound traffic to one or more routers. In such a case, configuring DNS is as simple as defining a wildcard record in DNS that points to the load balancer.

+

For example, assuming a domain of example.com:

+
    +
  • An A record enumerating each of your load balancer(s) IPs (i.e. DNS round-robining)
  • +
  • A CNAME record referencing an existing fully-qualified domain name for the load balancer
      +
    • Per AWS' own documentation, this is the recommended strategy when using AWS Elastic Load Balancers, as ELB IPs may change over time.
    • +
    +
  • +
+

DNS for any applications using a "custom domain" (a fully-qualified domain name that is not a subdomain of the cluster's own domain) can be configured by creating a CNAME record that references the wildcard record described above.

+

Although it is dependent upon your distribution of Kubernetes and your underlying infrastructure, in many cases, the IP(s) or existing fully-qualified domain name of a load balancer can be determined directly using the kubectl tool:

+
$ kubectl --namespace=istio-nginx describe service | grep "LoadBalancer"
+LoadBalancer Ingress:   a493e4e58ea0511e5bb390686bc85da3-1558404688.us-west-2.elb.amazonaws.com
+ + +

The LoadBalancer Ingress field typically describes an existing domain name or public IP(s). Note that if Kubernetes is able to automatically provision a load balancer for you, it does so asynchronously. If the command shown above is issued very soon after Workflow installation, the load balancer may not exist yet.

+

Without a Load Balancer

+

On some platforms (Minikube, for instance), a load balancer is not an easy or practical thing to provision. In these cases, one can directly identify the public IP of a Kubernetes node that is hosting a router pod and use that information to configure the local /etc/hosts file.

+

Because wildcard entries do not work in a local /etc/hosts file, using this strategy may result in frequent editing of that file to add fully-qualified subdomains of a cluster for each application added to that cluster. Because of this a more viable option may be to utilize the xip.io service.

+

In general, for any IP, a.b.c.d, the fully-qualified domain name any-subdomain.a.b.c.d.xip.io will resolve to the IP a.b.c.d. This can be enormously useful.

+

To begin, find the node(s) hosting router instances using kubectl:

+
$ kubectl --namespace=istio-ingress describe pod | grep Node:
+Node:       ip-10-0-0-199.us-west-2.compute.internal/10.0.0.199
+Node:       ip-10-0-0-198.us-west-2.compute.internal/10.0.0.198
+ + +

The command will display information for every router pod. For each, a node name and IP are displayed in the Node field. If the IPs appearing in these fields are public, any of these may be used to configure your local /etc/hosts file or may be used with xip.io. If the IPs shown are not public, further investigation may be needed.

+

You can list the IP addresses of a node using kubectl:

+
$ kubectl describe node ip-10-0-0-199.us-west-2.compute.internal
+# ...
+Addresses:  10.0.0.199,10.0.0.199,54.218.85.175
+# ...
+ + +

Here, the Addresses field lists all the node's IPs. If any of them are public, again, they may be used to configure your local /etc/hosts file or may be used with xip.io.

+

Tutorial: Configuring DNS with Google Cloud DNS

+

In this section, we'll describe how to configure Google Cloud DNS for routing your domain name to your Drycc cluster.

+

We'll assume the following in this section:

+
    +
  • Your Ingress service has a load balancer in front of it.
  • +
  • The load balancer need not be cloud based, it just needs to provide a stable IP address or a stable domain name
  • +
  • You have the mystuff.com domain name registered with a registrar
  • +
  • Replace your domain name with mystuff.com in the instructions to follow
  • +
  • Your registrar lets you alter the nameservers for your domain name (most registrars do)
  • +
+

Here are the steps for configuring cloud DNS to route to your drycc cluster:

+
    +
  1. Get the load balancer IP or domain name
  2. +
  3. If you are on Google Container Engine, you can run kubectl get svc -n istio-ingress and look for the LoadBalancer Ingress column to get the IP address
  4. +
  5. Create a new Cloud DNS Zone (on the console: Networking => Cloud DNS, then click on Create Zone)
  6. +
  7. Name your zone, and set the DNS name to mystuff.com. (note the . at the end
  8. +
  9. Click on the Create button
  10. +
  11. Click on the Add Record Set button on the resulting page
  12. +
  13. If your load balancer provides a stable IP address, enter the following fields in the resulting form:
  14. +
  15. DNS Name: *
  16. +
  17. Resource Record Type: A
  18. +
  19. TTL: the DNS TTL of your choosing. If you're testing or you anticipate that you'll tear down and rebuild many drycc clusters over time, we recommend a low TTL
  20. +
  21. IPv4 Address: The IP that you got in the very first step
  22. +
  23. Click the Create button
  24. +
  25. If your load balancer provides the stable domain name lbdomain.com, enter the following fields in the resulting form:
  26. +
  27. DNS Name: *
  28. +
  29. Resource Record Type: CNAME
  30. +
  31. TTL: the DNS TTL of your choosing. If you're testing or you anticipate that you'll tear down and rebuild many drycc clusters over time, we recommend a low TTL
  32. +
  33. Canonical name: lbdomain.com. (note the . a the end)
  34. +
  35. Click on the Create button
  36. +
  37. In your domain registrar, set the nameservers for your mystuff.com domain to the ones under the data column in the NS record on the same page. They'll often be something like the below (note the trailing . characters).
  38. +
+

ns-cloud-b1.googledomains.com. + ns-cloud-b2.googledomains.com. + ns-cloud-b3.googledomains.com. + ns-cloud-b4.googledomains.com.

+

Note: If you ever have to re-create your drycc cluster, simply go back to step 6.4 or 7.4 (depending on your load balancer) and change the IP address or domain name to the new value. You may have to wait for the TTL you set to expire.

+

Testing

+

To test that traffic reaches its intended destination, a request can be +sent to the Drycc controller like so (do not forget the trailing slash!):

+
curl http://drycc.example.com/v2/
+ + +

Or:

+
curl http://drycc.54.218.85.175.xip.io/v2/
+ + +

Since such requests require authentication, a response such as the following should be considered an indicator of success:

+
{"detail":"Authentication credentials were not provided."}
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/managing-workflow/deploy-hooks/index.html b/managing-workflow/deploy-hooks/index.html new file mode 100644 index 000000000..32b0bff04 --- /dev/null +++ b/managing-workflow/deploy-hooks/index.html @@ -0,0 +1,896 @@ + + + + + + + + + + + + + + + + + + Deploy Hooks - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Deploy Hooks

+

Deploy hooks allow an external service to receive a notification whenever a new version of your app +is pushed to Workflow. It’s useful to help keep the development team informed about deploys, while +it can also be used to integrate different systems together.

+

After one or more hooks are setup, hook output and errors appear in your application’s logs:

+
$ drycc logs
+...
+2011-03-15T15:07:29-07:00 drycc[api]: Deploy hook sent to http://drycc.rocks
+ + +

Deploy hooks are a generic HTTP hook. An administrator can create and configure multiple deploy +hooks by tuning the controller settings via the Helm chart.

+

HTTP POST Hook

+

The HTTP deploy hook performs an HTTP POST to a URL. The parameters included in the request are the +same as the variables available in the hook message: app, release, release_summary, sha and +user. See below for their descriptions:

+
app=secure-woodland&release=v4&release_summary=gabrtv%20deployed%35b3726&sha=35b3726&user=gabrtv
+ + +

Optionally, if a deploy hook secret key is added to the controller through +tuning the controller settings, a new Authorization header will be +present in the POST request. The value of this header is computed as the HMAC hex digest of the +request URL, using the secret as the key.

+

In order to authenticate that this request came from Workflow, use the secret key, the full URL and +the HMAC-SHA1 hashing algorithm to compute the signature. In Python, that would look something like +this:

+
import hashlib
+import hmac
+
+hmac.new("my_secret_key", "http://drycc.rocks?app=secure-woodland&release=v4&release_summary=gabrtv%20deployed%35b3726&sha=35b3726&user=gabrtv", digestmod=hashlib.sha1).hexdigest()
+ + +

If the value of the computed HMAC hex digest and the value in the Authorization header are +identical, then the request came from Workflow.

+
+

Important

+

When computing the signature, ensure that the URL parameters are in alphabetic order. This is +critical when computing the cryptographic signature as most web applications don't care about +the order of the HTTP parameters, but the cryptographic signature will not be the same.

+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/managing-workflow/platform-logging/index.html b/managing-workflow/platform-logging/index.html new file mode 100644 index 000000000..4bd45f3b0 --- /dev/null +++ b/managing-workflow/platform-logging/index.html @@ -0,0 +1,896 @@ + + + + + + + + + + + + + + + + + + Platform Logging - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Platform Logging

+

The logging platform is made up of 2 components - Fluentbit and Logger.

+

Fluentbit runs on every worker node of the cluster and is deployed as a Daemon Set. The Fluentbit pods capture all of the stderr and stdout streams of every container running on the host (even those not hosted directly by kubernetes). Once the log message arrives in our custom fluentbit plugin we determine where the message originated.

+

If the message was from the Workflow Controller or from an application deployed via workflow we send it to the logs topic on the local Redis Stream instance.

+

Logger then acts as a consumer reading messages off of the Redis Stream logs topic storing those messages in a local Redis instance. When a user wants to retrieve log entries using the drycc logs command we make an HTTP request from Controller to Logger which then fetches the appropriate data from Redis.

+

Configuring Off Cluster Redis

+

Even though we provide a redis instance with the default Workflow install, it is recommended that operators use a third-party source like Elasticache or similar offering. This way your data is durable across upgrades or outages. If you have a third-party Redis installation you would like to use all you need to do is set the following values in your helm chart:

+
    +
  • db = "0"
  • +
  • host = "my.host.redis"
  • +
  • port = "6379"
  • +
  • password = ""
  • +
+

These can be changed by running helm inspect values drycc/workflow > values.yaml before using +helm install to complete the installation. To customize the redis credentials, edit values.yaml +and modify the redis section of the file to tune these settings.

+

Debugging Logger

+

If the drycc logs command encounters an error it will return the following message:

+
Error: There are currently no log messages. Please check the following things:
+1) Logger and fluentbit pods are running.
+2) The application is writing logs to the logger component by checking that an entry in the ring buffer was created: kubectl  --namespace=drycc logs <logger pod>
+3) Making sure that the container logs were mounted properly into the fluentbit pod: kubectl --namespace=drycc exec <fluentbit pod> ls /var/log/containers
+ + +

Architecture Diagram

+
                        ┌────────┐                                        
+                        │ Router │                  ┌────────┐     ┌─────┐
+                        └────────┘                  │ Logger │◀───▶│Redis│
+                            │                       └────────┘     └─────┘
+                        Log file                        ▲                
+                            │                           │                
+                            ▼                           │                
+┌────────┐             ┌─────────┐    logs/metrics   ┌──────────────┐     
+│App Logs│──Log File──▶│Fluentbit│───────topics─────▶│ Redis Stream │     
+└────────┘             └─────────┘                   └──────────────┘     
+ + +

Default Configuration

+

Fluent Bit is based in a pluggable architecture where different plugins plays a major role in the data pipeline, more than 70 built-in plugins available. +Please refer to charts values.yaml for specific configurations.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/managing-workflow/platform-monitoring/index.html b/managing-workflow/platform-monitoring/index.html new file mode 100644 index 000000000..e1b7bc3ec --- /dev/null +++ b/managing-workflow/platform-monitoring/index.html @@ -0,0 +1,931 @@ + + + + + + + + + + + + + + + + + + Platform Monitoring - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Platform Monitoring

+

Description

+

We now include a monitoring stack for introspection on a running Kubernetes cluster. The stack includes 4 components:

+ +

Architecture Diagram

+
┌────────────────┐                                                        
+│ HOST           │                                                        
+│  node-exporter │◀──┐                       ┌──────────────────┐         
+└────────────────┘   │                       │kube-state-metrics│         
+                     │                       └──────────────────┘         
+┌────────────────┐   │                               ▲                    
+│ HOST           │   │    ┌────────────┐             │                    
+│  node-exporter │◀──┼────│ Prometheus │─────────────┘                    
+└────────────────┘   │    └────────────┘                                  
+                     │          ▲                                         
+┌───────────────┐    │          │                                         
+│ HOST          │    │          ▼                                         
+│  node-exporter│◀───┘    ┌──────────┐                                    
+└───────────────┘         │ Grafana  │                                    
+                          └──────────┘                                    
+ + +

Grafana

+

Grafana allows users to create custom dashboards that visualize the data captured to the running Prometheus component. By default Grafana is exposed using a service annotation through the router at the following URL: http://grafana.mydomain.com. The default login is admin/admin. If you are interested in changing these values please see [Tuning Component Settings][].

+

Grafana will preload several dashboards to help operators get started with monitoring Kubernetes and Drycc Workflow. +These dashboards are meant as starting points and don't include every item that might be desirable to monitor in a +production installation.

+

Drycc Workflow monitoring by default does not write data to the host filesystem or to long-term storage. If the Grafana instance fails, modified dashboards are lost.

+

Production Configuration

+

A production install of Grafana should have the following configuration values changed if possible:

+
    +
  • Change the default username and password from admin/admin. The value for the password is passed in plain text so it is best to set this value on the command line instead of checking it into version control.
  • +
  • Enable persistence
  • +
  • Use a supported external database such as mysql or postgres. You can find more information here
  • +
+

On Cluster Persistence

+

Enabling persistence will allow your custom configuration to persist across pod restarts. This means that the default sqllite database (which stores things like sessions and user data) will not disappear if you upgrade the Workflow installation.

+

If you wish to have persistence for Grafana you can set enabled to true in the values.yaml file before running helm install.

+
 grafana:
+   # Configure the following ONLY if you want persistence for on-cluster grafana
+   # GCP PDs and EBS volumes are supported only
+   persistence:
+     enabled: true # Set to true to enable persistence
+     size: 5Gi # PVC size
+ + +

Off Cluster Grafana

+

If you wish to provide your own Grafana instance you can set grafanaLocation in the values.yaml file before running helm install.

+

Prometheus

+

Prometheus writes data to the host disk; however, if the prometheus pod dies and comes back on another host, the data will not be recovered. The prometheus graph UI is also exposed through the router allowing users to access the query engine by going to prometheus.mydomain.com.

+

On Cluster Persistence

+

You can set node-exporter and kube-state-metrics to true or false in the values.yaml. +If you wish to have persistence for Prometheus you can set enabled to true in the values.yaml file before running helm install.

+
prometheus:
+  prometheus-server:
+    persistence:
+      enabled: true # Set to true to enable persistence
+      size: 10Gi # PVC size
+node-exporter:
+  enabled: true
+kube-state-metrics:
+  enabled: true
+ + +

Off Cluster Prometheus

+

To use off-cluster Prometheus, please provide the following values in the values.yaml file before running helm install.

+
    +
  • global.prometheusLocation=off-cluster
  • +
  • url = "http://my.prometheus.url:9090"
  • +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/managing-workflow/production-deployments/index.html b/managing-workflow/production-deployments/index.html new file mode 100644 index 000000000..6d4b004bd --- /dev/null +++ b/managing-workflow/production-deployments/index.html @@ -0,0 +1,896 @@ + + + + + + + + + + + + + + + + + + Production Deployments - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Production Deployments

+

When readying a Workflow deployment for production workloads, there are some additional +recommendations.

+

Running Workflow without drycc storage

+

In production, persistent storage can be achieved by running an external object store. +For users on AWS, GCE/GKE or Azure, the convenience of Amazon S3, Google GCS or Microsoft Azure Storage +makes the prospect of running a Storage-less Workflow cluster quite reasonable. For users who have restriction +on using external object storage using swift object storage can be an option.

+

Running a Workflow cluster without Storage provides several advantages:

+
    +
  • Removal of state from the worker nodes
  • +
  • Reduced resource usage
  • +
  • Reduced complexity and operational burden of managing Workflow
  • +
+

See Configuring Object Storage for details on removing this operational complexity.

+

Review Security Considerations

+

There are some additional security-related considerations when running Workflow in production. +See [Security Considerations][] for details.

+

Registration is Admin-Only

+

By default, registration with the Workflow controller is in "admin_only" mode. The first user +to run a drycc register command becomes the initial "admin" user, and registrations after that +are disallowed unless requested by an admin.

+

Please see the following documentation to learn about changing registration mode:

+ +

Disable Grafana Signups

+

It is also recommended to disable signups for the Grafana dashboards.

+

Please see the following documentation to learn about disabling Grafana signups:

+ +

Running Workflow with RBAC

+

If your cluster has RBAC amongst your authorization modes ($ kubectl api-versions should contains rbac.authorization.k8s.io) it may be necessary to enable RBAC in Workflow. +This can be achieved by setting use_rbac in the global section of values.yaml to true, or by adding --set=global.use_rbac=true to the $ helm install/upgrade command. +RBAC support was announced in Kubernetes-1.5 and is enabled by default if: +- your Kubernetes cluster is in GKE +- your Kubernetes cluster built with kubeadm

+

Note: helm may need to be given specific permissions under RBAC if not already done.

+

Attention: Azure ACS Kubernetes clusters are not RBAC-enabled for today due to lack in authentication strategy. Feel free to watch this PR for more details.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/managing-workflow/tuning-component-settings/index.html b/managing-workflow/tuning-component-settings/index.html new file mode 100644 index 000000000..b8e95fd1f --- /dev/null +++ b/managing-workflow/tuning-component-settings/index.html @@ -0,0 +1,1186 @@ + + + + + + + + + + + + + + + + + + Tuning Component Settings - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Tuning Component Settings

+

Helm Charts are a set of Kubernetes manifests that reflect best practices for deploying an +application or service on Kubernetes.

+

After you add the Drycc Chart Repository, you can customize the chart using +helm inspect values drycc/workflow > values.yaml before using helm install to complete the +installation.

+

There are a few ways to customize the respective component:

+
    +
  • +

    If the value is exposed in the values.yaml file as derived above, one may modify the section of the component to tune these settings. The modified value(s) will then take effect at chart installation or release upgrade time via either of the two respective commands:

    +
    $ helm install drycc oci://registry.drycc.cc/charts/workflow \
    +    -n drycc \
    +    --namespace drycc \
    +    -f values.yaml
    +$ helm upgrade drycc oci://registry.drycc.cc/charts/workflow \
    +    -n drycc \
    +    --namespace drycc \
    +    -f values.yaml
    + + +
  • +
  • +

    If the value hasn't yet been exposed in the values.yaml file, one may edit the component deployment with the tuned setting. Here we edit the drycc-controller deployment:

    +
    $ kubectl --namespace drycc edit deployment drycc-controller
    + + +

    Add/edit the setting via the appropriate environment variable and value under the env section and save. The updated deployment will recreate the component pod with the new/modified setting.

    +
  • +
  • +

    Lastly, one may also fetch and edit the chart as served by version control/the chart repository itself:

    +
    $ helm fetch oci://registry.drycc.cc/charts/workflow --untar
    +$ $EDITOR workflow/charts/controller/templates/controller-deployment.yaml
    + + +

    Then run helm install ./workflow --namespace drycc --name drycc to apply the changes, or helm upgrade drycc ./workflow if the cluster is already running.

    +
  • +
+

Setting Resource limits

+

You can set resource limits to Workflow components by modifying the values.yaml file fetched +earlier. This file has a section for each Workflow component. To set a limit to any Workflow +component just add limitsCpu, limitsMemory in the section and set them to the appropriate +values.

+

Below is an example of how the builder section of values.yaml might look with CPU and memory +limits set:

+
builder:
+  imageOrg: "drycc"
+  imagePullPolicy: "Always"
+  imageTag: "canary"
+  limitsCpu: "100m"
+  limitsMemory: "50Mi"
+ + +

Customizing the Builder

+

The following environment variables are tunable for the Builder component:

+ + + + + + + + + + + + + + + + + +
SettingDescription
DEBUGEnable debug log output (default: false)
BUILDER_POD_NODE_SELECTORA node selector setting for builder job. As it may sometimes consume a lot of node resources, one may want a given builder job to run in a specific node only, so it won't affect critical nodes. for example pool:testing,disk:magnetic
+

Customizing the Controller

+

The following environment variables are tunable for the Controller component:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SettingDescription
REGISTRATION_MODEset registration to "enabled", "disabled", or "admin_only" (default: "admin_only")
GUNICORN_WORKERSnumber of gunicorn workers spawned to process requests (default: CPU cores * 4 + 1)
RESERVED_NAMESa comma-separated list of names which applications cannot reserve for routing (default: "drycc, drycc-builder")
DRYCC_DEPLOY_HOOK_URLSa comma-separated list of URLs to send deploy hooks to.
DRYCC_DEPLOY_HOOK_SECRET_KEYa private key used to compute the HMAC signature for deploy hooks.
DRYCC_DEPLOY_REJECT_IF_PROCFILE_MISSINGrejects a deploy if the previous build had a Procfile but the current deploy is missing it. A 409 is thrown in the API. Prevents accidental process types removal. (default: "false", allowed values: "true", "false")
DRYCC_DEPLOY_PROCFILE_MISSING_REMOVEwhen turned on (default) any missing process type in a Procfile compared to the previous deploy is removed. When set to false will allow an empty Procfile to go through without removing missing process types, note that new images, configs and so on will get updated on all proc types. (default: "true", allowed values: "true", "false")
DRYCC_DEFAULT_CONFIG_TAGSset tags for all applications by default, for example: '{"role": "worker"}'. (default: '')
KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPECset resource quota to application namespace by setting ResourceQuota spec, for example: {"spec":{"hard":{"pods":"10"}}}, restrict app owner to spawn more then 10 pods (default: "", no quota will be applied to namespace)
+

LDAP authentication settings

+

Configuration options for LDAP authentication are detailed here.

+

The following environment variables are available for enabling LDAP +authentication of user accounts in the Passport component:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SettingDescription
LDAP_ENDPOINTThe URI of the LDAP server. If not specified, LDAP authentication is not enabled (default: "", example: ldap://hostname).
LDAP_BIND_DNThe distinguished name to use when binding to the LDAP server (default: "")
LDAP_BIND_PASSWORDThe password to use with LDAP_BIND_DN (default: "")
LDAP_USER_BASEDNThe distinguished name of the search base for user names (default: "")
LDAP_USER_FILTERThe name of the login field in the users search base (default: "username")
LDAP_GROUP_BASEDNThe distinguished name of the search base for user's groups names (default: "")
LDAP_GROUP_FILTERThe filter for user's groups (default: "", example: objectClass=person)
+

Global and per application settings

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SettingDescription
DRYCC_DEPLOY_BATCHESthe number of pods to bring up and take down sequentially during a scale (default: number of available nodes)
DRYCC_DEPLOY_TIMEOUTdeploy timeout in seconds per deploy batch (default: 120)
IMAGE_PULL_POLICYthe kubernetes image pull policy for application images (default: "IfNotPresent") (allowed values: "Always", "IfNotPresent")
KUBERNETES_DEPLOYMENTS_REVISION_HISTORY_LIMIThow many revisions Kubernetes keeps around of a given Deployment (default: all revisions)
KUBERNETES_POD_TERMINATION_GRACE_PERIOD_SECONDShow many seconds kubernetes waits for a pod to finish work after a SIGTERM before sending SIGKILL (default: 30)
+

See the Deploying Apps guide for more detailed information on those.

+

Customizing the Database

+

The following environment variables are tunable for the Database component:

+ + + + + + + + + + + + + + + + + +
SettingDescription
BACKUP_FREQUENCYhow often the database should perform a base backup (default: "12h")
BACKUPS_TO_RETAINnumber of base backups the backing store should retain (default: 5)
+

Customizing Fluentbit

+

The following values can be changed in the values.yaml file or by using the --values flag with the Helm CLI.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
config.serviceThe service section defines the global properties of the service.
config.inputsAn input section defines a source (related to an input plugin).
config.filtersA filter section defines a filter (related to a filter plugin)
config.outputsThe outputs section specify a destination that certain records should follow after a Tag match.
+

For more information about the various variables that can be set please see the fluentbit.

+

Customizing the Logger

+

The following environment variables are tunable for the Logger component:

+ + + + + + + + + + + + + + + + + +
SettingDescription
STORAGE_ADAPTERHow to store logs that are sent to the logger. Legal values are "file", "memory", and "redis". (default: "redis")
NUMBER_OF_LINESHow many lines to store in the ring buffer (default: 1000)
+

Customizing the Monitor

+

Grafana

+

We have exposed some of the more useful configuration values directly in the chart. This allows them to be set using either the values.yaml file or by using the --set flag with the Helm CLI. You can see these options below:

+

Setting | Default Value | Description +----------------- | -------------- |------------ | +user | "admin" | The first user created in the database (this user has admin privileges) +password | "admin" | Password for the first user. +allow_sign_up | "true" | Allows users to sign up for an account.

+

For a list of other options you can set by using environment variables please see the configuration file in Github.

+

Telegraf

+

For a list of configuration values that can be set by using environment variables please see the following configuration file.

+

Prometheus

+

You can find a list of values that can be set using environment variables here.

+

Customizing the Registry

+

The Registry component can be tuned by following the +drycc/distribution config doc.

+

Customizing the Router

+

The majority of router settings are tunable through annotations, which allows the router to be +re-configured with zero downtime post-installation. You can find the list of annotations to tune +here.

+

The following environment variables are tunable for the [Router][] component:

+ + + + + + + + + + + + + +
SettingDescription
POD_NAMESPACEThe pod namespace the router resides in. This is set by the Kubernetes downward API.
+

Customizing Workflow Manager

+

The following environment variables are tunable for [Workflow Manager][]:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SettingDescription
CHECK_VERSIONSEnables the external version check at https://versions.drycc.info/ (default: "true")
POLL_INTERVAL_SECThe interval when Workflow Manager performs a version check, in seconds (default: 43200, or 12 hours)
VERSIONS_API_URLThe versions API URL (default: "https://versions-staging.drycc.info")
DOCTOR_API_URLThe doctor API URL (default: "https://doctor-staging.drycc.info")
API_VERSIONThe version number Workflow Manager sends to the versions API (default: "v2")
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/managing-workflow/upgrading-workflow/index.html b/managing-workflow/upgrading-workflow/index.html new file mode 100644 index 000000000..206cc6300 --- /dev/null +++ b/managing-workflow/upgrading-workflow/index.html @@ -0,0 +1,914 @@ + + + + + + + + + + + + + + + + + + Upgrading Workflow - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Upgrading Workflow

+

Drycc Workflow releases may be upgraded in-place with minimal downtime. This upgrade process requires:

+ +

Upgrade Process

+
+

Note

+

If upgrading from a Helm Classic install, you'll need to 'migrate' the cluster to a Kubernetes Helm installation. See Workflow-Migration for steps.

+
+

Step 1: Apply the Workflow upgrade

+

Helm will remove all components from the previous release. Traffic to applications deployed through +Workflow will continue to flow during the upgrade. No service interruptions should occur.

+

If Workflow is not configured to use off-cluster Postgres, the Workflow API will experience a brief +period of downtime while the database recovers from backup.

+

First, find the name of the release helm gave to your deployment with helm ls, then run

+
$ helm upgrade <release-name> oci://registry.drycc.cc/charts/workflow
+ + +

Note: If using off-cluster object storage on gcs and/or off-cluster registry using gcr and intending to upgrade from a pre-v2.10.0 chart to v2.10.0 or greater, the key_json values will now need to be pre-base64-encoded. Therefore, assuming the rest of the custom/off-cluster values are defined in the existing values.yaml used for previous installs, the following may be run:

+
$ B64_KEY_JSON="$(cat ~/path/to/key.json | base64 -w 0)"
+$ helm upgrade <release_name> drycc/workflow -f values.yaml --set gcs.key_json="${B64_KEY_JSON}",registry-token-refresher.gcr.key_json="${B64_KEY_JSON}"
+ + +

Alternatively, simply replace the appropriate values in values.yaml and do without the --set +parameter. Make sure to wrap it in single quotes as double quotes will give a parser error when +upgrading.

+

Step 2: Verify Upgrade

+

Verify that all components have started and passed their readiness checks:

+
$ kubectl --namespace=drycc get pods
+NAME                                     READY     STATUS    RESTARTS   AGE
+drycc-builder-2448122224-3cibz            1/1       Running   0          5m
+drycc-controller-1410285775-ipc34         1/1       Running   3          5m
+drycc-controller-celery-694f75749b-cmxxn  3/3       Running   0          5m
+drycc-database-e7c5z                      1/1       Running   0          5m
+drycc-logger-cgjup                        1/1       Running   3          5m
+drycc-logger-fluentbit-45h7j              1/1       Running   0          5m
+drycc-logger-fluentbit-4z7lw              1/1       Running   0          5m
+drycc-logger-fluentbit-k2wsw              1/1       Running   0          5m
+drycc-logger-fluentbit-skdw4              1/1       Running   0          5m
+drycc-redis-8nazu                         1/1       Running   0          5m
+drycc-monitor-grafana-tm266               1/1       Running   0          5m
+drycc-monitor-telegraf-51zel              1/1       Running   1          5m
+drycc-monitor-telegraf-cdasg              1/1       Running   0          5m
+drycc-monitor-telegraf-hea6x              1/1       Running   0          5m
+drycc-monitor-telegraf-r7lsg              1/1       Running   0          5m
+drycc-registry-1814324048-yomz5           1/1       Running   0          5m
+drycc-registry-proxy-4m3o4                1/1       Running   0          5m
+drycc-registry-proxy-no3r1                1/1       Running   0          5m
+drycc-registry-proxy-ou8is                1/1       Running   0          5m
+drycc-registry-proxy-zyajl                1/1       Running   0          5m
+drycc-rabbitmq-0                          1/1       Running   0          5m
+ + +

Step 3: Upgrade the Drycc Client

+

Users of Drycc Workflow should now upgrade their drycc client to avoid getting WARNING: Client and server API versions do not match. Please consider upgrading. warnings.

+
curl -sfL https://www.drycc.cc/install-cli.sh | bash - && sudo mv drycc $(which drycc)
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/quickstart/deploy-an-app/index.html b/quickstart/deploy-an-app/index.html new file mode 100644 index 000000000..90144286d --- /dev/null +++ b/quickstart/deploy-an-app/index.html @@ -0,0 +1,948 @@ + + + + + + + + + + + + + + + + + + Deploy Your First App - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Determine Your Host and Hostname Values

+

Drycc workflow requires a wildcard DNS record to dynamically map app names to the router.

+

User should already have DNS set up pointing to their known host. The $hostname value can be calculated by prepending drycc. to the value set in global.platformDomain.

+

Login to Workflow

+

Workflow use the passport component to create and authorize users. +If you already have an account, use drycc login to authenticate against the Drycc Workflow API.

+
$ drycc login http://drycc.example.com
+Opening browser to http://drycc.example.com/v2/login/drycc/?key=4ccc81ee2dce4349ad5261ceffe72c71
+Waiting for login... .o.Logged in as admin
+Configuration file written to /root/.drycc/client.json
+ + +

Deploy an Application

+

Drycc Workflow supports three different types of applications, Buildpacks, +Dockerfiles and Container Images. Our first application will be a simple Container +Image-based application, so you don't have to wrestle with checking out code.

+

Run drycc create to create a new application on Drycc Workflow. If you do not +specify a name for your application, Workflow automatically generates a +friendly (and sometimes funny) name.

+
$ drycc create --no-remote
+Creating Application... done, created proper-barbecue
+If you want to add a git remote for this app later, use `drycc git:remote -a proper-barbecue`
+ + +

Our application has been created and named proper-barbecue. As with the +drycc hostname, any HTTP traffic to proper-barbecue will be automatically +routed to your application pods by the edge router.

+

Let's use the CLI to tell the platform to deploy an application and then use curl to send a request to the app:

+
$ drycc pull drycc/example-go -a proper-barbecue
+Creating build... done
+$ curl http://proper-barbecue.$hostname
+Powered by Drycc
+ + +
+

Note

If you see a 404 error, make sure you specified your application name with -a <appname>!

+

+
+

Workflow's edge router knows all about application names and automatically +sends traffic to the right application. The router sends traffic for +proper-barbecue.104.197.125.75.nip.io to your app, just like +drycc.104.197.125.75.nip.io was sent to the Workflow API service.

+

Change Application Configuration

+

Next, let's change some configuration using the CLI. Our example app is built +to read configuration from the environment. By using drycc config:set we can +change how the application behaves:

+
$ drycc config:set POWERED_BY="Container Images + Kubernetes" -a proper-barbecue
+Creating config... done
+
+=== proper-barbecue Config
+POWERED_BY      Container Images + Kubernetes
+ + +

Behind the scenes, Workflow creates a new release for your application and uses +Kubernetes to provide a zero-downtime rolling deploy to the new release!

+

Validate that our configuration change has worked:

+
$ curl http://proper-barbecue.104.197.125.75.nip.io
+Powered by Container Images + Kubernetes
+ + +

Scale Your Application

+

Last, let's scale our application by adding more application processes. Using the CLI you can easily add and remove +additional processes to service requests:

+
$ drycc scale cmd=2 -a proper-barbecue
+Scaling processes... but first, coffee!
+done in 36s
+=== proper-barbecue Processes
+--- cmd (started): 2
+proper-barbecue-v18-cmd-rk644 up (v18)
+proper-barbecue-v18-cmd-0ag04 up (v18)
+ + +

Congratulations! You have deployed, configured, and scaled your first application using Drycc Workflow.

+

Going Further

+

There is a lot more you can do with Drycc Workflow, play around with the CLI:

+
+

Important

+

In order to have permission to push an app you must add a SSH key to your user on the Drycc Workflow. +For more information, please check Users and SSH Keys and Troubleshooting Workflow.

+
+ +
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/quickstart/index.html b/quickstart/index.html new file mode 100644 index 000000000..a775009da --- /dev/null +++ b/quickstart/index.html @@ -0,0 +1,870 @@ + + + + + + + + + + + + + + + + + + Overview - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Quick Start

+

Get started with Drycc Workflow in three easy steps.

+
    +
  1. Install CLI tools for Helm and Drycc Workflow
  2. +
  3. Boot a Kubernetes and install Drycc Workflow
  4. +
  5. Deploy your first application
  6. +
+

This guide will help you set up a cluster suitable for evaluation, development and testing. When you are ready for staging and production, view our production checklist.

+

Step 1: Install Workflow

+

For the quickstart we will install Drycc Workflow.

+

Step 2: Install CLI tools

+

For the quickstart we will install Drycc Workflow CLI.

+

Step 3: Deploy your first app

+

Last but not least, login and deploy your first application.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/quickstart/install-cli-tools/index.html b/quickstart/install-cli-tools/index.html new file mode 100644 index 000000000..6231762ec --- /dev/null +++ b/quickstart/install-cli-tools/index.html @@ -0,0 +1,887 @@ + + + + + + + + + + + + + + + + + + Install CLI Tools - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Drycc Workflow Client CLI

+

The Drycc command-line interface (CLI), lets you interact with Drycc Workflow. +Use the CLI to create and configure and manage applications.

+

Install the drycc client for Linux or Mac OS X with:

+
$ curl -sfL https://www.drycc.cc/install-cli.sh | bash -
+ + +
+

Important

+

Users in Chinese mainland can use the following methods to speed up installation:

+

$ curl -sfL https://www.drycc.cc/install-cli.sh | INSTALL_DRYCC_MIRROR=cn bash -

+
+

Others please visit: https://github.com/drycc/workflow-cli/releases

+

The installer places the drycc binary in your current directory, but you +should move it somewhere in your $PATH:

+
$ sudo ln -fs $PWD/drycc /usr/local/bin/drycc
+ + +

or:

+
$ sudo mv $PWD/drycc /usr/local/bin/drycc
+ + +

Check your work by running drycc version:

+
$ drycc version
+v1.1.0
+ + +
+

Note

+

Note that version numbers may vary as new releases become available

+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/quickstart/install-workflow/index.html b/quickstart/install-workflow/index.html new file mode 100644 index 000000000..46a337e3e --- /dev/null +++ b/quickstart/install-workflow/index.html @@ -0,0 +1,1242 @@ + + + + + + + + + + + + + + + + + + Install Workflow - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Install Workflow

+

If you have a pure host, it can be a cloud server, bare metal server, virtual machine, or even your laptop. Then this chapter is very suitable for you.

+

Operating Systems

+

Drycc is expected to work on most modern Linux systems. Some OSS have specific requirements:

+
    +
  • (Red Hat/CentOS) Enterprise Linux, they usually use RPM package management.
  • +
  • Ubuntu (Desktop/Server/Cloud) Linux, a very popular distribution.
  • +
  • Debian GNU Linux, a very pure distribution of opensource software.
  • +
+

If you want to add more Linux distribution support, please submit a issue on github or submit PR directly.

+

System Software

+

Some basic software needs to be installed before installing drycc workflow.

+

OS configuration

+

K8s requires a large number of ports. If you are not sure what they are, please close the local firewall or open these ports. +At the same time, because k8s you need system time, you need to ensure that the system time is correct.

+

Installing open-iscsi

+

The command used to install open-iscsi differs depending on the Linux distribution. +We recommend using Ubuntu as the guest OS image since it contains open-iscsi already. +You may need to edit the cluster security group to allow SSH access. +For SUSE and openSUSE, use this command:

+
$ zypper install open-iscsi
+ + +

For Debian and Ubuntu, use this command:

+
$ apt-get install open-iscsi
+ + +

For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command:

+
$ yum install iscsi-initiator-utils
+ + +

Installing NFSv4 client

+

The command used to install a NFSv4 client differs depending on the Linux distribution.

+

For Debian and Ubuntu, use this command:

+
$ apt-get install nfs-common
+ + +

For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command:

+
$ yum install nfs-utils
+ + +

Installing curl

+

For Debian and Ubuntu, use this command:

+
$ apt-get install curl
+ + +

For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command:

+
$ yum install curl
+ + +

Installing bc

+

For Debian and Ubuntu, use this command:

+
$ apt-get install bc
+ + +

For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command:

+
$ yum install bc
+ + +

Hardware

+

Hardware requirements scale based on the size of your deployments. Minimum recommendations are outlined here.

+
    +
  • RAM: 1G Minimum (we recommend at least 2GB)
  • +
  • CPU: 1 Minimum
  • +
+

This configuration only contains the minimum requirements that can meet the operation.

+

Disk

+

Drycc performance depends on the performance of the database. To ensure optimal speed, we recommend using an SSD when possible. Disk performance will vary on ARM devices utilizing an SD card or eMMC.

+

Domain Name

+

Drycc needs a root domain name under your full control and points this domain name to the server to be installed. +Suppose there is a wildcard domain pointing to the current server to install drycc, which is the name *.dryccdoman.com. +We need to set the PLATFORM_DOMAIN environment variables before installation.

+
$ export PLATFORM_DOMAIN=dryccdoman.co
+ + +

Of course, if it is a test environment, we can also use nip.io, an IP to domain name service. +For example, your host IP is 59.46.3.190, we will get the following domain name 59.46.3.190.nip.io

+
$ export PLATFORM_DOMAIN=59.46.3.190.nip.io
+ + +

Install

+

Before installation, please make sure whether your installation environment is a public network. +If it is an intranet environment and there is no public IP, you need to disable the automatic certificate.

+
$ export CERT_MANAGER_ENABLED=false
+ + +

Then you can use the installation script available at https://www.drycc.cc/install.sh to install drycc as a service on systemd and openrc based systems.

+
$ curl -sfL https://www.drycc.cc/install.sh | bash -
+ + +
+

Important

+

If you are in China, you need to use mirror acceleration:

+

$ curl -sfL https://www.drycc.cc/install.sh | INSTALL_DRYCC_MIRROR=cn bash -

+
+

Install Node

+

Node can be a simple agent or a server; Server has the function of agent. Multiple servers have high availability, but the number of servers should not +exceed 7 at most. There is no limit to the number of agents.

+
    +
  • First, check the cluster token of the master.
  • +
+
$ cat /var/lib/rancher/k3s/server/node-token
+K1078e7213ca32bdaabb44536f14b9ce7926bb201f41c3f3edd39975c16ff4901ea::server:33bde27f-ac49-4483-b6ac-f4eec2c6dbfa
+ + +

We assume that the IP address of the cluster master is 192.168.6.240, in that way.

+
    +
  • Then, Set the environment variable:
  • +
+
$ export K3S_URL=https://192.168.6.240:6443
+$ export K3S_TOKEN="K1078e7213ca32bdaabb44536f14b9ce7926bb201f41c3f3edd39975c16ff4901ea::server:33bde27f-ac49-4483-b6ac-f4eec2c6dbfa"
+ + +
+

Important

+

If you are in China, you need to use mirror acceleration:

+

$ export INSTALL_DRYCC_MIRROR=cn

+
+
    +
  • Join the cluster as server:
  • +
+
$ curl -sfL https://www.drycc.cc/install.sh | bash -s - install_k3s_server
+ + +
    +
  • Join the cluster as agent:
  • +
+
$ curl -sfL https://www.drycc.cc/install.sh | bash -s - install_k3s_agent
+ + +

Install Options

+

When using this method to install drycc, the following environment variables can be used to configure the installation:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ENVIRONMENT VARIABLEDESCRIPTION
PLATFORM_DOMAINRequired item, specify drycc's domain name
DRYCC_ADMIN_USERNAMERequired item, specify drycc's admin username
DRYCC_ADMIN_PASSWORDRequired item, specify drycc's admin password
CERT_MANAGER_ENABLEDWhether to use automatic certificate. It is true by default
CHANNELBy default, stable channel will be installed. You can also specify testing
CONTAINERD_FILEThe config.yaml file path used by containerd
KUBE_API_SERVER_ADDRESSSet with the IP address of the loadbalancer that was in front of kube-apiserver, The default is the IP address of the current node
KUBE_API_SERVER_PORTSet with the PORT of the loadbalancer that was in front of kube-apiserver, which is 6443 by default
METALLB_CONFIG_FILEThe metallb config file path, layer 2 network is used by default
INSTALL_DRYCC_MIRRORSpecify the accelerated mirror location. Currently, only cn is supported
BUILDER_REPLICASNumber of builder replicas to deploy
CONTROLLER_API_REPLICASNumber of controller api replicas to deploy
CONTROLLER_CELERY_REPLICASNumber of controller celery replicas to deploy
CONTROLLER_WEBHOOK_REPLICASNumber of controller webhook replicas to deploy
CONTROLLER_APP_RUNTIME_CLASSRuntimeClass is a feature for selecting the container runtime configuration.
CONTROLLER_APP_STORAGE_CLASSStorageClass allocated by drycc volumes; default storageClass is used by default
REDIS_REPLICASNumber of redis replicas to deploy
REDIS_PERSISTENCE_SIZEThe size of the persistence space allocated to redis, which is 5Gi by default
REDIS_PERSISTENCE_STORAGE_CLASSStorangeClass of redis; default storangeclass is used by default
STORAGE_CSI_STATEFULSET_REPLICASNumber of storage csi controller replicas to deploy
STORAGE_MAINNODE_TIPD_REPLICASNumber of storage mainode tipd replicas to deploy
STORAGE_MAINNODE_TIPD_PERSISTENCE_SIZEThe size of the persistence space allocated to mainnode tipd, which is 10Gi by default
STORAGE_MAINNODE_TIPD_PERSISTENCE_STORAGE_CLASSStorangeClass of mainnode tipd; default storangeclass is used by default
STORAGE_MAINNODE_WEED_REPLICASNumber of storage mainode weed replicas to deploy
STORAGE_MAINNODE_WEED_PERSISTENCE_SIZEThe size of the persistence space allocated to mainnode weed, which is 10Gi by default
STORAGE_MAINNODE_WEED_PERSISTENCE_STORAGE_CLASSStorangeClass of mainnode weed; default storangeclass is used by default
STORAGE_METANODE_TIKV_REPLICASNumber of storage metanode tikv replicas to deploy
STORAGE_METANODE_TIKV_PERSISTENCE_SIZEThe size of the persistence space allocated to metanode tikv, which is 10Gi by default
STORAGE_METANODE_TIKV_PERSISTENCE_STORAGE_CLASSStorangeClass of mainnode tikv; default storangeclass is used by default
STORAGE_METANODE_WEED_REPLICASNumber of storage metanode weed replicas to deploy
STORAGE_METANODE_WEED_PERSISTENCE_SIZEThe size of the persistence space allocated to metanode weed, which is 10Gi by default
STORAGE_METANODE_WEED_PERSISTENCE_STORAGE_CLASSStorangeClass of mainnode weed; default storangeclass is used by default
STORAGE_DATANODE_WEED_REPLICASNumber of storage datanode weed replicas to deploy
STORAGE_DATANODE_WEED_PERSISTENCE_SIZEThe size of the persistence space allocated to datanode weed, which is 20Gi by default
STORAGE_DATANODE_WEED_PERSISTENCE_STORAGE_CLASSStorangeClass of datanode weed; default storangeclass is used by default
MONITOR_GRAFANA_PERSISTENCE_SIZEThe size of the persistence space allocated to monitor.grafana, which is 5Gi by default
MONITOR_GRAFANA_PERSISTENCE_STORAGE_CLASSStorangeClass of monitor grafana; default storangeclass is used by default
LOGGER_REPLICASNumber of logger replicas to deploy
RABBITMQ_REPLICASNumber of rabbitmq replicas to deploy
RABBITMQ_PERSISTENCE_SIZEThe size of the persistence space allocated to rabbitmq, which is 5Gi by default
RABBITMQ_PERSISTENCE_STORAGE_CLASSStorangeClass of rabbitmq; default storangeclass is used by default
DATABASE_REPLICASNumber of database replicas to deploy
DATABASE_PERSISTENCE_SIZEThe size of the persistence space allocated to database, which is 5Gi by default
DATABASE_PERSISTENCE_STORAGE_CLASSStorangeClass of database; default storangeclass is used by default
TIMESERIES_REPLICASNumber of timeseries replicas to deploy
TIMESERIES_PERSISTENCE_SIZEThe size of the persistence space allocated to timeseries, which is 5Gi by default
TIMESERIES_PERSISTENCE_STORAGE_CLASSStorangeClass of timeseries; default storangeclass is used by default
PASSPORT_REPLICASNumber of passport replicas to deploy
REGISTRY_REPLICASNumber of registry replicas to deploy
HELMBROKER_REPLICASNumber of helmbroker api replicas to deploy
HELMBROKER_CELERY_REPLICASNumber of helmbroker celery replicas to deploy
HELMBROKER_PERSISTENCE_SIZEThe size of the persistence space allocated to helmbroker, which is 5Gi by default
HELMBROKER_PERSISTENCE_STORAGE_CLASSStorangeClass of helmbroker; default storangeclass is used by default
PROMETHEUS_SERVER_RETENTIONPrometheus data retention period (default if not specified is 15 days)
PROMETHEUS_SERVER_PERSISTENCE_SIZEThe size of the persistence space allocated to prometheus-server, which is 10Gi by default
PROMETHEUS_SERVER_PERSISTENCE_STORAGE_CLASSStorangeClass of prometheus-server; default storangeclass is used by default
K3S_DATA_DIRThe config of k3s data dir; If not set, the default path is used
ACME_SERVERACME Server url, default use letsencrypt
ACME_EAB_KEY_IDThe key ID of which your external account binding is indexed by the external account
ACME_EAB_KEY_SECRETThe key Secret of which your external account symmetric MAC key
+

Since the installation script will install k3s, other environment variables can refer to k3s installation environment variables.

+

Uninstall

+

If you installed drycc using an installation script, you can uninstall the entire drycc using this script.

+
$ curl -sfL https://www.drycc.cc/uninstall.sh | bash -
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference-guide/controller-api/v2.0/index.html b/reference-guide/controller-api/v2.0/index.html new file mode 100644 index 000000000..494aa971d --- /dev/null +++ b/reference-guide/controller-api/v2.0/index.html @@ -0,0 +1,2009 @@ + + + + + + + + + + + + + + + + + + Controller API v2.0 - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Controller API v2.0

+

This is the v2.0 REST API for the Controller.

+

What's New

+

New! format of POST /v2/apps/<app id>/run has changed.

+

Authentication

+

Register a New User

+

Example Request:

+
POST /v2/auth/register/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+
+{
+    "username": "test",
+    "password": "opensesame",
+    "email": "test@example.com"
+}
+ + +

Optional Parameters:

+
{
+    "first_name": "test",
+    "last_name": "testerson"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "id": 1,
+    "last_login": "2014-10-19T22:01:00.601Z",
+    "is_superuser": true,
+    "username": "test",
+    "first_name": "test",
+    "last_name": "testerson",
+    "email": "test@example.com",
+    "is_staff": true,
+    "is_active": true,
+    "date_joined": "2014-10-19T22:01:00.601Z",
+    "groups": [],
+    "user_permissions": []
+}
+ + +

Log in

+

Example Request:

+
POST /v2/auth/login/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+
+{"username": "test", "password": "opensesame"}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{"token": "abc123"}
+ + +

Cancel Account

+

Example Request:

+
DELETE /v2/auth/cancel/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Regenerate Token

+
+

note

+

This command could require administrative privileges

+
+

Example Request:

+
POST /v2/auth/tokens/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Optional Parameters:

+
{
+    "username" : "test"
+    "all" : "true"
+}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{"token": "abc123"}
+ + +

Change Password

+

Example Request:

+
POST /v2/auth/passwd/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{
+    "password": "foo",
+    "new_password": "bar"
+}
+ + +

Optional parameters:

+
{"username": "testuser"}
+ + +
+

note

+

Using the username parameter requires administrative privileges and makes the password parameter optional.

+
+

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Applications

+

List all Applications

+

Example Request:

+
GET /v2/apps HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "created": "2014-01-01T00:00:00UTC",
+            "id": "example-go",
+            "owner": "test",
+            "structure": {},
+            "updated": "2014-01-01T00:00:00UTC",
+            "url": "example-go.example.com",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+        }
+    ]
+}
+ + +

Create an Application

+

Example Request:

+
POST /v2/apps/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+ + +

Optional parameters:

+
{"id": "example-go"}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "id": "example-go",
+    "owner": "test",
+    "structure": {},
+    "updated": "2014-01-01T00:00:00UTC",
+    "url": "example-go.example.com",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Destroy an Application

+

Example Request:

+
DELETE /v2/apps/example-go/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

List Application Details

+

Example Request:

+
GET /v2/apps/example-go/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "id": "example-go",
+    "owner": "test",
+    "structure": {},
+    "updated": "2014-01-01T00:00:00UTC",
+    "url": "example-go.example.com",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Update Application Details

+

Example Request:

+
POST /v2/apps/example-go/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Optional parameters:

+
{
+  "owner": "test"
+}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 1.8.0
+Content-Type: application/json
+ + +

Retrieve Application Logs

+

Example Request:

+
GET /v2/apps/example-go/logs/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Optional URL Query Parameters:

+
?log_lines=
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: text/plain
+
+"16:51:14 drycc[api]: test created initial release\n"
+ + +

Run one-off Commands

+
POST /v2/apps/example-go/run/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"command": "echo hi"}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{"exit_code": 0, "output": "hi\n"}
+ + +

Certificates

+

List all Certificates

+

Example Request:

+
GET /v2/certs HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+  "count": 1,
+  "next": null,
+  "previous": null,
+  "results": [
+    {
+      "id": 22,
+      "owner": "test",
+      "san": [],
+      "domains": [],
+      "created": "2016-06-22T22:24:20Z",
+      "updated": "2016-06-22T22:24:20Z",
+      "name": "foo",
+      "common_name": "bar.com",
+      "fingerprint": "7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0",
+      "expires": "2017-01-14T23:57:57Z",
+      "starts": "2016-01-15T23:57:57Z",
+      "issuer": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc",
+      "subject": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc"
+    }
+  ]
+}
+ + +

Get Certificate Details

+

Example Request:

+
GET /v2/certs/foo HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+  "id": 22,
+  "owner": "test",
+  "san": [],
+  "domains": [],
+  "created": "2016-06-22T22:24:20Z",
+  "updated": "2016-06-22T22:24:20Z",
+  "name": "foo",
+  "common_name": "bar.com",
+  "fingerprint": "7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0",
+  "expires": "2017-01-14T23:57:57Z",
+  "starts": "2016-01-15T23:57:57Z",
+  "issuer": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc",
+  "subject": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc"
+}
+ + +

Create Certificate

+

Example Request:

+
POST /v2/certs/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{
+    "name": "foo"
+    "certificate": "-----BEGIN CERTIFICATE-----",
+    "key": "-----BEGIN RSA PRIVATE KEY-----"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+  "id": 22,
+  "owner": "test",
+  "san": [],
+  "domains": [],
+  "created": "2016-06-22T22:24:20Z",
+  "updated": "2016-06-22T22:24:20Z",
+  "name": "foo",
+  "common_name": "bar.com",
+  "fingerprint": "7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0",
+  "expires": "2017-01-14T23:57:57Z",
+  "starts": "2016-01-15T23:57:57Z",
+  "issuer": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc",
+  "subject": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc"
+}
+ + +

Destroy a Certificate

+

Example Request:

+
DELETE /v2/certs/foo HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Attach a Domain to a Certificate

+

Example Request:

+
POST /v2/certs/foo/domain/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{
+    "domain": "test.com"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Remove a Domain from a Certificate

+

Example Request:

+
DELETE /v2/certs/foo/domain/test.com/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Pods

+

List all Pods

+

Example Request:

+
GET /v2/apps/example-go/pods/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "results": [
+        {
+            "name": "go-v2-web-e7dej",
+            "release": "v2",
+            "started": "2014-01-01T00:00:00Z",
+            "state": "up",
+            "type": "web"
+        }
+    ]
+}
+ + +

List all Pods by Type

+

Example Request:

+
GET /v2/apps/example-go/pods/web/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "results": [
+        {
+            "name": "go-v2-web-e7dej",
+            "release": "v2",
+            "started": "2014-01-01T00:00:00Z",
+            "state": "up",
+            "type": "web"
+        }
+    ]
+}
+ + +

Restart All Pods

+

Example Request:

+
POST /v2/apps/example-go/pods/restart/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+[
+    {
+        "name": "go-v2-web-atots",
+        "release": "v2",
+        "started": "2016-04-11T21:07:54Z",
+        "state": "up",
+        "type": "web"
+    }
+]
+ + +

Restart Pods by Type

+

Example Request:

+
POST /v2/apps/example-go/pods/web/restart/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+[
+    {
+        "name": "go-v2-web-atots",
+        "release": "v2",
+        "started": "2016-04-11T21:07:54Z",
+        "state": "up",
+        "type": "web"
+    }
+]
+ + +

Restart Pods by Type and Name

+

Example Request:

+
POST /v2/apps/example-go/pods/go-v2-web-atots/restart/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+[
+    {
+        "name": "go-v2-web-atots",
+        "release": "v2",
+        "started": "2016-04-11T21:07:54Z",
+        "state": "up",
+        "type": "web"
+    }
+]
+ + +

Scale Pods

+

Example Request:

+
POST /v2/apps/example-go/scale/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"web": 3}
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Configuration

+

List Application Configuration

+

Example Request:

+
GET /v2/apps/example-go/config/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "owner": "test",
+    "app": "example-go",
+    "values": {
+      "PLATFORM": "drycc"
+    },
+    "memory": {},
+    "cpu": {},
+    "tags": {},
+    "healthcheck": {},
+    "created": "2014-01-01T00:00:00UTC",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Create new Config

+

Example Request:

+
POST /v2/apps/example-go/config/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"values": {"HELLO": "world", "PLATFORM": "drycc"}}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+X-Drycc-Release: 3
+
+{
+    "owner": "test",
+    "app": "example-go",
+    "values": {
+        "DRYCC_APP": "example-go",
+        "DRYCC_RELEASE": "v3",
+        "HELLO": "world",
+        "PLATFORM": "drycc"
+
+    },
+    "memory": {},
+    "cpu": {},
+    "tags": {},
+    "healthcheck": {},
+    "created": "2014-01-01T00:00:00UTC",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Unset Config Variable

+

Example Request:

+
POST /v2/apps/example-go/config/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"values": {"HELLO": null}}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+X-Drycc-Release: 4
+
+{
+    "owner": "test",
+    "app": "example-go",
+    "values": {
+        "DRYCC_APP": "example-go",
+        "DRYCC_RELEASE": "v4",
+        "PLATFORM": "drycc"
+   },
+    "memory": {},
+    "cpu": {},
+    "tags": {},
+    "healthcheck": {},
+    "created": "2014-01-01T00:00:00UTC",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Domains

+

List Application Domains

+

Example Request:

+
GET /v2/apps/example-go/domains/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "app": "example-go",
+            "created": "2014-01-01T00:00:00UTC",
+            "domain": "example.example.com",
+            "owner": "test",
+            "updated": "2014-01-01T00:00:00UTC"
+        }
+    ]
+}
+ + +

Add Domain

+

Example Request:

+
POST /v2/apps/example-go/domains/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{'domain': 'example.example.com'}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "app": "example-go",
+    "created": "2014-01-01T00:00:00UTC",
+    "domain": "example.example.com",
+    "owner": "test",
+    "updated": "2014-01-01T00:00:00UTC"
+}
+ + +

Remove Domain

+

Example Request:

+
DELETE /v2/apps/example-go/domains/example.example.com HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Builds

+

List Application Builds

+

Example Request:

+
GET /v2/apps/example-go/builds/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "app": "example-go",
+            "created": "2014-01-01T00:00:00UTC",
+            "dockerfile": "FROM drycc/slugrunner RUN mkdir -p /app WORKDIR /app ENTRYPOINT [\"/runner/init\"] ADD slug.tgz /app ENV GIT_SHA 060da68f654e75fac06dbedd1995d5f8ad9084db",
+            "image": "example-go",
+            "owner": "test",
+            "procfile": {
+                "web": "example-go"
+            },
+            "sha": "060da68f",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+        }
+    ]
+}
+ + +

Create Application Build

+

Example Request:

+
POST /v2/apps/example-go/builds/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"image": "drycc/example-go:latest"}
+ + +

Optional Parameters:

+
{
+    "procfile": {
+      "web": "./cmd"
+    }
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+X-Drycc-Release: 4
+
+{
+    "app": "example-go",
+    "created": "2014-01-01T00:00:00UTC",
+    "dockerfile": "",
+    "image": "drycc/example-go:latest",
+    "owner": "test",
+    "procfile": {},
+    "sha": "",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Releases

+

List Application Releases

+

Example Request:

+
GET /v2/apps/example-go/releases/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 3,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "app": "example-go",
+            "build": "202d8e4b-600e-4425-a85c-ffc7ea607f61",
+            "config": "ed637ceb-5d32-44bd-9406-d326a777a513",
+            "created": "2014-01-01T00:00:00UTC",
+            "owner": "test",
+            "summary": "test changed nothing",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+            "version": 3
+        },
+        {
+            "app": "example-go",
+            "build": "202d8e4b-600e-4425-a85c-ffc7ea607f61",
+            "config": "95bd6dea-1685-4f78-a03d-fd7270b058d1",
+            "created": "2014-01-01T00:00:00UTC",
+            "owner": "test",
+            "summary": "test deployed 060da68",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+            "version": 2
+        },
+        {
+            "app": "example-go",
+            "build": null,
+            "config": "95bd6dea-1685-4f78-a03d-fd7270b058d1",
+            "created": "2014-01-01T00:00:00UTC",
+            "owner": "test",
+            "summary": "test created initial release",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+            "version": 1
+        }
+    ]
+}
+ + +

List Release Details

+

Example Request:

+
GET /v2/apps/example-go/releases/v2/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "app": "example-go",
+    "build": null,
+    "config": "95bd6dea-1685-4f78-a03d-fd7270b058d1",
+    "created": "2014-01-01T00:00:00UTC",
+    "owner": "test",
+    "summary": "test created initial release",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+    "version": 1
+}
+ + +

Rollback Release

+

Example Request:

+
POST /v2/apps/example-go/releases/rollback/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"version": 1}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{"version": 5}
+ + +

Keys

+

List Keys

+

Example Request:

+
GET /v2/keys/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "created": "2014-01-01T00:00:00UTC",
+            "id": "test@example.com",
+            "owner": "test",
+            "public": "ssh-rsa <...>",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+        }
+    ]
+}
+ + +

Add Key to User

+

Example Request:

+
POST /v2/keys/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{
+    "id": "example",
+    "public": "ssh-rsa <...>"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "id": "example",
+    "owner": "example",
+    "public": "ssh-rsa <...>",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Remove Key from User

+

Example Request:

+
DELETE /v2/keys/example HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Permissions

+

List Application Permissions

+
+

note

+

This does not include the app owner.

+
+

Example Request:

+
GET /v2/apps/example-go/perms/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "users": [
+        "test",
+        "foo"
+    ]
+}
+ + +

Create Application Permission

+

Example Request:

+
POST /v2/apps/example-go/perms/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{"username": "example"}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Remove Application Permission

+

Example Request:

+
DELETE /v2/apps/example-go/perms/example HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

List Administrators

+

Example Request:

+
GET /v2/admin/perms/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 2,
+    "next": null
+    "previous": null,
+    "results": [
+        {
+            "username": "test",
+            "is_superuser": true
+        },
+        {
+            "username": "foo",
+            "is_superuser": true
+        }
+    ]
+}
+ + +

Grant User Administrative Privileges

+
+

note

+

This command requires administrative privileges

+
+

Example Request:

+
POST /v2/admin/perms HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{"username": "example"}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Remove User's Administrative Privileges

+
+

note

+

This command requires administrative privileges

+
+

Example Request:

+
DELETE /v2/admin/perms/example HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Users

+

List all users

+
+

note

+

This command requires administrative privileges

+
+

Example Request:

+
GET /v2/users HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.0
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "id": 1,
+            "last_login": "2014-10-19T22:01:00.601Z",
+            "is_superuser": true,
+            "username": "test",
+            "first_name": "test",
+            "last_name": "testerson",
+            "email": "test@example.com",
+            "is_staff": true,
+            "is_active": true,
+            "date_joined": "2014-10-19T22:01:00.601Z",
+            "groups": [],
+            "user_permissions": []
+        }
+    ]
+}
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference-guide/controller-api/v2.1/index.html b/reference-guide/controller-api/v2.1/index.html new file mode 100644 index 000000000..35e2aba79 --- /dev/null +++ b/reference-guide/controller-api/v2.1/index.html @@ -0,0 +1,2008 @@ + + + + + + + + + + + + + + + + + + Controller API v2.1 - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Controller API v2.1

+

This is the v2.1 REST API for the Controller.

+

What's New

+

New! healthcheck field in configuration, deprecates the HEALTHCHECK_* environment variables.

+

New! Unsetting a configuration variable that does not exist will return a 422.

+

New! Creating an identical sequential release returns a 409 rather than create a no-op release.

+

Authentication

+

Register a New User

+

Example Request:

+
POST /v2/auth/register/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+
+{
+    "username": "test",
+    "password": "opensesame",
+    "email": "test@example.com"
+}
+ + +

Optional Parameters:

+
{
+    "first_name": "test",
+    "last_name": "testerson"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "id": 1,
+    "last_login": "2014-10-19T22:01:00.601Z",
+    "is_superuser": true,
+    "username": "test",
+    "first_name": "test",
+    "last_name": "testerson",
+    "email": "test@example.com",
+    "is_staff": true,
+    "is_active": true,
+    "date_joined": "2014-10-19T22:01:00.601Z",
+    "groups": [],
+    "user_permissions": []
+}
+ + +

Log in

+

Example Request:

+
POST /v2/auth/login/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+
+{"username": "test", "password": "opensesame"}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{"token": "abc123"}
+ + +

Cancel Account

+

Example Request:

+
DELETE /v2/auth/cancel/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Regenerate Token

+
+

note

+

This command could require administrative privileges

+
+

Example Request:

+
POST /v2/auth/tokens/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Optional Parameters:

+
{
+    "username" : "test"
+    "all" : "true"
+}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{"token": "abc123"}
+ + +

Change Password

+

Example Request:

+
POST /v2/auth/passwd/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{
+    "password": "foo",
+    "new_password": "bar"
+}
+ + +

Optional parameters:

+
{"username": "testuser"}
+ + +
+

note

+

Using the username parameter requires administrative privileges and makes the password parameter optional.

+
+

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Applications

+

List all Applications

+

Example Request:

+
GET /v2/apps HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "created": "2014-01-01T00:00:00UTC",
+            "id": "example-go",
+            "owner": "test",
+            "structure": {},
+            "updated": "2014-01-01T00:00:00UTC",
+            "url": "example-go.example.com",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+        }
+    ]
+}
+ + +

Create an Application

+

Example Request:

+
POST /v2/apps/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+ + +

Optional parameters:

+
{"id": "example-go"}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "id": "example-go",
+    "owner": "test",
+    "structure": {},
+    "updated": "2014-01-01T00:00:00UTC",
+    "url": "example-go.example.com",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Destroy an Application

+

Example Request:

+
DELETE /v2/apps/example-go/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

List Application Details

+

Example Request:

+
GET /v2/apps/example-go/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "id": "example-go",
+    "owner": "test",
+    "structure": {},
+    "updated": "2014-01-01T00:00:00UTC",
+    "url": "example-go.example.com",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Update Application Details

+

Example Request:

+
POST /v2/apps/example-go/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Optional parameters:

+
{
+  "owner": "test"
+}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 1.8.0
+Content-Type: application/json
+ + +

Retrieve Application Logs

+

Example Request:

+
GET /v2/apps/example-go/logs/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Optional URL Query Parameters:

+
?log_lines=
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: text/plain
+
+"16:51:14 drycc[api]: test created initial release\n"
+ + +

Run one-off Commands

+
POST /v2/apps/example-go/run/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"command": "echo hi"}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{"exit_code": 0, "output": "hi\n"}
+ + +

Certificates

+

List all Certificates

+

Example Request:

+
GET /v2/certs HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+  "count": 1,
+  "next": null,
+  "previous": null,
+  "results": [
+    {
+      "id": 22,
+      "owner": "test",
+      "san": [],
+      "domains": [],
+      "created": "2016-06-22T22:24:20Z",
+      "updated": "2016-06-22T22:24:20Z",
+      "name": "foo",
+      "common_name": "bar.com",
+      "fingerprint": "7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0",
+      "expires": "2017-01-14T23:57:57Z",
+      "starts": "2016-01-15T23:57:57Z",
+      "issuer": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc",
+      "subject": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc"
+    }
+  ]
+}
+ + +

Get Certificate Details

+

Example Request:

+
GET /v2/certs/foo HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+  "id": 22,
+  "owner": "test",
+  "san": [],
+  "domains": [],
+  "created": "2016-06-22T22:24:20Z",
+  "updated": "2016-06-22T22:24:20Z",
+  "name": "foo",
+  "common_name": "bar.com",
+  "fingerprint": "7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0",
+  "expires": "2017-01-14T23:57:57Z",
+  "starts": "2016-01-15T23:57:57Z",
+  "issuer": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc",
+  "subject": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc"
+}
+ + +

Create Certificate

+

Example Request:

+
POST /v2/certs/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{
+    "name": "foo"
+    "certificate": "-----BEGIN CERTIFICATE-----",
+    "key": "-----BEGIN RSA PRIVATE KEY-----"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+  "id": 22,
+  "owner": "test",
+  "san": [],
+  "domains": [],
+  "created": "2016-06-22T22:24:20Z",
+  "updated": "2016-06-22T22:24:20Z",
+  "name": "foo",
+  "common_name": "bar.com",
+  "fingerprint": "7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0",
+  "expires": "2017-01-14T23:57:57Z",
+  "starts": "2016-01-15T23:57:57Z",
+  "issuer": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc",
+  "subject": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc"
+}
+ + +

Destroy a Certificate

+

Example Request:

+
DELETE /v2/certs/foo HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Attach a Domain to a Certificate

+

Example Request:

+
POST /v2/certs/foo/domain/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{
+    "domain": "test.com"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Remove a Domain from a Certificate

+

Example Request:

+
DELETE /v2/certs/foo/domain/test.com/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Pods

+

List all Pods

+

Example Request:

+
GET /v2/apps/example-go/pods/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "results": [
+        {
+            "name": "go-v2-web-e7dej",
+            "release": "v2",
+            "started": "2014-01-01T00:00:00Z",
+            "state": "up",
+            "type": "web"
+        }
+    ]
+}
+ + +

List all Pods by Type

+

Example Request:

+
GET /v2/apps/example-go/pods/web/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "results": [
+        {
+            "name": "go-v2-web-e7dej",
+            "release": "v2",
+            "started": "2014-01-01T00:00:00Z",
+            "state": "up",
+            "type": "web"
+        }
+    ]
+}
+ + +

Restart All Pods

+

Example Request:

+
POST /v2/apps/example-go/pods/restart/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+[
+    {
+        "name": "go-v2-web-atots",
+        "release": "v2",
+        "started": "2016-04-11T21:07:54Z",
+        "state": "up",
+        "type": "web"
+    }
+]
+ + +

Restart Pods by Type

+

Example Request:

+
POST /v2/apps/example-go/pods/web/restart/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+[
+    {
+        "name": "go-v2-web-atots",
+        "release": "v2",
+        "started": "2016-04-11T21:07:54Z",
+        "state": "up",
+        "type": "web"
+    }
+]
+ + +

Restart Pods by Type and Name

+

Example Request:

+
POST /v2/apps/example-go/pods/go-v2-web-atots/restart/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+[
+    {
+        "name": "go-v2-web-atots",
+        "release": "v2",
+        "started": "2016-04-11T21:07:54Z",
+        "state": "up",
+        "type": "web"
+    }
+]
+ + +

Scale Pods

+

Example Request:

+
POST /v2/apps/example-go/scale/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"web": 3}
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Configuration

+

List Application Configuration

+

Example Request:

+
GET /v2/apps/example-go/config/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "owner": "test",
+    "app": "example-go",
+    "values": {
+      "PLATFORM": "drycc"
+    },
+    "memory": {},
+    "cpu": {},
+    "tags": {},
+    "healthcheck": {},
+    "created": "2014-01-01T00:00:00UTC",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Create new Config

+

Example Request:

+
POST /v2/apps/example-go/config/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"values": {"HELLO": "world", "PLATFORM": "drycc"}}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "owner": "test",
+    "app": "example-go",
+    "values": {
+        "DRYCC_APP": "example-go",
+        "DRYCC_RELEASE": "v3",
+        "HELLO": "world",
+        "PLATFORM": "drycc"
+
+    },
+    "memory": {},
+    "cpu": {},
+    "tags": {},
+    "healthcheck": {},
+    "created": "2014-01-01T00:00:00UTC",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Unset Config Variable

+

Example Request:

+
POST /v2/apps/example-go/config/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"values": {"HELLO": null}}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "owner": "test",
+    "app": "example-go",
+    "values": {
+        "DRYCC_APP": "example-go",
+        "DRYCC_RELEASE": "v4",
+        "PLATFORM": "drycc"
+   },
+    "memory": {},
+    "cpu": {},
+    "tags": {},
+    "healthcheck": {},
+    "created": "2014-01-01T00:00:00UTC",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Domains

+

List Application Domains

+

Example Request:

+
GET /v2/apps/example-go/domains/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "app": "example-go",
+            "created": "2014-01-01T00:00:00UTC",
+            "domain": "example.example.com",
+            "owner": "test",
+            "updated": "2014-01-01T00:00:00UTC"
+        }
+    ]
+}
+ + +

Add Domain

+

Example Request:

+
POST /v2/apps/example-go/domains/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{'domain': 'example.example.com'}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "app": "example-go",
+    "created": "2014-01-01T00:00:00UTC",
+    "domain": "example.example.com",
+    "owner": "test",
+    "updated": "2014-01-01T00:00:00UTC"
+}
+ + +

Remove Domain

+

Example Request:

+
DELETE /v2/apps/example-go/domains/example.example.com HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Builds

+

List Application Builds

+

Example Request:

+
GET /v2/apps/example-go/builds/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "app": "example-go",
+            "created": "2014-01-01T00:00:00UTC",
+            "dockerfile": "FROM drycc/slugrunner RUN mkdir -p /app WORKDIR /app ENTRYPOINT [\"/runner/init\"] ADD slug.tgz /app ENV GIT_SHA 060da68f654e75fac06dbedd1995d5f8ad9084db",
+            "image": "example-go",
+            "owner": "test",
+            "procfile": {
+                "web": "example-go"
+            },
+            "sha": "060da68f",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+        }
+    ]
+}
+ + +

Create Application Build

+

Example Request:

+
POST /v2/apps/example-go/builds/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"image": "drycc/example-go:latest"}
+ + +

Optional Parameters:

+
{
+    "procfile": {
+      "web": "./cmd"
+    }
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "app": "example-go",
+    "created": "2014-01-01T00:00:00UTC",
+    "dockerfile": "",
+    "image": "drycc/example-go:latest",
+    "owner": "test",
+    "procfile": {},
+    "sha": "",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Releases

+

List Application Releases

+

Example Request:

+
GET /v2/apps/example-go/releases/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 3,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "app": "example-go",
+            "build": "202d8e4b-600e-4425-a85c-ffc7ea607f61",
+            "config": "ed637ceb-5d32-44bd-9406-d326a777a513",
+            "created": "2014-01-01T00:00:00UTC",
+            "owner": "test",
+            "summary": "test changed nothing",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+            "version": 3
+        },
+        {
+            "app": "example-go",
+            "build": "202d8e4b-600e-4425-a85c-ffc7ea607f61",
+            "config": "95bd6dea-1685-4f78-a03d-fd7270b058d1",
+            "created": "2014-01-01T00:00:00UTC",
+            "owner": "test",
+            "summary": "test deployed 060da68",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+            "version": 2
+        },
+        {
+            "app": "example-go",
+            "build": null,
+            "config": "95bd6dea-1685-4f78-a03d-fd7270b058d1",
+            "created": "2014-01-01T00:00:00UTC",
+            "owner": "test",
+            "summary": "test created initial release",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+            "version": 1
+        }
+    ]
+}
+ + +

List Release Details

+

Example Request:

+
GET /v2/apps/example-go/releases/v2/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "app": "example-go",
+    "build": null,
+    "config": "95bd6dea-1685-4f78-a03d-fd7270b058d1",
+    "created": "2014-01-01T00:00:00UTC",
+    "owner": "test",
+    "summary": "test created initial release",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+    "version": 1
+}
+ + +

Rollback Release

+

Example Request:

+
POST /v2/apps/example-go/releases/rollback/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"version": 1}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{"version": 5}
+ + +

Keys

+

List Keys

+

Example Request:

+
GET /v2/keys/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "created": "2014-01-01T00:00:00UTC",
+            "id": "test@example.com",
+            "owner": "test",
+            "public": "ssh-rsa <...>",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+        }
+    ]
+}
+ + +

Add Key to User

+

Example Request:

+
POST /v2/keys/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{
+    "id": "example",
+    "public": "ssh-rsa <...>"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "id": "example",
+    "owner": "example",
+    "public": "ssh-rsa <...>",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Remove Key from User

+

Example Request:

+
DELETE /v2/keys/example HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Permissions

+

List Application Permissions

+
+

note

+

This does not include the app owner.

+
+

Example Request:

+
GET /v2/apps/example-go/perms/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "users": [
+        "test",
+        "foo"
+    ]
+}
+ + +

Create Application Permission

+

Example Request:

+
POST /v2/apps/example-go/perms/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{"username": "example"}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Remove Application Permission

+

Example Request:

+
DELETE /v2/apps/example-go/perms/example HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

List Administrators

+

Example Request:

+
GET /v2/admin/perms/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 2,
+    "next": null
+    "previous": null,
+    "results": [
+        {
+            "username": "test",
+            "is_superuser": true
+        },
+        {
+            "username": "foo",
+            "is_superuser": true
+        }
+    ]
+}
+ + +

Grant User Administrative Privileges

+
+

note

+

This command requires administrative privileges

+
+

Example Request:

+
POST /v2/admin/perms HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{"username": "example"}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Remove User's Administrative Privileges

+
+

note

+

This command requires administrative privileges

+
+

Example Request:

+
DELETE /v2/admin/perms/example HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+ + +

Users

+

List all users

+
+

note

+

This command requires administrative privileges

+
+

Example Request:

+
GET /v2/users HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.1
+DRYCC_PLATFORM_VERSION: 2.1.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "id": 1,
+            "last_login": "2014-10-19T22:01:00.601Z",
+            "is_superuser": true,
+            "username": "test",
+            "first_name": "test",
+            "last_name": "testerson",
+            "email": "test@example.com",
+            "is_staff": true,
+            "is_active": true,
+            "date_joined": "2014-10-19T22:01:00.601Z",
+            "groups": [],
+            "user_permissions": []
+        }
+    ]
+}
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference-guide/controller-api/v2.2/index.html b/reference-guide/controller-api/v2.2/index.html new file mode 100644 index 000000000..cdf058795 --- /dev/null +++ b/reference-guide/controller-api/v2.2/index.html @@ -0,0 +1,2035 @@ + + + + + + + + + + + + + + + + + + Controller API v2.2 - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Controller API v2.2

+

This is the v2.2 REST API for the Controller.

+

What's New

+

New! /v2/auth/whoami endpoint

+

Authentication

+

Register a New User

+

Example Request:

+
POST /v2/auth/register/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+
+{
+    "username": "test",
+    "password": "opensesame",
+    "email": "test@example.com"
+}
+ + +

Optional Parameters:

+
{
+    "first_name": "test",
+    "last_name": "testerson"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "id": 1,
+    "last_login": "2014-10-19T22:01:00.601Z",
+    "is_superuser": true,
+    "username": "test",
+    "first_name": "test",
+    "last_name": "testerson",
+    "email": "test@example.com",
+    "is_staff": true,
+    "is_active": true,
+    "date_joined": "2014-10-19T22:01:00.601Z",
+    "groups": [],
+    "user_permissions": []
+}
+ + +

Log in

+

Example Request:

+
POST /v2/auth/login/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+
+{"username": "test", "password": "opensesame"}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{"token": "abc123"}
+ + +

Cancel Account

+

Example Request:

+
DELETE /v2/auth/cancel/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

Who Am I

+

Example Request:

+
GET /v2/auth/whoami/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "id": 1,
+    "last_login": "2014-10-19T22:01:00.601Z",
+    "is_superuser": true,
+    "username": "test",
+    "first_name": "test",
+    "last_name": "testerson",
+    "email": "test@example.com",
+    "is_staff": true,
+    "is_active": true,
+    "date_joined": "2014-10-19T22:01:00.601Z",
+    "groups": [],
+    "user_permissions": []
+}
+ + +

Regenerate Token

+
+

note

+

This command could require administrative privileges

+
+

Example Request:

+
POST /v2/auth/tokens/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Optional Parameters:

+
{
+    "username" : "test"
+    "all" : "true"
+}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{"token": "abc123"}
+ + +

Change Password

+

Example Request:

+
POST /v2/auth/passwd/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{
+    "password": "foo",
+    "new_password": "bar"
+}
+ + +

Optional parameters:

+
{"username": "testuser"}
+ + +
+

note

+

Using the username parameter requires administrative privileges and makes the password parameter optional.

+
+

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

Applications

+

List all Applications

+

Example Request:

+
GET /v2/apps HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "created": "2014-01-01T00:00:00UTC",
+            "id": "example-go",
+            "owner": "test",
+            "structure": {},
+            "updated": "2014-01-01T00:00:00UTC",
+            "url": "example-go.example.com",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+        }
+    ]
+}
+ + +

Create an Application

+

Example Request:

+
POST /v2/apps/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+ + +

Optional parameters:

+
{"id": "example-go"}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "id": "example-go",
+    "owner": "test",
+    "structure": {},
+    "updated": "2014-01-01T00:00:00UTC",
+    "url": "example-go.example.com",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Destroy an Application

+

Example Request:

+
DELETE /v2/apps/example-go/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

List Application Details

+

Example Request:

+
GET /v2/apps/example-go/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "id": "example-go",
+    "owner": "test",
+    "structure": {},
+    "updated": "2014-01-01T00:00:00UTC",
+    "url": "example-go.example.com",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Update Application Details

+

Example Request:

+
POST /v2/apps/example-go/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Optional parameters:

+
{
+  "owner": "test"
+}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 1.8.0
+Content-Type: application/json
+ + +

Retrieve Application Logs

+

Example Request:

+
GET /v2/apps/example-go/logs/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Optional URL Query Parameters:

+
?log_lines=
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: text/plain
+
+"16:51:14 drycc[api]: test created initial release\n"
+ + +

Run one-off Commands

+
POST /v2/apps/example-go/run/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"command": "echo hi"}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{"exit_code": 0, "output": "hi\n"}
+ + +

Certificates

+

List all Certificates

+

Example Request:

+
GET /v2/certs HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+  "count": 1,
+  "next": null,
+  "previous": null,
+  "results": [
+    {
+      "id": 22,
+      "owner": "test",
+      "san": [],
+      "domains": [],
+      "created": "2016-06-22T22:24:20Z",
+      "updated": "2016-06-22T22:24:20Z",
+      "name": "foo",
+      "common_name": "bar.com",
+      "fingerprint": "7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0",
+      "expires": "2017-01-14T23:57:57Z",
+      "starts": "2016-01-15T23:57:57Z",
+      "issuer": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc",
+      "subject": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc"
+    }
+  ]
+}
+ + +

Get Certificate Details

+

Example Request:

+
GET /v2/certs/foo HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+  "id": 22,
+  "owner": "test",
+  "san": [],
+  "domains": [],
+  "created": "2016-06-22T22:24:20Z",
+  "updated": "2016-06-22T22:24:20Z",
+  "name": "foo",
+  "common_name": "bar.com",
+  "fingerprint": "7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0",
+  "expires": "2017-01-14T23:57:57Z",
+  "starts": "2016-01-15T23:57:57Z",
+  "issuer": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc",
+  "subject": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc"
+}
+ + +

Create Certificate

+

Example Request:

+
POST /v2/certs/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{
+    "name": "foo"
+    "certificate": "-----BEGIN CERTIFICATE-----",
+    "key": "-----BEGIN RSA PRIVATE KEY-----"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+  "id": 22,
+  "owner": "test",
+  "san": [],
+  "domains": [],
+  "created": "2016-06-22T22:24:20Z",
+  "updated": "2016-06-22T22:24:20Z",
+  "name": "foo",
+  "common_name": "bar.com",
+  "fingerprint": "7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0",
+  "expires": "2017-01-14T23:57:57Z",
+  "starts": "2016-01-15T23:57:57Z",
+  "issuer": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc",
+  "subject": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc"
+}
+ + +

Destroy a Certificate

+

Example Request:

+
DELETE /v2/certs/foo HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

Attach a Domain to a Certificate

+

Example Request:

+
POST /v2/certs/foo/domain/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{
+    "domain": "test.com"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

Remove a Domain from a Certificate

+

Example Request:

+
DELETE /v2/certs/foo/domain/test.com/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

Pods

+

List all Pods

+

Example Request:

+
GET /v2/apps/example-go/pods/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "results": [
+        {
+            "name": "go-v2-web-e7dej",
+            "release": "v2",
+            "started": "2014-01-01T00:00:00Z",
+            "state": "up",
+            "type": "web"
+        }
+    ]
+}
+ + +

List all Pods by Type

+

Example Request:

+
GET /v2/apps/example-go/pods/web/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "results": [
+        {
+            "name": "go-v2-web-e7dej",
+            "release": "v2",
+            "started": "2014-01-01T00:00:00Z",
+            "state": "up",
+            "type": "web"
+        }
+    ]
+}
+ + +

Restart All Pods

+

Example Request:

+
POST /v2/apps/example-go/pods/restart/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+[
+    {
+        "name": "go-v2-web-atots",
+        "release": "v2",
+        "started": "2016-04-11T21:07:54Z",
+        "state": "up",
+        "type": "web"
+    }
+]
+ + +

Restart Pods by Type

+

Example Request:

+
POST /v2/apps/example-go/pods/web/restart/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+[
+    {
+        "name": "go-v2-web-atots",
+        "release": "v2",
+        "started": "2016-04-11T21:07:54Z",
+        "state": "up",
+        "type": "web"
+    }
+]
+ + +

Restart Pods by Type and Name

+

Example Request:

+
POST /v2/apps/example-go/pods/go-v2-web-atots/restart/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+[
+    {
+        "name": "go-v2-web-atots",
+        "release": "v2",
+        "started": "2016-04-11T21:07:54Z",
+        "state": "up",
+        "type": "web"
+    }
+]
+ + +

Scale Pods

+

Example Request:

+
POST /v2/apps/example-go/scale/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"web": 3}
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

Configuration

+

List Application Configuration

+

Example Request:

+
GET /v2/apps/example-go/config/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "owner": "test",
+    "app": "example-go",
+    "values": {
+      "PLATFORM": "drycc"
+    },
+    "memory": {},
+    "cpu": {},
+    "tags": {},
+    "healthcheck": {},
+    "created": "2014-01-01T00:00:00UTC",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Create new Config

+

Example Request:

+
POST /v2/apps/example-go/config/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"values": {"HELLO": "world", "PLATFORM": "drycc"}}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "owner": "test",
+    "app": "example-go",
+    "values": {
+        "DRYCC_APP": "example-go",
+        "DRYCC_RELEASE": "v3",
+        "HELLO": "world",
+        "PLATFORM": "drycc"
+
+    },
+    "memory": {},
+    "cpu": {},
+    "tags": {},
+    "healthcheck": {},
+    "created": "2014-01-01T00:00:00UTC",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Unset Config Variable

+

Example Request:

+
POST /v2/apps/example-go/config/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"values": {"HELLO": null}}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "owner": "test",
+    "app": "example-go",
+    "values": {
+        "DRYCC_APP": "example-go",
+        "DRYCC_RELEASE": "v4",
+        "PLATFORM": "drycc"
+   },
+    "memory": {},
+    "cpu": {},
+    "tags": {},
+    "healthcheck": {},
+    "created": "2014-01-01T00:00:00UTC",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Domains

+

List Application Domains

+

Example Request:

+
GET /v2/apps/example-go/domains/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "app": "example-go",
+            "created": "2014-01-01T00:00:00UTC",
+            "domain": "example.example.com",
+            "owner": "test",
+            "updated": "2014-01-01T00:00:00UTC"
+        }
+    ]
+}
+ + +

Add Domain

+

Example Request:

+
POST /v2/apps/example-go/domains/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{'domain': 'example.example.com'}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "app": "example-go",
+    "created": "2014-01-01T00:00:00UTC",
+    "domain": "example.example.com",
+    "owner": "test",
+    "updated": "2014-01-01T00:00:00UTC"
+}
+ + +

Remove Domain

+

Example Request:

+
DELETE /v2/apps/example-go/domains/example.example.com HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

Builds

+

List Application Builds

+

Example Request:

+
GET /v2/apps/example-go/builds/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "app": "example-go",
+            "created": "2014-01-01T00:00:00UTC",
+            "dockerfile": "FROM drycc/slugrunner RUN mkdir -p /app WORKDIR /app ENTRYPOINT [\"/runner/init\"] ADD slug.tgz /app ENV GIT_SHA 060da68f654e75fac06dbedd1995d5f8ad9084db",
+            "image": "example-go",
+            "owner": "test",
+            "procfile": {
+                "web": "example-go"
+            },
+            "sha": "060da68f",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+        }
+    ]
+}
+ + +

Create Application Build

+

Example Request:

+
POST /v2/apps/example-go/builds/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"image": "drycc/example-go:latest"}
+ + +

Optional Parameters:

+
{
+    "procfile": {
+      "web": "./cmd"
+    }
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "app": "example-go",
+    "created": "2014-01-01T00:00:00UTC",
+    "dockerfile": "",
+    "image": "drycc/example-go:latest",
+    "owner": "test",
+    "procfile": {},
+    "sha": "",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Releases

+

List Application Releases

+

Example Request:

+
GET /v2/apps/example-go/releases/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "count": 3,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "app": "example-go",
+            "build": "202d8e4b-600e-4425-a85c-ffc7ea607f61",
+            "config": "ed637ceb-5d32-44bd-9406-d326a777a513",
+            "created": "2014-01-01T00:00:00UTC",
+            "owner": "test",
+            "summary": "test changed nothing",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+            "version": 3
+        },
+        {
+            "app": "example-go",
+            "build": "202d8e4b-600e-4425-a85c-ffc7ea607f61",
+            "config": "95bd6dea-1685-4f78-a03d-fd7270b058d1",
+            "created": "2014-01-01T00:00:00UTC",
+            "owner": "test",
+            "summary": "test deployed 060da68",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+            "version": 2
+        },
+        {
+            "app": "example-go",
+            "build": null,
+            "config": "95bd6dea-1685-4f78-a03d-fd7270b058d1",
+            "created": "2014-01-01T00:00:00UTC",
+            "owner": "test",
+            "summary": "test created initial release",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+            "version": 1
+        }
+    ]
+}
+ + +

List Release Details

+

Example Request:

+
GET /v2/apps/example-go/releases/v2/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "app": "example-go",
+    "build": null,
+    "config": "95bd6dea-1685-4f78-a03d-fd7270b058d1",
+    "created": "2014-01-01T00:00:00UTC",
+    "owner": "test",
+    "summary": "test created initial release",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+    "version": 1
+}
+ + +

Rollback Release

+

Example Request:

+
POST /v2/apps/example-go/releases/rollback/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"version": 1}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{"version": 5}
+ + +

Keys

+

List Keys

+

Example Request:

+
GET /v2/keys/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "created": "2014-01-01T00:00:00UTC",
+            "id": "test@example.com",
+            "owner": "test",
+            "public": "ssh-rsa <...>",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+        }
+    ]
+}
+ + +

Add Key to User

+

Example Request:

+
POST /v2/keys/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{
+    "id": "example",
+    "public": "ssh-rsa <...>"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "id": "example",
+    "owner": "example",
+    "public": "ssh-rsa <...>",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Remove Key from User

+

Example Request:

+
DELETE /v2/keys/example HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

Permissions

+

List Application Permissions

+
+

note

+

This does not include the app owner.

+
+

Example Request:

+
GET /v2/apps/example-go/perms/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "users": [
+        "test",
+        "foo"
+    ]
+}
+ + +

Create Application Permission

+

Example Request:

+
POST /v2/apps/example-go/perms/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{"username": "example"}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

Remove Application Permission

+

Example Request:

+
DELETE /v2/apps/example-go/perms/example HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

List Administrators

+

Example Request:

+
GET /v2/admin/perms/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "count": 2,
+    "next": null
+    "previous": null,
+    "results": [
+        {
+            "username": "test",
+            "is_superuser": true
+        },
+        {
+            "username": "foo",
+            "is_superuser": true
+        }
+    ]
+}
+ + +

Grant User Administrative Privileges

+
+

note

+

This command requires administrative privileges

+
+

Example Request:

+
POST /v2/admin/perms HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{"username": "example"}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

Remove User's Administrative Privileges

+
+

note

+

This command requires administrative privileges

+
+

Example Request:

+
DELETE /v2/admin/perms/example HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+ + +

Users

+

List all users

+
+

note

+

This command requires administrative privileges

+
+

Example Request:

+
GET /v2/users HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.2
+DRYCC_PLATFORM_VERSION: 2.2.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "id": 1,
+            "last_login": "2014-10-19T22:01:00.601Z",
+            "is_superuser": true,
+            "username": "test",
+            "first_name": "test",
+            "last_name": "testerson",
+            "email": "test@example.com",
+            "is_staff": true,
+            "is_active": true,
+            "date_joined": "2014-10-19T22:01:00.601Z",
+            "groups": [],
+            "user_permissions": []
+        }
+    ]
+}
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference-guide/controller-api/v2.3/index.html b/reference-guide/controller-api/v2.3/index.html new file mode 100644 index 000000000..392dc1756 --- /dev/null +++ b/reference-guide/controller-api/v2.3/index.html @@ -0,0 +1,2086 @@ + + + + + + + + + + + + + + + + + + Controller API v2.3 - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Controller API v2.3

+

This is the v2.3 REST API for the Controller.

+

What's New

+

New! /v2/apps/{name}/logs endpoint was fixed and no longer returns b'log data' and instead returns a normal string log data

+

Authentication

+

Register a New User

+

Example Request:

+
POST /v2/auth/register/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+
+{
+    "username": "test",
+    "password": "opensesame",
+    "email": "test@example.com"
+}
+ + +

Optional Parameters:

+
{
+    "first_name": "test",
+    "last_name": "testerson"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "id": 1,
+    "last_login": "2014-10-19T22:01:00.601Z",
+    "is_superuser": true,
+    "username": "test",
+    "first_name": "test",
+    "last_name": "testerson",
+    "email": "test@example.com",
+    "is_staff": true,
+    "is_active": true,
+    "date_joined": "2014-10-19T22:01:00.601Z",
+    "groups": [],
+    "user_permissions": []
+}
+ + +

Log in

+

Example Request:

+
POST /v2/auth/login/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+
+{"username": "test", "password": "opensesame"}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{"token": "abc123"}
+ + +

Cancel Account

+

Example Request:

+
DELETE /v2/auth/cancel/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

Who Am I

+

Example Request:

+
GET /v2/auth/whoami/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "id": 1,
+    "last_login": "2014-10-19T22:01:00.601Z",
+    "is_superuser": true,
+    "username": "test",
+    "first_name": "test",
+    "last_name": "testerson",
+    "email": "test@example.com",
+    "is_staff": true,
+    "is_active": true,
+    "date_joined": "2014-10-19T22:01:00.601Z",
+    "groups": [],
+    "user_permissions": []
+}
+ + +

Regenerate Token

+
+

note

+

This command could require administrative privileges

+
+

Example Request:

+
POST /v2/auth/tokens/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Optional Parameters:

+
{
+    "username" : "test"
+    "all" : "true"
+}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{"token": "abc123"}
+ + +

Change Password

+

Example Request:

+
POST /v2/auth/passwd/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{
+    "password": "foo",
+    "new_password": "bar"
+}
+ + +

Optional parameters:

+
{"username": "testuser"}
+ + +
+

note

+

Using the username parameter requires administrative privileges and makes the password parameter optional.

+
+

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

Applications

+

List all Applications

+

Example Request:

+
GET /v2/apps HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "created": "2014-01-01T00:00:00UTC",
+            "id": "example-go",
+            "owner": "test",
+            "structure": {},
+            "updated": "2014-01-01T00:00:00UTC",
+            "url": "example-go.example.com",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+        }
+    ]
+}
+ + +

Create an Application

+

Example Request:

+
POST /v2/apps/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+ + +

Optional parameters:

+
{"id": "example-go"}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "id": "example-go",
+    "owner": "test",
+    "structure": {},
+    "updated": "2014-01-01T00:00:00UTC",
+    "url": "example-go.example.com",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Destroy an Application

+

Example Request:

+
DELETE /v2/apps/example-go/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

List Application Details

+

Example Request:

+
GET /v2/apps/example-go/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "id": "example-go",
+    "owner": "test",
+    "structure": {},
+    "updated": "2014-01-01T00:00:00UTC",
+    "url": "example-go.example.com",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Update Application Details

+

Example Request:

+
POST /v2/apps/example-go/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Optional parameters:

+
{
+  "owner": "test"
+}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 1.8.0
+Content-Type: application/json
+ + +

Retrieve Application Logs

+

Example Request:

+
GET /v2/apps/example-go/logs/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Optional URL Query Parameters:

+
?log_lines=
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: text/plain
+
+"16:51:14 drycc[api]: test created initial release\n"
+ + +

Run one-off Commands

+
POST /v2/apps/example-go/run/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"command": "echo hi"}
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{"exit_code": 0, "output": "hi\n"}
+ + +

Certificates

+

List all Certificates

+

Example Request:

+
GET /v2/certs HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+  "count": 1,
+  "next": null,
+  "previous": null,
+  "results": [
+    {
+      "id": 22,
+      "owner": "test",
+      "san": [],
+      "domains": [],
+      "created": "2016-06-22.32.34:20Z",
+      "updated": "2016-06-22.32.34:20Z",
+      "name": "foo",
+      "common_name": "bar.com",
+      "fingerprint": "7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0",
+      "expires": "2017-01-14T23:57:57Z",
+      "starts": "2016-01-15T23:57:57Z",
+      "issuer": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc",
+      "subject": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc"
+    }
+  ]
+}
+ + +

Get Certificate Details

+

Example Request:

+
GET /v2/certs/foo HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+  "id": 22,
+  "owner": "test",
+  "san": [],
+  "domains": [],
+  "created": "2016-06-22.32.34:20Z",
+  "updated": "2016-06-22.32.34:20Z",
+  "name": "foo",
+  "common_name": "bar.com",
+  "fingerprint": "7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0",
+  "expires": "2017-01-14T23:57:57Z",
+  "starts": "2016-01-15T23:57:57Z",
+  "issuer": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc",
+  "subject": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc"
+}
+ + +

Create Certificate

+

Example Request:

+
POST /v2/certs/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{
+    "name": "foo"
+    "certificate": "-----BEGIN CERTIFICATE-----",
+    "key": "-----BEGIN RSA PRIVATE KEY-----"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+  "id": 22,
+  "owner": "test",
+  "san": [],
+  "domains": [],
+  "created": "2016-06-22.32.34:20Z",
+  "updated": "2016-06-22.32.34:20Z",
+  "name": "foo",
+  "common_name": "bar.com",
+  "fingerprint": "7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0",
+  "expires": "2017-01-14T23:57:57Z",
+  "starts": "2016-01-15T23:57:57Z",
+  "issuer": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc",
+  "subject": "/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc"
+}
+ + +

Destroy a Certificate

+

Example Request:

+
DELETE /v2/certs/foo HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

Attach a Domain to a Certificate

+

Example Request:

+
POST /v2/certs/foo/domain/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{
+    "domain": "test.com"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

Remove a Domain from a Certificate

+

Example Request:

+
DELETE /v2/certs/foo/domain/test.com/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

Enable or disable TLS

+

Example Request:

+
POST /v2/apps/example-go/tls/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{
+  "https_enforced": true
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "app": "example-go",
+    "owner": "test",
+    "https_enforced": true,
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Get TLS status

+

Example Request:

+
GET /v2/apps/example-go/tls/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "app": "example-go",
+    "owner": "test",
+    "https_enforced": false,
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Pods

+

List all Pods

+

Example Request:

+
GET /v2/apps/example-go/pods/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "results": [
+        {
+            "name": "go-v2-web-e7dej",
+            "release": "v2",
+            "started": "2014-01-01T00:00:00Z",
+            "state": "up",
+            "type": "web"
+        }
+    ]
+}
+ + +

List all Pods by Type

+

Example Request:

+
GET /v2/apps/example-go/pods/web/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "results": [
+        {
+            "name": "go-v2-web-e7dej",
+            "release": "v2",
+            "started": "2014-01-01T00:00:00Z",
+            "state": "up",
+            "type": "web"
+        }
+    ]
+}
+ + +

Restart All Pods

+

Example Request:

+
POST /v2/apps/example-go/pods/restart/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+[
+    {
+        "name": "go-v2-web-atots",
+        "release": "v2",
+        "started": "2016-04-11T21:07:54Z",
+        "state": "up",
+        "type": "web"
+    }
+]
+ + +

Restart Pods by Type

+

Example Request:

+
POST /v2/apps/example-go/pods/web/restart/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+[
+    {
+        "name": "go-v2-web-atots",
+        "release": "v2",
+        "started": "2016-04-11T21:07:54Z",
+        "state": "up",
+        "type": "web"
+    }
+]
+ + +

Restart Pods by Type and Name

+

Example Request:

+
POST /v2/apps/example-go/pods/go-v2-web-atots/restart/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+[
+    {
+        "name": "go-v2-web-atots",
+        "release": "v2",
+        "started": "2016-04-11T21:07:54Z",
+        "state": "up",
+        "type": "web"
+    }
+]
+ + +

Scale Pods

+

Example Request:

+
POST /v2/apps/example-go/scale/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"web": 3}
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

Configuration

+

List Application Configuration

+

Example Request:

+
GET /v2/apps/example-go/config/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "owner": "test",
+    "app": "example-go",
+    "values": {
+      "PLATFORM": "drycc"
+    },
+    "memory": {},
+    "cpu": {},
+    "tags": {},
+    "healthcheck": {},
+    "created": "2014-01-01T00:00:00UTC",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Create new Config

+

Example Request:

+
POST /v2/apps/example-go/config/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"values": {"HELLO": "world", "PLATFORM": "drycc"}}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "owner": "test",
+    "app": "example-go",
+    "values": {
+        "DRYCC_APP": "example-go",
+        "DRYCC_RELEASE": "v3",
+        "HELLO": "world",
+        "PLATFORM": "drycc"
+
+    },
+    "memory": {},
+    "cpu": {},
+    "tags": {},
+    "healthcheck": {},
+    "created": "2014-01-01T00:00:00UTC",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Unset Config Variable

+

Example Request:

+
POST /v2/apps/example-go/config/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"values": {"HELLO": null}}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "owner": "test",
+    "app": "example-go",
+    "values": {
+        "DRYCC_APP": "example-go",
+        "DRYCC_RELEASE": "v4",
+        "PLATFORM": "drycc"
+   },
+    "memory": {},
+    "cpu": {},
+    "tags": {},
+    "healthcheck": {},
+    "created": "2014-01-01T00:00:00UTC",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Domains

+

List Application Domains

+

Example Request:

+
GET /v2/apps/example-go/domains/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "app": "example-go",
+            "created": "2014-01-01T00:00:00UTC",
+            "domain": "example.example.com",
+            "owner": "test",
+            "updated": "2014-01-01T00:00:00UTC"
+        }
+    ]
+}
+ + +

Add Domain

+

Example Request:

+
POST /v2/apps/example-go/domains/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{'domain': 'example.example.com'}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "app": "example-go",
+    "created": "2014-01-01T00:00:00UTC",
+    "domain": "example.example.com",
+    "owner": "test",
+    "updated": "2014-01-01T00:00:00UTC"
+}
+ + +

Remove Domain

+

Example Request:

+
DELETE /v2/apps/example-go/domains/example.example.com HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

Builds

+

List Application Builds

+

Example Request:

+
GET /v2/apps/example-go/builds/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "app": "example-go",
+            "created": "2014-01-01T00:00:00UTC",
+            "dockerfile": "FROM drycc/slugrunner RUN mkdir -p /app WORKDIR /app ENTRYPOINT [\"/runner/init\"] ADD slug.tgz /app ENV GIT_SHA 060da68f654e75fac06dbedd1995d5f8ad9084db",
+            "image": "example-go",
+            "owner": "test",
+            "procfile": {
+                "web": "example-go"
+            },
+            "sha": "060da68f",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+        }
+    ]
+}
+ + +

Create Application Build

+

Example Request:

+
POST /v2/apps/example-go/builds/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"image": "drycc/example-go:latest"}
+ + +

Optional Parameters:

+
{
+    "procfile": {
+      "web": "./cmd"
+    }
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "app": "example-go",
+    "created": "2014-01-01T00:00:00UTC",
+    "dockerfile": "",
+    "image": "drycc/example-go:latest",
+    "owner": "test",
+    "procfile": {},
+    "sha": "",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Releases

+

List Application Releases

+

Example Request:

+
GET /v2/apps/example-go/releases/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "count": 3,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "app": "example-go",
+            "build": "2.3d8e4b-600e-4425-a85c-ffc7ea607f61",
+            "config": "ed637ceb-5d32-44bd-9406-d326a777a513",
+            "created": "2014-01-01T00:00:00UTC",
+            "owner": "test",
+            "summary": "test changed nothing",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+            "version": 3
+        },
+        {
+            "app": "example-go",
+            "build": "2.3d8e4b-600e-4425-a85c-ffc7ea607f61",
+            "config": "95bd6dea-1685-4f78-a03d-fd7270b058d1",
+            "created": "2014-01-01T00:00:00UTC",
+            "owner": "test",
+            "summary": "test deployed 060da68",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+            "version": 2
+        },
+        {
+            "app": "example-go",
+            "build": null,
+            "config": "95bd6dea-1685-4f78-a03d-fd7270b058d1",
+            "created": "2014-01-01T00:00:00UTC",
+            "owner": "test",
+            "summary": "test created initial release",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+            "version": 1
+        }
+    ]
+}
+ + +

List Release Details

+

Example Request:

+
GET /v2/apps/example-go/releases/v2/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "app": "example-go",
+    "build": null,
+    "config": "95bd6dea-1685-4f78-a03d-fd7270b058d1",
+    "created": "2014-01-01T00:00:00UTC",
+    "owner": "test",
+    "summary": "test created initial release",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75",
+    "version": 1
+}
+ + +

Rollback Release

+

Example Request:

+
POST /v2/apps/example-go/releases/rollback/ HTTP/1.1
+Host: drycc.example.com
+Content-Type: application/json
+Authorization: token abc123
+
+{"version": 1}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{"version": 5}
+ + +

Keys

+

List Keys

+

Example Request:

+
GET /v2/keys/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "created": "2014-01-01T00:00:00UTC",
+            "id": "test@example.com",
+            "owner": "test",
+            "public": "ssh-rsa <...>",
+            "updated": "2014-01-01T00:00:00UTC",
+            "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+        }
+    ]
+}
+ + +

Add Key to User

+

Example Request:

+
POST /v2/keys/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{
+    "id": "example",
+    "public": "ssh-rsa <...>"
+}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "created": "2014-01-01T00:00:00UTC",
+    "id": "example",
+    "owner": "example",
+    "public": "ssh-rsa <...>",
+    "updated": "2014-01-01T00:00:00UTC",
+    "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
+}
+ + +

Remove Key from User

+

Example Request:

+
DELETE /v2/keys/example HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

Permissions

+

List Application Permissions

+
+

note

+

This does not include the app owner.

+
+

Example Request:

+
GET /v2/apps/example-go/perms/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "users": [
+        "test",
+        "foo"
+    ]
+}
+ + +

Create Application Permission

+

Example Request:

+
POST /v2/apps/example-go/perms/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{"username": "example"}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

Remove Application Permission

+

Example Request:

+
DELETE /v2/apps/example-go/perms/example HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

List Administrators

+

Example Request:

+
GET /v2/admin/perms/ HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "count": 2,
+    "next": null
+    "previous": null,
+    "results": [
+        {
+            "username": "test",
+            "is_superuser": true
+        },
+        {
+            "username": "foo",
+            "is_superuser": true
+        }
+    ]
+}
+ + +

Grant User Administrative Privileges

+
+

note

+

This command requires administrative privileges

+
+

Example Request:

+
POST /v2/admin/perms HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+
+{"username": "example"}
+ + +

Example Response:

+
HTTP/1.1 201 CREATED
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

Remove User's Administrative Privileges

+
+

note

+

This command requires administrative privileges

+
+

Example Request:

+
DELETE /v2/admin/perms/example HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 204 NO CONTENT
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+ + +

Users

+

List all users

+
+

note

+

This command requires administrative privileges

+
+

Example Request:

+
GET /v2/users HTTP/1.1
+Host: drycc.example.com
+Authorization: token abc123
+ + +

Example Response:

+
HTTP/1.1 200 OK
+DRYCC_API_VERSION: 2.3
+DRYCC_PLATFORM_VERSION: 2.3.0
+Content-Type: application/json
+
+{
+    "count": 1,
+    "next": null,
+    "previous": null,
+    "results": [
+        {
+            "id": 1,
+            "last_login": "2014-10-19T22:01:00.601Z",
+            "is_superuser": true,
+            "username": "test",
+            "first_name": "test",
+            "last_name": "testerson",
+            "email": "test@example.com",
+            "is_staff": true,
+            "is_active": true,
+            "date_joined": "2014-10-19T22:01:00.601Z",
+            "groups": [],
+            "user_permissions": []
+        }
+    ]
+}
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference-guide/creating-a-self-signed-ssl-certificate/index.html b/reference-guide/creating-a-self-signed-ssl-certificate/index.html new file mode 100644 index 000000000..caf01e93e --- /dev/null +++ b/reference-guide/creating-a-self-signed-ssl-certificate/index.html @@ -0,0 +1,909 @@ + + + + + + + + + + + + + + + + + + Creating a Self-Signed SSL Certificate - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Creating a Self-Signed SSL Certificate

+

When using the app ssl feature for non-production applications or when installing SSL for the platform, you can avoid the costs associated with the SSL certificate by using a self-signed SSL certificate. Though the certificate implements full encryption, visitors to your site will see a browser warning indicating that the certificate should not be trusted.

+

Prerequisites

+

The openssl library is required to generate your own certificate. Run the following command in your local environment to see if you already have openssl installed.

+
$ which openssl
+/usr/bin/openssl
+ + +

If the which command does not return a path then you will need to install openssl yourself:

+ + + + + + + + + + + + + + + + + + + + + +
If you have...Install with...
Mac OS XHomebrew: brew install openssl
Windowscomplete package .exe installed
Ubuntu Linuxapt-get install openssl
+

Generate Private Key and Certificate Signing Request

+

A private key and certificate signing request are required to create an SSL certificate. These can be generated with a few simple commands. When the openssl req command asks for a “challenge password”, just press return, leaving the password empty.

+
$ openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
+...
+$ openssl rsa -passin pass:x -in server.pass.key -out server.key
+writing RSA key
+$ rm server.pass.key
+$ openssl req -new -key server.key -out server.csr
+...
+Country Name (2 letter code) [AU]:US
+State or Province Name (full name) [Some-State]:California
+...
+A challenge password []:
+...
+ + +

Generate SSL Certificate

+

The self-signed SSL certificate is generated from the server.key private key and server.csr files.

+
$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
+ + +

The server.crt file is your site certificate suitable for use with Drycc's SSL endpoint along with the server.key private key.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference-guide/terms/index.html b/reference-guide/terms/index.html new file mode 100644 index 000000000..75b0cc573 --- /dev/null +++ b/reference-guide/terms/index.html @@ -0,0 +1,901 @@ + + + + + + + + + + + + + + + + + + Terms - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Terms

+

Application

+

An application services requests and background jobs for a deployed git repository. Each application includes a set of Containers used to run isolated processes, and a Release that defines the current Build and Config deployed by containers.

+

Build

+

Drycc builds are created automatically on the controller when a developer uses git push drycc master. When a new build is created, a new Release is created automatically.

+

Config

+

Config refers to a set of environment variables used by Containers in as Application.

+

When Config is changed, a new Release is created automatically.

+

Container

+

Drycc containers are instances of containers used to run Applications. Containers perform the actual work of an Application by servicing requests or by running background tasks as part of the cluster.

+

Ephemeral Filesystem

+

Each container gets its own ephemeral filesystem, with a fresh copy of the most recently deployed code. During the container’s lifetime, its running processes can use the filesystem as a temporary scratchpad, but no files that are written are visible to processes in any other container. Any files written to the ephemeral filesystem will be discarded the moment the container is either stopped or restarted.

+

Container States

+

There are several states that a container can be in at any time. The states are:

+
    +
  • initialized - the state of the container before it is created
  • +
  • created - the container is built and ready for operation
  • +
  • up - the container is running
  • +
  • down - the container crashed or is stopped
  • +
  • destroyed - the container has been destroyed
  • +
+

Controller

+

The controller is the "brain" of the Drycc platform. A controller manages Applications and their lifecycle.

+

The controller is in charge of:

+
    +
  • Processing client API calls
  • +
  • Managing containers that perform work for applications
  • +
  • Managing proxies that route traffic to containers
  • +
  • Managing users, keys and other base configuration
  • +
+

The Controller stack includes:

+
    +
  • Django API Server for handling API calls
  • +
+

Key

+

Drycc keys are SSH Keys used during the git push process. Each user can use the client to manage a list of keys on the Controller.

+

Release

+

A Drycc release is a combination of a Build with a Config. Each Application is associated with one release at a time. Drycc releases are numbered and new releases always increment by one (e.g. v1, v2, v3).

+

Containers that host an application use these release versions to pull the correct code and configuration.

+

Scheduler

+

The Scheduler is responsible for creating, starting, stopping, and destroying Containers. For example, a command such as drycc scale cmd=10 tells the Scheduler to run ten Containers from the Container image for your Application.

+

The Scheduler must decide which machines are eligible to run these container jobs. Scheduler backends vary in the details of their job allocation policies and whether or not they are resource-aware, among other features.

+

The Drycc scheduler client is implemented in the Controller component.

+

Service

+

A Kubernetes Service is an abstraction which defines a logical set of Pods and a policy by which to access them. In Workflow, a Service is used to load-balance an application's Containers internally through a virtual IP address.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/roadmap/planning-process/index.html b/roadmap/planning-process/index.html new file mode 100644 index 000000000..5c2739c2c --- /dev/null +++ b/roadmap/planning-process/index.html @@ -0,0 +1,872 @@ + + + + + + + + + + + + + + + + + + Planning Process - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Planning Process

+

Drycc features a lightweight process that emphasizes openness and ensures every community member can be an integral part of planning for the future.

+

The Role of Maintainers

+

Maintainers lead the Drycc projects. Their duties include proposing the Roadmap, reviewing and integrating contributions and maintaining the vision of the project.

+

Open Roadmap

+

The Drycc Roadmap is a community document. While Maintainers propose the Roadmap, it gets discussed and refined in Release Planning Meetings.

+

Contributing to the Roadmap

+

Proposals and issues can be opened by anyone. Every member of the community is welcome to participate in the discussion by providing feedback and/or offering counter-proposals.

+

Release Milestones

+

The Roadmap gets delivered progressively via the Release Schedule. Releases are defined during Release Planning Meetings and managed using GitHub Milestones which track specific deliverables and work-in-progress.

+

Release Planning Meetings

+

Major decisions affecting the Roadmap are discussed during Release Planning Meetings on the first Thursday of each month, aligned with the Release Schedule.

+

Release Planning Meetings are open to the public with access coordinated via the Drycc #community Slack channel. +Notes from past meetings are below, along with links to a recording of the entire meeting on YouTube.

+

Credits

+

Thanks to Amy Lindburg and our friends at Podman for their inspiration.

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/roadmap/releases/index.html b/roadmap/releases/index.html new file mode 100644 index 000000000..f0a55225b --- /dev/null +++ b/roadmap/releases/index.html @@ -0,0 +1,1052 @@ + + + + + + + + + + + + + + + + + + Releases - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Releases

+

Drycc uses a continuous delivery approach for creating releases. Every merged commit that passes +testing results in a deliverable that can be given a semantic version tag and shipped.

+

The master git branch of a project should always work. Only changes considered ready to be +released publicly are merged.

+

Components Release as Needed

+

Drycc components release new versions as often as needed. Fixing a high priority bug requires the +project maintainer to create a new patch release. Merging a backward-compatible feature implies +a minor release.

+

By releasing often, each component release becomes a safe and routine event. This makes it faster +and easier for users to obtain specific fixes. Continuous delivery also reduces the work +necessary to release a product such as Drycc Workflow, which integrates several components.

+

"Components" applies not just to Drycc Workflow projects, but also to development and release +tools, to Container base images, and to other Drycc projects that do semantic version releases.

+

See "How to Release a Component" for more detail.

+

Workflow Releases Each Month

+

Drycc Workflow has a regular, public release cadence. From v2.8.0 onward, new Workflow feature +releases arrive on the first Thursday of each month. Patch releases are created at any time, +as needed. GitHub milestones are used to communicate the content and timing of major and minor +releases, and longer-term planning is visible at the Roadmap.

+

Workflow release timing is not linked to specific features. If a feature is merged before the +release date, it is included in the next release.

+

See "How to Release Workflow" for more detail.

+

Semantic Versioning

+

Drycc releases comply with semantic versioning, with the "public API" broadly +defined as:

+
    +
  • REST, gRPC, or other API that is network-accessible
  • +
  • Library or framework API intended for public use
  • +
  • "Pluggable" socket-level protocols users can redirect
  • +
  • CLI commands and output formats
  • +
+

In general, changes to anything a user might reasonably link to, customize, or integrate with +should be backward-compatible, or else require a major release. Drycc users can be confident that +upgrading to a patch or to a minor release will not break anything.

+

How to Release a Component

+

Most Drycc projects are "components" which produce a Container image or binary executable as a +deliverable. This section leads a maintainer through creating a component release.

+

Step 1: Update Code and Run the Release Tool

+

Major or minor releases should happen on the master branch. Patch releases +should check out the previous release tag and cherry-pick specific commits from master.

+

Note: if a patch release, the release artifact will have to be manually promoted by triggering +the component-promote job with the following values:

+
COMPONENT_NAME=<component name>
+COMPONENT_SHA=<patch commit sha>
+ + +

Make sure you have the dryccrel release tool in your search $PATH.

+

Run dryccrel release once with a fake semver tag to proofread the changelog content. (If HEAD +of master is not what is intended for the release, add the --sha flag as described +in dryccrel release --help.)

+
$ dryccrel release controller v0.0.0
+Doing a dry run of the component release...
+skipping commit 943a49267eeb28546819a266654806cfcbae0e38
+
+Creating changelog for controller with tag v2.8.1 through commit 943a49267eeb28546819a266654806cfcbae0e38
+
+### v2.8.1 -> v0.0.0
+
+#### Fixes
+
+- [`615b834`](https://github.com/drycc/controller/commit/615b834f39cb68a854cc1f1e2f0f82d862ea2731) boot: Ensure DRYCC_DEBUG==true for debug output
+ + +

Based on the changelog content, determine whether the component deserves a minor or patch +release. Run the command again with that semver tag and --dry-run=false. You will still be +asked for confirmation before the release is created:

+
$ dryccrel release controller v2.8.2 --dry-run=false
+skipping commit 943a49267eeb28546819a266654806cfcbae0e38
+
+Creating changelog for controller with tag v2.8.1 through commit 943a49267eeb28546819a266654806cfcbae0e38
+
+### v2.8.1 -> v2.8.2
+
+
+#### Fixes
+
+- [`615b834`](https://github.com/drycc/controller/commit/615b834f39cb68a854cc1f1e2f0f82d862ea2731) boot: Ensure DRYCC_DEBUG==true for debug output
+
+
+Please review the above changelog contents and ensure:
+  1. All intended commits are mentioned
+  2. The changes agree with the semver release tag (major, minor, or patch)
+
+Create release for Drycc Controller v2.8.2? [y/n]: y
+New release is available at https://github.com/drycc/controller/releases/tag/v2.8.2
+ + +

Step 2: Verify the Component is Available

+

Tagging the component (see Step 1) +starts a CI job that eventually results in an artifact being made available for public download. +Please see the CI flow diagrams for details.

+

Double-check that the artifact is available, either by a podman pull command or by running the +appropriate installer script.

+

If the artifact can't be downloaded, ensure that its CI release jobs are still in progress, or +fix whatever issue arose in the pipeline. For example, the +master merge pipeline +may have failed to promote the :git-abc1d23 candidate image and needs to be restarted with +that component and commit.

+

If the component has a correlating Kubernetes Helm chart, +this chart will also be packaged, signed and uploaded to its production chart repo. Please +verify it can be fetched (and verified):

+
$ helm fetch oci://registry.drycc.cc/charts/controller --version 1.0.0
+Verification: &{0xc4207ec870 sha256:026e766e918ff28d2a7041bc3d560d149ee7eb0cb84165c9d9d00a3045ff45c3 controller-v1.0.1.tgz}
+ + +

How to Release Workflow

+

Drycc Workflow integrates multiple component releases together with a Kubernetes Helm chart +deliverable. This section leads a maintainer through creating a Workflow release.

+

Step 1: Set Environment Variables

+

Export two environment variables that will be used in later steps:

+
export WORKFLOW_RELEASE=v2.17.0 WORKFLOW_PREV_RELEASE=v2.16.0  # for example
+ + +

Step 2: Tag Supporting Repositories

+

Some Workflow components not in the Helm chart must also be tagged in sync with the release. +Follow the component release process above and ensure that +these components are tagged:

+ +

The version number for drycc/workflow-cli should always match the overall Workflow version +number.

+

Step 3: Create Helm Chart

+

To create and stage a release candidate chart for Workflow, we will build the workflow-chart-stage job with the following parameters:

+

RELEASE_TAG=$WORKFLOW_RELEASE

+

This job will gather all of the latest component release tags and use these to specify the versions of all component charts. +It will then package the Workflow chart, upload it to the staging chart repo and kick off an e2e run against said chart.

+

Step 4: Manual Testing

+

Now it's time to go above and beyond current CI tests. Create a testing matrix spreadsheet (copying +from the previous document is a good start) and sign up testers to cover all permutations.

+

Testers should pay special attention to the overall user experience, make sure upgrading from +earlier versions is smooth, and cover various storage configurations and Kubernetes versions and +infrastructure providers.

+

When showstopper-level bugs are found, the process is as follows:

+
    +
  1. Create a component PR that fixes the bug.
  2. +
  3. Once the PR passes and is reviewed, merge it and do a new + component release
  4. +
  5. Trigger the same workflow-chart-stage job as mentioned in Step 3 to upload the newly-generated Workflow release candidate chart to staging.
  6. +
+

Step 5: Release the Chart

+

When testing has completed without uncovering any new showstopper bugs, kick off the workflow-chart-release job with the following parameter:

+

RELEASE_TAG=$WORKFLOW_RELEASE

+

This job will copy the release candidate chart (now approved by CI and manual testing) from the staging repo to the production repo, signing +it if it has not done so already.

+

Step 6: Assemble Master Changelog

+

Each component already updated its release notes on GitHub with CHANGELOG content. We'll now +generate the master changelog for the Workflow chart, consisting of all component and auxilliary repo changes.

+

We'll employ the requirements.lock file from the WORKFLOW_PREV_RELEASE chart, as well as a repo-to-chart-name mapping file, this time invoking dryccrel changelog global to get all component changes between +the chart versions existing in the WORKFLOW_PREV_RELEASE chart and the most recent releases existing in GitHub. +(Therefore, if there are any unreleased commits in a component repo, they will not appear here):

+
helm fetch --untar oci://registry.drycc.cc/charts/workflow --version $WORKFLOW_PREV_RELEASE
+dryccrel changelog global workflow/requirements.lock map.json > changelog-$WORKFLOW_RELEASE.md
+ + +

This master changelog should then be placed into a single gist. The file will also be added to the documentation +update PR created in the next step.

+

Step 7: Update Documentation

+

Create a new pull request at drycc/workflow that updates version references to the new release. +Use git grep $WORKFLOW_PREV_RELEASE to find any references, but be careful not to change +CHANGELOG.md.

+

Place the $WORKFLOW_RELEASE master changelog generated in Step 7 in the changelogs directory. +Make sure to add a header to the page to make it clear that this is for a Workflow release, e.g.:

+
## Workflow v2.16.0 -> v2.17.0
+ + +

Once the PR has been reviewed and merged, do a component release of +drycc/workflow itself. The version number for drycc/workflow should always match the +overall Workflow version number.

+

Step 8: Close GitHub Milestones

+

Create a pull request at seed-repo to close the release +milestone and create the next one. When changes are merged to seed-repo, milestones on all +relevant projects will be updated. If there are open issues attached to the milestone, move them +to the next upcoming milestone before merging the pull request.

+

Milestones map to Drycc Workflow releases in drycc/workflow. These milestones do not correspond +to individual component release tags.

+

Step 9: Release Workflow CLI Stable

+

Now that the $WORKFLOW_RELEASE version of Workflow CLI has been vetted, we can push stable artifacts based on this version.

+

Kick off https://ci.drycc.info/job/workflow-cli-build-stable/ with the TAG build parameter of $WORKFLOW_RELEASE +and then verify stable artifacts are available and appropriately updated after the job completes:

+
$ curl -sfL https://www.drycc.cc/install-cli.sh | bash -
+$ ./drycc version
+# (Should show $WORKFLOW_RELEASE)
+ + +

Step 10: Let Everyone Know

+

Let the rest of the team know they can start blogging and tweeting about the new Workflow release. +Post a message to the #company channel on Slack. Include a link to the released chart and to the +master CHANGELOG:

+
@here Drycc Workflow v2.17.0 is now live!
+Master CHANGELOG: https://drycc.info/docs/workflow/changelogs/v2.17.0/
+ + +

You're done with the release. Nice job!

+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/roadmap/roadmap/index.html b/roadmap/roadmap/index.html new file mode 100644 index 000000000..2001773c4 --- /dev/null +++ b/roadmap/roadmap/index.html @@ -0,0 +1,900 @@ + + + + + + + + + + + + + + + + + + Roadmap - Drycc Workflow Documentation + + + + + + + +
+
+ + + + + + + +
+ +
+
+
+
+

Drycc Workflow Roadmap

+

The Drycc Workflow Roadmap is a community document created as part of the open +Planning Process. Each roadmap item describes a high-level capability or +grouping of features that are deemed important to the future of Drycc.

+

Given the project's rapid Release Schedule, roadmap +items are designed to provide a sense of direction over many releases.

+

Interactive drycc run /bin/bash

+

Provide the ability for developers to launch an interactive terminal session in +their application environment.

+

Related issues:

+ +

Log Streaming

+

Stream application logs via drycc logs -f https://github.com/drycc/drycc/issues/465

+

Teams and Permissions

+

Teams and Permissions represents a more flexible permissions model to allow +more nuanced control to applications, capabilities and resources on the +platform. There have been a number of proposals in this area which need to be +reconciled for Drycc Workflow before we begin implementation.

+

Related issues:

+ +

Monitoring

+ +

Workflow Addons/Services

+

Developers should be able to quickly and easily provision application +dependencies using a services or addon abstraction. +https://github.com/drycc/drycc/issues/231

+

Inbound/Outbound Webhooks

+

Drycc Workflow should be able to send and receive webhooks from external +systems. Facilitating integration with third party services like GitHub, +Gitlab, Slack, Hipchat.

+ +
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/search/lunr.js b/search/lunr.js new file mode 100644 index 000000000..6aa370fbc --- /dev/null +++ b/search/lunr.js @@ -0,0 +1,3475 @@ +/** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + */ + +;(function(){ + +/** + * A convenience function for configuring and constructing + * a new lunr Index. + * + * A lunr.Builder instance is created and the pipeline setup + * with a trimmer, stop word filter and stemmer. + * + * This builder object is yielded to the configuration function + * that is passed as a parameter, allowing the list of fields + * and other builder parameters to be customised. + * + * All documents _must_ be added within the passed config function. + * + * @example + * var idx = lunr(function () { + * this.field('title') + * this.field('body') + * this.ref('id') + * + * documents.forEach(function (doc) { + * this.add(doc) + * }, this) + * }) + * + * @see {@link lunr.Builder} + * @see {@link lunr.Pipeline} + * @see {@link lunr.trimmer} + * @see {@link lunr.stopWordFilter} + * @see {@link lunr.stemmer} + * @namespace {function} lunr + */ +var lunr = function (config) { + var builder = new lunr.Builder + + builder.pipeline.add( + lunr.trimmer, + lunr.stopWordFilter, + lunr.stemmer + ) + + builder.searchPipeline.add( + lunr.stemmer + ) + + config.call(builder, builder) + return builder.build() +} + +lunr.version = "2.3.9" +/*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * A namespace containing utils for the rest of the lunr library + * @namespace lunr.utils + */ +lunr.utils = {} + +/** + * Print a warning message to the console. + * + * @param {String} message The message to be printed. + * @memberOf lunr.utils + * @function + */ +lunr.utils.warn = (function (global) { + /* eslint-disable no-console */ + return function (message) { + if (global.console && console.warn) { + console.warn(message) + } + } + /* eslint-enable no-console */ +})(this) + +/** + * Convert an object to a string. + * + * In the case of `null` and `undefined` the function returns + * the empty string, in all other cases the result of calling + * `toString` on the passed object is returned. + * + * @param {Any} obj The object to convert to a string. + * @return {String} string representation of the passed object. + * @memberOf lunr.utils + */ +lunr.utils.asString = function (obj) { + if (obj === void 0 || obj === null) { + return "" + } else { + return obj.toString() + } +} + +/** + * Clones an object. + * + * Will create a copy of an existing object such that any mutations + * on the copy cannot affect the original. + * + * Only shallow objects are supported, passing a nested object to this + * function will cause a TypeError. + * + * Objects with primitives, and arrays of primitives are supported. + * + * @param {Object} obj The object to clone. + * @return {Object} a clone of the passed object. + * @throws {TypeError} when a nested object is passed. + * @memberOf Utils + */ +lunr.utils.clone = function (obj) { + if (obj === null || obj === undefined) { + return obj + } + + var clone = Object.create(null), + keys = Object.keys(obj) + + for (var i = 0; i < keys.length; i++) { + var key = keys[i], + val = obj[key] + + if (Array.isArray(val)) { + clone[key] = val.slice() + continue + } + + if (typeof val === 'string' || + typeof val === 'number' || + typeof val === 'boolean') { + clone[key] = val + continue + } + + throw new TypeError("clone is not deep and does not support nested objects") + } + + return clone +} +lunr.FieldRef = function (docRef, fieldName, stringValue) { + this.docRef = docRef + this.fieldName = fieldName + this._stringValue = stringValue +} + +lunr.FieldRef.joiner = "/" + +lunr.FieldRef.fromString = function (s) { + var n = s.indexOf(lunr.FieldRef.joiner) + + if (n === -1) { + throw "malformed field ref string" + } + + var fieldRef = s.slice(0, n), + docRef = s.slice(n + 1) + + return new lunr.FieldRef (docRef, fieldRef, s) +} + +lunr.FieldRef.prototype.toString = function () { + if (this._stringValue == undefined) { + this._stringValue = this.fieldName + lunr.FieldRef.joiner + this.docRef + } + + return this._stringValue +} +/*! + * lunr.Set + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * A lunr set. + * + * @constructor + */ +lunr.Set = function (elements) { + this.elements = Object.create(null) + + if (elements) { + this.length = elements.length + + for (var i = 0; i < this.length; i++) { + this.elements[elements[i]] = true + } + } else { + this.length = 0 + } +} + +/** + * A complete set that contains all elements. + * + * @static + * @readonly + * @type {lunr.Set} + */ +lunr.Set.complete = { + intersect: function (other) { + return other + }, + + union: function () { + return this + }, + + contains: function () { + return true + } +} + +/** + * An empty set that contains no elements. + * + * @static + * @readonly + * @type {lunr.Set} + */ +lunr.Set.empty = { + intersect: function () { + return this + }, + + union: function (other) { + return other + }, + + contains: function () { + return false + } +} + +/** + * Returns true if this set contains the specified object. + * + * @param {object} object - Object whose presence in this set is to be tested. + * @returns {boolean} - True if this set contains the specified object. + */ +lunr.Set.prototype.contains = function (object) { + return !!this.elements[object] +} + +/** + * Returns a new set containing only the elements that are present in both + * this set and the specified set. + * + * @param {lunr.Set} other - set to intersect with this set. + * @returns {lunr.Set} a new set that is the intersection of this and the specified set. + */ + +lunr.Set.prototype.intersect = function (other) { + var a, b, elements, intersection = [] + + if (other === lunr.Set.complete) { + return this + } + + if (other === lunr.Set.empty) { + return other + } + + if (this.length < other.length) { + a = this + b = other + } else { + a = other + b = this + } + + elements = Object.keys(a.elements) + + for (var i = 0; i < elements.length; i++) { + var element = elements[i] + if (element in b.elements) { + intersection.push(element) + } + } + + return new lunr.Set (intersection) +} + +/** + * Returns a new set combining the elements of this and the specified set. + * + * @param {lunr.Set} other - set to union with this set. + * @return {lunr.Set} a new set that is the union of this and the specified set. + */ + +lunr.Set.prototype.union = function (other) { + if (other === lunr.Set.complete) { + return lunr.Set.complete + } + + if (other === lunr.Set.empty) { + return this + } + + return new lunr.Set(Object.keys(this.elements).concat(Object.keys(other.elements))) +} +/** + * A function to calculate the inverse document frequency for + * a posting. This is shared between the builder and the index + * + * @private + * @param {object} posting - The posting for a given term + * @param {number} documentCount - The total number of documents. + */ +lunr.idf = function (posting, documentCount) { + var documentsWithTerm = 0 + + for (var fieldName in posting) { + if (fieldName == '_index') continue // Ignore the term index, its not a field + documentsWithTerm += Object.keys(posting[fieldName]).length + } + + var x = (documentCount - documentsWithTerm + 0.5) / (documentsWithTerm + 0.5) + + return Math.log(1 + Math.abs(x)) +} + +/** + * A token wraps a string representation of a token + * as it is passed through the text processing pipeline. + * + * @constructor + * @param {string} [str=''] - The string token being wrapped. + * @param {object} [metadata={}] - Metadata associated with this token. + */ +lunr.Token = function (str, metadata) { + this.str = str || "" + this.metadata = metadata || {} +} + +/** + * Returns the token string that is being wrapped by this object. + * + * @returns {string} + */ +lunr.Token.prototype.toString = function () { + return this.str +} + +/** + * A token update function is used when updating or optionally + * when cloning a token. + * + * @callback lunr.Token~updateFunction + * @param {string} str - The string representation of the token. + * @param {Object} metadata - All metadata associated with this token. + */ + +/** + * Applies the given function to the wrapped string token. + * + * @example + * token.update(function (str, metadata) { + * return str.toUpperCase() + * }) + * + * @param {lunr.Token~updateFunction} fn - A function to apply to the token string. + * @returns {lunr.Token} + */ +lunr.Token.prototype.update = function (fn) { + this.str = fn(this.str, this.metadata) + return this +} + +/** + * Creates a clone of this token. Optionally a function can be + * applied to the cloned token. + * + * @param {lunr.Token~updateFunction} [fn] - An optional function to apply to the cloned token. + * @returns {lunr.Token} + */ +lunr.Token.prototype.clone = function (fn) { + fn = fn || function (s) { return s } + return new lunr.Token (fn(this.str, this.metadata), this.metadata) +} +/*! + * lunr.tokenizer + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * A function for splitting a string into tokens ready to be inserted into + * the search index. Uses `lunr.tokenizer.separator` to split strings, change + * the value of this property to change how strings are split into tokens. + * + * This tokenizer will convert its parameter to a string by calling `toString` and + * then will split this string on the character in `lunr.tokenizer.separator`. + * Arrays will have their elements converted to strings and wrapped in a lunr.Token. + * + * Optional metadata can be passed to the tokenizer, this metadata will be cloned and + * added as metadata to every token that is created from the object to be tokenized. + * + * @static + * @param {?(string|object|object[])} obj - The object to convert into tokens + * @param {?object} metadata - Optional metadata to associate with every token + * @returns {lunr.Token[]} + * @see {@link lunr.Pipeline} + */ +lunr.tokenizer = function (obj, metadata) { + if (obj == null || obj == undefined) { + return [] + } + + if (Array.isArray(obj)) { + return obj.map(function (t) { + return new lunr.Token( + lunr.utils.asString(t).toLowerCase(), + lunr.utils.clone(metadata) + ) + }) + } + + var str = obj.toString().toLowerCase(), + len = str.length, + tokens = [] + + for (var sliceEnd = 0, sliceStart = 0; sliceEnd <= len; sliceEnd++) { + var char = str.charAt(sliceEnd), + sliceLength = sliceEnd - sliceStart + + if ((char.match(lunr.tokenizer.separator) || sliceEnd == len)) { + + if (sliceLength > 0) { + var tokenMetadata = lunr.utils.clone(metadata) || {} + tokenMetadata["position"] = [sliceStart, sliceLength] + tokenMetadata["index"] = tokens.length + + tokens.push( + new lunr.Token ( + str.slice(sliceStart, sliceEnd), + tokenMetadata + ) + ) + } + + sliceStart = sliceEnd + 1 + } + + } + + return tokens +} + +/** + * The separator used to split a string into tokens. Override this property to change the behaviour of + * `lunr.tokenizer` behaviour when tokenizing strings. By default this splits on whitespace and hyphens. + * + * @static + * @see lunr.tokenizer + */ +lunr.tokenizer.separator = /[\s\-]+/ +/*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * lunr.Pipelines maintain an ordered list of functions to be applied to all + * tokens in documents entering the search index and queries being ran against + * the index. + * + * An instance of lunr.Index created with the lunr shortcut will contain a + * pipeline with a stop word filter and an English language stemmer. Extra + * functions can be added before or after either of these functions or these + * default functions can be removed. + * + * When run the pipeline will call each function in turn, passing a token, the + * index of that token in the original list of all tokens and finally a list of + * all the original tokens. + * + * The output of functions in the pipeline will be passed to the next function + * in the pipeline. To exclude a token from entering the index the function + * should return undefined, the rest of the pipeline will not be called with + * this token. + * + * For serialisation of pipelines to work, all functions used in an instance of + * a pipeline should be registered with lunr.Pipeline. Registered functions can + * then be loaded. If trying to load a serialised pipeline that uses functions + * that are not registered an error will be thrown. + * + * If not planning on serialising the pipeline then registering pipeline functions + * is not necessary. + * + * @constructor + */ +lunr.Pipeline = function () { + this._stack = [] +} + +lunr.Pipeline.registeredFunctions = Object.create(null) + +/** + * A pipeline function maps lunr.Token to lunr.Token. A lunr.Token contains the token + * string as well as all known metadata. A pipeline function can mutate the token string + * or mutate (or add) metadata for a given token. + * + * A pipeline function can indicate that the passed token should be discarded by returning + * null, undefined or an empty string. This token will not be passed to any downstream pipeline + * functions and will not be added to the index. + * + * Multiple tokens can be returned by returning an array of tokens. Each token will be passed + * to any downstream pipeline functions and all will returned tokens will be added to the index. + * + * Any number of pipeline functions may be chained together using a lunr.Pipeline. + * + * @interface lunr.PipelineFunction + * @param {lunr.Token} token - A token from the document being processed. + * @param {number} i - The index of this token in the complete list of tokens for this document/field. + * @param {lunr.Token[]} tokens - All tokens for this document/field. + * @returns {(?lunr.Token|lunr.Token[])} + */ + +/** + * Register a function with the pipeline. + * + * Functions that are used in the pipeline should be registered if the pipeline + * needs to be serialised, or a serialised pipeline needs to be loaded. + * + * Registering a function does not add it to a pipeline, functions must still be + * added to instances of the pipeline for them to be used when running a pipeline. + * + * @param {lunr.PipelineFunction} fn - The function to check for. + * @param {String} label - The label to register this function with + */ +lunr.Pipeline.registerFunction = function (fn, label) { + if (label in this.registeredFunctions) { + lunr.utils.warn('Overwriting existing registered function: ' + label) + } + + fn.label = label + lunr.Pipeline.registeredFunctions[fn.label] = fn +} + +/** + * Warns if the function is not registered as a Pipeline function. + * + * @param {lunr.PipelineFunction} fn - The function to check for. + * @private + */ +lunr.Pipeline.warnIfFunctionNotRegistered = function (fn) { + var isRegistered = fn.label && (fn.label in this.registeredFunctions) + + if (!isRegistered) { + lunr.utils.warn('Function is not registered with pipeline. This may cause problems when serialising the index.\n', fn) + } +} + +/** + * Loads a previously serialised pipeline. + * + * All functions to be loaded must already be registered with lunr.Pipeline. + * If any function from the serialised data has not been registered then an + * error will be thrown. + * + * @param {Object} serialised - The serialised pipeline to load. + * @returns {lunr.Pipeline} + */ +lunr.Pipeline.load = function (serialised) { + var pipeline = new lunr.Pipeline + + serialised.forEach(function (fnName) { + var fn = lunr.Pipeline.registeredFunctions[fnName] + + if (fn) { + pipeline.add(fn) + } else { + throw new Error('Cannot load unregistered function: ' + fnName) + } + }) + + return pipeline +} + +/** + * Adds new functions to the end of the pipeline. + * + * Logs a warning if the function has not been registered. + * + * @param {lunr.PipelineFunction[]} functions - Any number of functions to add to the pipeline. + */ +lunr.Pipeline.prototype.add = function () { + var fns = Array.prototype.slice.call(arguments) + + fns.forEach(function (fn) { + lunr.Pipeline.warnIfFunctionNotRegistered(fn) + this._stack.push(fn) + }, this) +} + +/** + * Adds a single function after a function that already exists in the + * pipeline. + * + * Logs a warning if the function has not been registered. + * + * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline. + * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline. + */ +lunr.Pipeline.prototype.after = function (existingFn, newFn) { + lunr.Pipeline.warnIfFunctionNotRegistered(newFn) + + var pos = this._stack.indexOf(existingFn) + if (pos == -1) { + throw new Error('Cannot find existingFn') + } + + pos = pos + 1 + this._stack.splice(pos, 0, newFn) +} + +/** + * Adds a single function before a function that already exists in the + * pipeline. + * + * Logs a warning if the function has not been registered. + * + * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline. + * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline. + */ +lunr.Pipeline.prototype.before = function (existingFn, newFn) { + lunr.Pipeline.warnIfFunctionNotRegistered(newFn) + + var pos = this._stack.indexOf(existingFn) + if (pos == -1) { + throw new Error('Cannot find existingFn') + } + + this._stack.splice(pos, 0, newFn) +} + +/** + * Removes a function from the pipeline. + * + * @param {lunr.PipelineFunction} fn The function to remove from the pipeline. + */ +lunr.Pipeline.prototype.remove = function (fn) { + var pos = this._stack.indexOf(fn) + if (pos == -1) { + return + } + + this._stack.splice(pos, 1) +} + +/** + * Runs the current list of functions that make up the pipeline against the + * passed tokens. + * + * @param {Array} tokens The tokens to run through the pipeline. + * @returns {Array} + */ +lunr.Pipeline.prototype.run = function (tokens) { + var stackLength = this._stack.length + + for (var i = 0; i < stackLength; i++) { + var fn = this._stack[i] + var memo = [] + + for (var j = 0; j < tokens.length; j++) { + var result = fn(tokens[j], j, tokens) + + if (result === null || result === void 0 || result === '') continue + + if (Array.isArray(result)) { + for (var k = 0; k < result.length; k++) { + memo.push(result[k]) + } + } else { + memo.push(result) + } + } + + tokens = memo + } + + return tokens +} + +/** + * Convenience method for passing a string through a pipeline and getting + * strings out. This method takes care of wrapping the passed string in a + * token and mapping the resulting tokens back to strings. + * + * @param {string} str - The string to pass through the pipeline. + * @param {?object} metadata - Optional metadata to associate with the token + * passed to the pipeline. + * @returns {string[]} + */ +lunr.Pipeline.prototype.runString = function (str, metadata) { + var token = new lunr.Token (str, metadata) + + return this.run([token]).map(function (t) { + return t.toString() + }) +} + +/** + * Resets the pipeline by removing any existing processors. + * + */ +lunr.Pipeline.prototype.reset = function () { + this._stack = [] +} + +/** + * Returns a representation of the pipeline ready for serialisation. + * + * Logs a warning if the function has not been registered. + * + * @returns {Array} + */ +lunr.Pipeline.prototype.toJSON = function () { + return this._stack.map(function (fn) { + lunr.Pipeline.warnIfFunctionNotRegistered(fn) + + return fn.label + }) +} +/*! + * lunr.Vector + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * A vector is used to construct the vector space of documents and queries. These + * vectors support operations to determine the similarity between two documents or + * a document and a query. + * + * Normally no parameters are required for initializing a vector, but in the case of + * loading a previously dumped vector the raw elements can be provided to the constructor. + * + * For performance reasons vectors are implemented with a flat array, where an elements + * index is immediately followed by its value. E.g. [index, value, index, value]. This + * allows the underlying array to be as sparse as possible and still offer decent + * performance when being used for vector calculations. + * + * @constructor + * @param {Number[]} [elements] - The flat list of element index and element value pairs. + */ +lunr.Vector = function (elements) { + this._magnitude = 0 + this.elements = elements || [] +} + + +/** + * Calculates the position within the vector to insert a given index. + * + * This is used internally by insert and upsert. If there are duplicate indexes then + * the position is returned as if the value for that index were to be updated, but it + * is the callers responsibility to check whether there is a duplicate at that index + * + * @param {Number} insertIdx - The index at which the element should be inserted. + * @returns {Number} + */ +lunr.Vector.prototype.positionForIndex = function (index) { + // For an empty vector the tuple can be inserted at the beginning + if (this.elements.length == 0) { + return 0 + } + + var start = 0, + end = this.elements.length / 2, + sliceLength = end - start, + pivotPoint = Math.floor(sliceLength / 2), + pivotIndex = this.elements[pivotPoint * 2] + + while (sliceLength > 1) { + if (pivotIndex < index) { + start = pivotPoint + } + + if (pivotIndex > index) { + end = pivotPoint + } + + if (pivotIndex == index) { + break + } + + sliceLength = end - start + pivotPoint = start + Math.floor(sliceLength / 2) + pivotIndex = this.elements[pivotPoint * 2] + } + + if (pivotIndex == index) { + return pivotPoint * 2 + } + + if (pivotIndex > index) { + return pivotPoint * 2 + } + + if (pivotIndex < index) { + return (pivotPoint + 1) * 2 + } +} + +/** + * Inserts an element at an index within the vector. + * + * Does not allow duplicates, will throw an error if there is already an entry + * for this index. + * + * @param {Number} insertIdx - The index at which the element should be inserted. + * @param {Number} val - The value to be inserted into the vector. + */ +lunr.Vector.prototype.insert = function (insertIdx, val) { + this.upsert(insertIdx, val, function () { + throw "duplicate index" + }) +} + +/** + * Inserts or updates an existing index within the vector. + * + * @param {Number} insertIdx - The index at which the element should be inserted. + * @param {Number} val - The value to be inserted into the vector. + * @param {function} fn - A function that is called for updates, the existing value and the + * requested value are passed as arguments + */ +lunr.Vector.prototype.upsert = function (insertIdx, val, fn) { + this._magnitude = 0 + var position = this.positionForIndex(insertIdx) + + if (this.elements[position] == insertIdx) { + this.elements[position + 1] = fn(this.elements[position + 1], val) + } else { + this.elements.splice(position, 0, insertIdx, val) + } +} + +/** + * Calculates the magnitude of this vector. + * + * @returns {Number} + */ +lunr.Vector.prototype.magnitude = function () { + if (this._magnitude) return this._magnitude + + var sumOfSquares = 0, + elementsLength = this.elements.length + + for (var i = 1; i < elementsLength; i += 2) { + var val = this.elements[i] + sumOfSquares += val * val + } + + return this._magnitude = Math.sqrt(sumOfSquares) +} + +/** + * Calculates the dot product of this vector and another vector. + * + * @param {lunr.Vector} otherVector - The vector to compute the dot product with. + * @returns {Number} + */ +lunr.Vector.prototype.dot = function (otherVector) { + var dotProduct = 0, + a = this.elements, b = otherVector.elements, + aLen = a.length, bLen = b.length, + aVal = 0, bVal = 0, + i = 0, j = 0 + + while (i < aLen && j < bLen) { + aVal = a[i], bVal = b[j] + if (aVal < bVal) { + i += 2 + } else if (aVal > bVal) { + j += 2 + } else if (aVal == bVal) { + dotProduct += a[i + 1] * b[j + 1] + i += 2 + j += 2 + } + } + + return dotProduct +} + +/** + * Calculates the similarity between this vector and another vector. + * + * @param {lunr.Vector} otherVector - The other vector to calculate the + * similarity with. + * @returns {Number} + */ +lunr.Vector.prototype.similarity = function (otherVector) { + return this.dot(otherVector) / this.magnitude() || 0 +} + +/** + * Converts the vector to an array of the elements within the vector. + * + * @returns {Number[]} + */ +lunr.Vector.prototype.toArray = function () { + var output = new Array (this.elements.length / 2) + + for (var i = 1, j = 0; i < this.elements.length; i += 2, j++) { + output[j] = this.elements[i] + } + + return output +} + +/** + * A JSON serializable representation of the vector. + * + * @returns {Number[]} + */ +lunr.Vector.prototype.toJSON = function () { + return this.elements +} +/* eslint-disable */ +/*! + * lunr.stemmer + * Copyright (C) 2020 Oliver Nightingale + * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt + */ + +/** + * lunr.stemmer is an english language stemmer, this is a JavaScript + * implementation of the PorterStemmer taken from http://tartarus.org/~martin + * + * @static + * @implements {lunr.PipelineFunction} + * @param {lunr.Token} token - The string to stem + * @returns {lunr.Token} + * @see {@link lunr.Pipeline} + * @function + */ +lunr.stemmer = (function(){ + var step2list = { + "ational" : "ate", + "tional" : "tion", + "enci" : "ence", + "anci" : "ance", + "izer" : "ize", + "bli" : "ble", + "alli" : "al", + "entli" : "ent", + "eli" : "e", + "ousli" : "ous", + "ization" : "ize", + "ation" : "ate", + "ator" : "ate", + "alism" : "al", + "iveness" : "ive", + "fulness" : "ful", + "ousness" : "ous", + "aliti" : "al", + "iviti" : "ive", + "biliti" : "ble", + "logi" : "log" + }, + + step3list = { + "icate" : "ic", + "ative" : "", + "alize" : "al", + "iciti" : "ic", + "ical" : "ic", + "ful" : "", + "ness" : "" + }, + + c = "[^aeiou]", // consonant + v = "[aeiouy]", // vowel + C = c + "[^aeiouy]*", // consonant sequence + V = v + "[aeiou]*", // vowel sequence + + mgr0 = "^(" + C + ")?" + V + C, // [C]VC... is m>0 + meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$", // [C]VC[V] is m=1 + mgr1 = "^(" + C + ")?" + V + C + V + C, // [C]VCVC... is m>1 + s_v = "^(" + C + ")?" + v; // vowel in stem + + var re_mgr0 = new RegExp(mgr0); + var re_mgr1 = new RegExp(mgr1); + var re_meq1 = new RegExp(meq1); + var re_s_v = new RegExp(s_v); + + var re_1a = /^(.+?)(ss|i)es$/; + var re2_1a = /^(.+?)([^s])s$/; + var re_1b = /^(.+?)eed$/; + var re2_1b = /^(.+?)(ed|ing)$/; + var re_1b_2 = /.$/; + var re2_1b_2 = /(at|bl|iz)$/; + var re3_1b_2 = new RegExp("([^aeiouylsz])\\1$"); + var re4_1b_2 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + + var re_1c = /^(.+?[^aeiou])y$/; + var re_2 = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + + var re_3 = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + + var re_4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + var re2_4 = /^(.+?)(s|t)(ion)$/; + + var re_5 = /^(.+?)e$/; + var re_5_1 = /ll$/; + var re3_5 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + + var porterStemmer = function porterStemmer(w) { + var stem, + suffix, + firstch, + re, + re2, + re3, + re4; + + if (w.length < 3) { return w; } + + firstch = w.substr(0,1); + if (firstch == "y") { + w = firstch.toUpperCase() + w.substr(1); + } + + // Step 1a + re = re_1a + re2 = re2_1a; + + if (re.test(w)) { w = w.replace(re,"$1$2"); } + else if (re2.test(w)) { w = w.replace(re2,"$1$2"); } + + // Step 1b + re = re_1b; + re2 = re2_1b; + if (re.test(w)) { + var fp = re.exec(w); + re = re_mgr0; + if (re.test(fp[1])) { + re = re_1b_2; + w = w.replace(re,""); + } + } else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = re_s_v; + if (re2.test(stem)) { + w = stem; + re2 = re2_1b_2; + re3 = re3_1b_2; + re4 = re4_1b_2; + if (re2.test(w)) { w = w + "e"; } + else if (re3.test(w)) { re = re_1b_2; w = w.replace(re,""); } + else if (re4.test(w)) { w = w + "e"; } + } + } + + // Step 1c - replace suffix y or Y by i if preceded by a non-vowel which is not the first letter of the word (so cry -> cri, by -> by, say -> say) + re = re_1c; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + w = stem + "i"; + } + + // Step 2 + re = re_2; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = re_mgr0; + if (re.test(stem)) { + w = stem + step2list[suffix]; + } + } + + // Step 3 + re = re_3; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = re_mgr0; + if (re.test(stem)) { + w = stem + step3list[suffix]; + } + } + + // Step 4 + re = re_4; + re2 = re2_4; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = re_mgr1; + if (re.test(stem)) { + w = stem; + } + } else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = re_mgr1; + if (re2.test(stem)) { + w = stem; + } + } + + // Step 5 + re = re_5; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = re_mgr1; + re2 = re_meq1; + re3 = re3_5; + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) { + w = stem; + } + } + + re = re_5_1; + re2 = re_mgr1; + if (re.test(w) && re2.test(w)) { + re = re_1b_2; + w = w.replace(re,""); + } + + // and turn initial Y back to y + + if (firstch == "y") { + w = firstch.toLowerCase() + w.substr(1); + } + + return w; + }; + + return function (token) { + return token.update(porterStemmer); + } +})(); + +lunr.Pipeline.registerFunction(lunr.stemmer, 'stemmer') +/*! + * lunr.stopWordFilter + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * lunr.generateStopWordFilter builds a stopWordFilter function from the provided + * list of stop words. + * + * The built in lunr.stopWordFilter is built using this generator and can be used + * to generate custom stopWordFilters for applications or non English languages. + * + * @function + * @param {Array} token The token to pass through the filter + * @returns {lunr.PipelineFunction} + * @see lunr.Pipeline + * @see lunr.stopWordFilter + */ +lunr.generateStopWordFilter = function (stopWords) { + var words = stopWords.reduce(function (memo, stopWord) { + memo[stopWord] = stopWord + return memo + }, {}) + + return function (token) { + if (token && words[token.toString()] !== token.toString()) return token + } +} + +/** + * lunr.stopWordFilter is an English language stop word list filter, any words + * contained in the list will not be passed through the filter. + * + * This is intended to be used in the Pipeline. If the token does not pass the + * filter then undefined will be returned. + * + * @function + * @implements {lunr.PipelineFunction} + * @params {lunr.Token} token - A token to check for being a stop word. + * @returns {lunr.Token} + * @see {@link lunr.Pipeline} + */ +lunr.stopWordFilter = lunr.generateStopWordFilter([ + 'a', + 'able', + 'about', + 'across', + 'after', + 'all', + 'almost', + 'also', + 'am', + 'among', + 'an', + 'and', + 'any', + 'are', + 'as', + 'at', + 'be', + 'because', + 'been', + 'but', + 'by', + 'can', + 'cannot', + 'could', + 'dear', + 'did', + 'do', + 'does', + 'either', + 'else', + 'ever', + 'every', + 'for', + 'from', + 'get', + 'got', + 'had', + 'has', + 'have', + 'he', + 'her', + 'hers', + 'him', + 'his', + 'how', + 'however', + 'i', + 'if', + 'in', + 'into', + 'is', + 'it', + 'its', + 'just', + 'least', + 'let', + 'like', + 'likely', + 'may', + 'me', + 'might', + 'most', + 'must', + 'my', + 'neither', + 'no', + 'nor', + 'not', + 'of', + 'off', + 'often', + 'on', + 'only', + 'or', + 'other', + 'our', + 'own', + 'rather', + 'said', + 'say', + 'says', + 'she', + 'should', + 'since', + 'so', + 'some', + 'than', + 'that', + 'the', + 'their', + 'them', + 'then', + 'there', + 'these', + 'they', + 'this', + 'tis', + 'to', + 'too', + 'twas', + 'us', + 'wants', + 'was', + 'we', + 'were', + 'what', + 'when', + 'where', + 'which', + 'while', + 'who', + 'whom', + 'why', + 'will', + 'with', + 'would', + 'yet', + 'you', + 'your' +]) + +lunr.Pipeline.registerFunction(lunr.stopWordFilter, 'stopWordFilter') +/*! + * lunr.trimmer + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * lunr.trimmer is a pipeline function for trimming non word + * characters from the beginning and end of tokens before they + * enter the index. + * + * This implementation may not work correctly for non latin + * characters and should either be removed or adapted for use + * with languages with non-latin characters. + * + * @static + * @implements {lunr.PipelineFunction} + * @param {lunr.Token} token The token to pass through the filter + * @returns {lunr.Token} + * @see lunr.Pipeline + */ +lunr.trimmer = function (token) { + return token.update(function (s) { + return s.replace(/^\W+/, '').replace(/\W+$/, '') + }) +} + +lunr.Pipeline.registerFunction(lunr.trimmer, 'trimmer') +/*! + * lunr.TokenSet + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * A token set is used to store the unique list of all tokens + * within an index. Token sets are also used to represent an + * incoming query to the index, this query token set and index + * token set are then intersected to find which tokens to look + * up in the inverted index. + * + * A token set can hold multiple tokens, as in the case of the + * index token set, or it can hold a single token as in the + * case of a simple query token set. + * + * Additionally token sets are used to perform wildcard matching. + * Leading, contained and trailing wildcards are supported, and + * from this edit distance matching can also be provided. + * + * Token sets are implemented as a minimal finite state automata, + * where both common prefixes and suffixes are shared between tokens. + * This helps to reduce the space used for storing the token set. + * + * @constructor + */ +lunr.TokenSet = function () { + this.final = false + this.edges = {} + this.id = lunr.TokenSet._nextId + lunr.TokenSet._nextId += 1 +} + +/** + * Keeps track of the next, auto increment, identifier to assign + * to a new tokenSet. + * + * TokenSets require a unique identifier to be correctly minimised. + * + * @private + */ +lunr.TokenSet._nextId = 1 + +/** + * Creates a TokenSet instance from the given sorted array of words. + * + * @param {String[]} arr - A sorted array of strings to create the set from. + * @returns {lunr.TokenSet} + * @throws Will throw an error if the input array is not sorted. + */ +lunr.TokenSet.fromArray = function (arr) { + var builder = new lunr.TokenSet.Builder + + for (var i = 0, len = arr.length; i < len; i++) { + builder.insert(arr[i]) + } + + builder.finish() + return builder.root +} + +/** + * Creates a token set from a query clause. + * + * @private + * @param {Object} clause - A single clause from lunr.Query. + * @param {string} clause.term - The query clause term. + * @param {number} [clause.editDistance] - The optional edit distance for the term. + * @returns {lunr.TokenSet} + */ +lunr.TokenSet.fromClause = function (clause) { + if ('editDistance' in clause) { + return lunr.TokenSet.fromFuzzyString(clause.term, clause.editDistance) + } else { + return lunr.TokenSet.fromString(clause.term) + } +} + +/** + * Creates a token set representing a single string with a specified + * edit distance. + * + * Insertions, deletions, substitutions and transpositions are each + * treated as an edit distance of 1. + * + * Increasing the allowed edit distance will have a dramatic impact + * on the performance of both creating and intersecting these TokenSets. + * It is advised to keep the edit distance less than 3. + * + * @param {string} str - The string to create the token set from. + * @param {number} editDistance - The allowed edit distance to match. + * @returns {lunr.Vector} + */ +lunr.TokenSet.fromFuzzyString = function (str, editDistance) { + var root = new lunr.TokenSet + + var stack = [{ + node: root, + editsRemaining: editDistance, + str: str + }] + + while (stack.length) { + var frame = stack.pop() + + // no edit + if (frame.str.length > 0) { + var char = frame.str.charAt(0), + noEditNode + + if (char in frame.node.edges) { + noEditNode = frame.node.edges[char] + } else { + noEditNode = new lunr.TokenSet + frame.node.edges[char] = noEditNode + } + + if (frame.str.length == 1) { + noEditNode.final = true + } + + stack.push({ + node: noEditNode, + editsRemaining: frame.editsRemaining, + str: frame.str.slice(1) + }) + } + + if (frame.editsRemaining == 0) { + continue + } + + // insertion + if ("*" in frame.node.edges) { + var insertionNode = frame.node.edges["*"] + } else { + var insertionNode = new lunr.TokenSet + frame.node.edges["*"] = insertionNode + } + + if (frame.str.length == 0) { + insertionNode.final = true + } + + stack.push({ + node: insertionNode, + editsRemaining: frame.editsRemaining - 1, + str: frame.str + }) + + // deletion + // can only do a deletion if we have enough edits remaining + // and if there are characters left to delete in the string + if (frame.str.length > 1) { + stack.push({ + node: frame.node, + editsRemaining: frame.editsRemaining - 1, + str: frame.str.slice(1) + }) + } + + // deletion + // just removing the last character from the str + if (frame.str.length == 1) { + frame.node.final = true + } + + // substitution + // can only do a substitution if we have enough edits remaining + // and if there are characters left to substitute + if (frame.str.length >= 1) { + if ("*" in frame.node.edges) { + var substitutionNode = frame.node.edges["*"] + } else { + var substitutionNode = new lunr.TokenSet + frame.node.edges["*"] = substitutionNode + } + + if (frame.str.length == 1) { + substitutionNode.final = true + } + + stack.push({ + node: substitutionNode, + editsRemaining: frame.editsRemaining - 1, + str: frame.str.slice(1) + }) + } + + // transposition + // can only do a transposition if there are edits remaining + // and there are enough characters to transpose + if (frame.str.length > 1) { + var charA = frame.str.charAt(0), + charB = frame.str.charAt(1), + transposeNode + + if (charB in frame.node.edges) { + transposeNode = frame.node.edges[charB] + } else { + transposeNode = new lunr.TokenSet + frame.node.edges[charB] = transposeNode + } + + if (frame.str.length == 1) { + transposeNode.final = true + } + + stack.push({ + node: transposeNode, + editsRemaining: frame.editsRemaining - 1, + str: charA + frame.str.slice(2) + }) + } + } + + return root +} + +/** + * Creates a TokenSet from a string. + * + * The string may contain one or more wildcard characters (*) + * that will allow wildcard matching when intersecting with + * another TokenSet. + * + * @param {string} str - The string to create a TokenSet from. + * @returns {lunr.TokenSet} + */ +lunr.TokenSet.fromString = function (str) { + var node = new lunr.TokenSet, + root = node + + /* + * Iterates through all characters within the passed string + * appending a node for each character. + * + * When a wildcard character is found then a self + * referencing edge is introduced to continually match + * any number of any characters. + */ + for (var i = 0, len = str.length; i < len; i++) { + var char = str[i], + final = (i == len - 1) + + if (char == "*") { + node.edges[char] = node + node.final = final + + } else { + var next = new lunr.TokenSet + next.final = final + + node.edges[char] = next + node = next + } + } + + return root +} + +/** + * Converts this TokenSet into an array of strings + * contained within the TokenSet. + * + * This is not intended to be used on a TokenSet that + * contains wildcards, in these cases the results are + * undefined and are likely to cause an infinite loop. + * + * @returns {string[]} + */ +lunr.TokenSet.prototype.toArray = function () { + var words = [] + + var stack = [{ + prefix: "", + node: this + }] + + while (stack.length) { + var frame = stack.pop(), + edges = Object.keys(frame.node.edges), + len = edges.length + + if (frame.node.final) { + /* In Safari, at this point the prefix is sometimes corrupted, see: + * https://github.com/olivernn/lunr.js/issues/279 Calling any + * String.prototype method forces Safari to "cast" this string to what + * it's supposed to be, fixing the bug. */ + frame.prefix.charAt(0) + words.push(frame.prefix) + } + + for (var i = 0; i < len; i++) { + var edge = edges[i] + + stack.push({ + prefix: frame.prefix.concat(edge), + node: frame.node.edges[edge] + }) + } + } + + return words +} + +/** + * Generates a string representation of a TokenSet. + * + * This is intended to allow TokenSets to be used as keys + * in objects, largely to aid the construction and minimisation + * of a TokenSet. As such it is not designed to be a human + * friendly representation of the TokenSet. + * + * @returns {string} + */ +lunr.TokenSet.prototype.toString = function () { + // NOTE: Using Object.keys here as this.edges is very likely + // to enter 'hash-mode' with many keys being added + // + // avoiding a for-in loop here as it leads to the function + // being de-optimised (at least in V8). From some simple + // benchmarks the performance is comparable, but allowing + // V8 to optimize may mean easy performance wins in the future. + + if (this._str) { + return this._str + } + + var str = this.final ? '1' : '0', + labels = Object.keys(this.edges).sort(), + len = labels.length + + for (var i = 0; i < len; i++) { + var label = labels[i], + node = this.edges[label] + + str = str + label + node.id + } + + return str +} + +/** + * Returns a new TokenSet that is the intersection of + * this TokenSet and the passed TokenSet. + * + * This intersection will take into account any wildcards + * contained within the TokenSet. + * + * @param {lunr.TokenSet} b - An other TokenSet to intersect with. + * @returns {lunr.TokenSet} + */ +lunr.TokenSet.prototype.intersect = function (b) { + var output = new lunr.TokenSet, + frame = undefined + + var stack = [{ + qNode: b, + output: output, + node: this + }] + + while (stack.length) { + frame = stack.pop() + + // NOTE: As with the #toString method, we are using + // Object.keys and a for loop instead of a for-in loop + // as both of these objects enter 'hash' mode, causing + // the function to be de-optimised in V8 + var qEdges = Object.keys(frame.qNode.edges), + qLen = qEdges.length, + nEdges = Object.keys(frame.node.edges), + nLen = nEdges.length + + for (var q = 0; q < qLen; q++) { + var qEdge = qEdges[q] + + for (var n = 0; n < nLen; n++) { + var nEdge = nEdges[n] + + if (nEdge == qEdge || qEdge == '*') { + var node = frame.node.edges[nEdge], + qNode = frame.qNode.edges[qEdge], + final = node.final && qNode.final, + next = undefined + + if (nEdge in frame.output.edges) { + // an edge already exists for this character + // no need to create a new node, just set the finality + // bit unless this node is already final + next = frame.output.edges[nEdge] + next.final = next.final || final + + } else { + // no edge exists yet, must create one + // set the finality bit and insert it + // into the output + next = new lunr.TokenSet + next.final = final + frame.output.edges[nEdge] = next + } + + stack.push({ + qNode: qNode, + output: next, + node: node + }) + } + } + } + } + + return output +} +lunr.TokenSet.Builder = function () { + this.previousWord = "" + this.root = new lunr.TokenSet + this.uncheckedNodes = [] + this.minimizedNodes = {} +} + +lunr.TokenSet.Builder.prototype.insert = function (word) { + var node, + commonPrefix = 0 + + if (word < this.previousWord) { + throw new Error ("Out of order word insertion") + } + + for (var i = 0; i < word.length && i < this.previousWord.length; i++) { + if (word[i] != this.previousWord[i]) break + commonPrefix++ + } + + this.minimize(commonPrefix) + + if (this.uncheckedNodes.length == 0) { + node = this.root + } else { + node = this.uncheckedNodes[this.uncheckedNodes.length - 1].child + } + + for (var i = commonPrefix; i < word.length; i++) { + var nextNode = new lunr.TokenSet, + char = word[i] + + node.edges[char] = nextNode + + this.uncheckedNodes.push({ + parent: node, + char: char, + child: nextNode + }) + + node = nextNode + } + + node.final = true + this.previousWord = word +} + +lunr.TokenSet.Builder.prototype.finish = function () { + this.minimize(0) +} + +lunr.TokenSet.Builder.prototype.minimize = function (downTo) { + for (var i = this.uncheckedNodes.length - 1; i >= downTo; i--) { + var node = this.uncheckedNodes[i], + childKey = node.child.toString() + + if (childKey in this.minimizedNodes) { + node.parent.edges[node.char] = this.minimizedNodes[childKey] + } else { + // Cache the key for this node since + // we know it can't change anymore + node.child._str = childKey + + this.minimizedNodes[childKey] = node.child + } + + this.uncheckedNodes.pop() + } +} +/*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * An index contains the built index of all documents and provides a query interface + * to the index. + * + * Usually instances of lunr.Index will not be created using this constructor, instead + * lunr.Builder should be used to construct new indexes, or lunr.Index.load should be + * used to load previously built and serialized indexes. + * + * @constructor + * @param {Object} attrs - The attributes of the built search index. + * @param {Object} attrs.invertedIndex - An index of term/field to document reference. + * @param {Object} attrs.fieldVectors - Field vectors + * @param {lunr.TokenSet} attrs.tokenSet - An set of all corpus tokens. + * @param {string[]} attrs.fields - The names of indexed document fields. + * @param {lunr.Pipeline} attrs.pipeline - The pipeline to use for search terms. + */ +lunr.Index = function (attrs) { + this.invertedIndex = attrs.invertedIndex + this.fieldVectors = attrs.fieldVectors + this.tokenSet = attrs.tokenSet + this.fields = attrs.fields + this.pipeline = attrs.pipeline +} + +/** + * A result contains details of a document matching a search query. + * @typedef {Object} lunr.Index~Result + * @property {string} ref - The reference of the document this result represents. + * @property {number} score - A number between 0 and 1 representing how similar this document is to the query. + * @property {lunr.MatchData} matchData - Contains metadata about this match including which term(s) caused the match. + */ + +/** + * Although lunr provides the ability to create queries using lunr.Query, it also provides a simple + * query language which itself is parsed into an instance of lunr.Query. + * + * For programmatically building queries it is advised to directly use lunr.Query, the query language + * is best used for human entered text rather than program generated text. + * + * At its simplest queries can just be a single term, e.g. `hello`, multiple terms are also supported + * and will be combined with OR, e.g `hello world` will match documents that contain either 'hello' + * or 'world', though those that contain both will rank higher in the results. + * + * Wildcards can be included in terms to match one or more unspecified characters, these wildcards can + * be inserted anywhere within the term, and more than one wildcard can exist in a single term. Adding + * wildcards will increase the number of documents that will be found but can also have a negative + * impact on query performance, especially with wildcards at the beginning of a term. + * + * Terms can be restricted to specific fields, e.g. `title:hello`, only documents with the term + * hello in the title field will match this query. Using a field not present in the index will lead + * to an error being thrown. + * + * Modifiers can also be added to terms, lunr supports edit distance and boost modifiers on terms. A term + * boost will make documents matching that term score higher, e.g. `foo^5`. Edit distance is also supported + * to provide fuzzy matching, e.g. 'hello~2' will match documents with hello with an edit distance of 2. + * Avoid large values for edit distance to improve query performance. + * + * Each term also supports a presence modifier. By default a term's presence in document is optional, however + * this can be changed to either required or prohibited. For a term's presence to be required in a document the + * term should be prefixed with a '+', e.g. `+foo bar` is a search for documents that must contain 'foo' and + * optionally contain 'bar'. Conversely a leading '-' sets the terms presence to prohibited, i.e. it must not + * appear in a document, e.g. `-foo bar` is a search for documents that do not contain 'foo' but may contain 'bar'. + * + * To escape special characters the backslash character '\' can be used, this allows searches to include + * characters that would normally be considered modifiers, e.g. `foo\~2` will search for a term "foo~2" instead + * of attempting to apply a boost of 2 to the search term "foo". + * + * @typedef {string} lunr.Index~QueryString + * @example Simple single term query + * hello + * @example Multiple term query + * hello world + * @example term scoped to a field + * title:hello + * @example term with a boost of 10 + * hello^10 + * @example term with an edit distance of 2 + * hello~2 + * @example terms with presence modifiers + * -foo +bar baz + */ + +/** + * Performs a search against the index using lunr query syntax. + * + * Results will be returned sorted by their score, the most relevant results + * will be returned first. For details on how the score is calculated, please see + * the {@link https://lunrjs.com/guides/searching.html#scoring|guide}. + * + * For more programmatic querying use lunr.Index#query. + * + * @param {lunr.Index~QueryString} queryString - A string containing a lunr query. + * @throws {lunr.QueryParseError} If the passed query string cannot be parsed. + * @returns {lunr.Index~Result[]} + */ +lunr.Index.prototype.search = function (queryString) { + return this.query(function (query) { + var parser = new lunr.QueryParser(queryString, query) + parser.parse() + }) +} + +/** + * A query builder callback provides a query object to be used to express + * the query to perform on the index. + * + * @callback lunr.Index~queryBuilder + * @param {lunr.Query} query - The query object to build up. + * @this lunr.Query + */ + +/** + * Performs a query against the index using the yielded lunr.Query object. + * + * If performing programmatic queries against the index, this method is preferred + * over lunr.Index#search so as to avoid the additional query parsing overhead. + * + * A query object is yielded to the supplied function which should be used to + * express the query to be run against the index. + * + * Note that although this function takes a callback parameter it is _not_ an + * asynchronous operation, the callback is just yielded a query object to be + * customized. + * + * @param {lunr.Index~queryBuilder} fn - A function that is used to build the query. + * @returns {lunr.Index~Result[]} + */ +lunr.Index.prototype.query = function (fn) { + // for each query clause + // * process terms + // * expand terms from token set + // * find matching documents and metadata + // * get document vectors + // * score documents + + var query = new lunr.Query(this.fields), + matchingFields = Object.create(null), + queryVectors = Object.create(null), + termFieldCache = Object.create(null), + requiredMatches = Object.create(null), + prohibitedMatches = Object.create(null) + + /* + * To support field level boosts a query vector is created per + * field. An empty vector is eagerly created to support negated + * queries. + */ + for (var i = 0; i < this.fields.length; i++) { + queryVectors[this.fields[i]] = new lunr.Vector + } + + fn.call(query, query) + + for (var i = 0; i < query.clauses.length; i++) { + /* + * Unless the pipeline has been disabled for this term, which is + * the case for terms with wildcards, we need to pass the clause + * term through the search pipeline. A pipeline returns an array + * of processed terms. Pipeline functions may expand the passed + * term, which means we may end up performing multiple index lookups + * for a single query term. + */ + var clause = query.clauses[i], + terms = null, + clauseMatches = lunr.Set.empty + + if (clause.usePipeline) { + terms = this.pipeline.runString(clause.term, { + fields: clause.fields + }) + } else { + terms = [clause.term] + } + + for (var m = 0; m < terms.length; m++) { + var term = terms[m] + + /* + * Each term returned from the pipeline needs to use the same query + * clause object, e.g. the same boost and or edit distance. The + * simplest way to do this is to re-use the clause object but mutate + * its term property. + */ + clause.term = term + + /* + * From the term in the clause we create a token set which will then + * be used to intersect the indexes token set to get a list of terms + * to lookup in the inverted index + */ + var termTokenSet = lunr.TokenSet.fromClause(clause), + expandedTerms = this.tokenSet.intersect(termTokenSet).toArray() + + /* + * If a term marked as required does not exist in the tokenSet it is + * impossible for the search to return any matches. We set all the field + * scoped required matches set to empty and stop examining any further + * clauses. + */ + if (expandedTerms.length === 0 && clause.presence === lunr.Query.presence.REQUIRED) { + for (var k = 0; k < clause.fields.length; k++) { + var field = clause.fields[k] + requiredMatches[field] = lunr.Set.empty + } + + break + } + + for (var j = 0; j < expandedTerms.length; j++) { + /* + * For each term get the posting and termIndex, this is required for + * building the query vector. + */ + var expandedTerm = expandedTerms[j], + posting = this.invertedIndex[expandedTerm], + termIndex = posting._index + + for (var k = 0; k < clause.fields.length; k++) { + /* + * For each field that this query term is scoped by (by default + * all fields are in scope) we need to get all the document refs + * that have this term in that field. + * + * The posting is the entry in the invertedIndex for the matching + * term from above. + */ + var field = clause.fields[k], + fieldPosting = posting[field], + matchingDocumentRefs = Object.keys(fieldPosting), + termField = expandedTerm + "/" + field, + matchingDocumentsSet = new lunr.Set(matchingDocumentRefs) + + /* + * if the presence of this term is required ensure that the matching + * documents are added to the set of required matches for this clause. + * + */ + if (clause.presence == lunr.Query.presence.REQUIRED) { + clauseMatches = clauseMatches.union(matchingDocumentsSet) + + if (requiredMatches[field] === undefined) { + requiredMatches[field] = lunr.Set.complete + } + } + + /* + * if the presence of this term is prohibited ensure that the matching + * documents are added to the set of prohibited matches for this field, + * creating that set if it does not yet exist. + */ + if (clause.presence == lunr.Query.presence.PROHIBITED) { + if (prohibitedMatches[field] === undefined) { + prohibitedMatches[field] = lunr.Set.empty + } + + prohibitedMatches[field] = prohibitedMatches[field].union(matchingDocumentsSet) + + /* + * Prohibited matches should not be part of the query vector used for + * similarity scoring and no metadata should be extracted so we continue + * to the next field + */ + continue + } + + /* + * The query field vector is populated using the termIndex found for + * the term and a unit value with the appropriate boost applied. + * Using upsert because there could already be an entry in the vector + * for the term we are working with. In that case we just add the scores + * together. + */ + queryVectors[field].upsert(termIndex, clause.boost, function (a, b) { return a + b }) + + /** + * If we've already seen this term, field combo then we've already collected + * the matching documents and metadata, no need to go through all that again + */ + if (termFieldCache[termField]) { + continue + } + + for (var l = 0; l < matchingDocumentRefs.length; l++) { + /* + * All metadata for this term/field/document triple + * are then extracted and collected into an instance + * of lunr.MatchData ready to be returned in the query + * results + */ + var matchingDocumentRef = matchingDocumentRefs[l], + matchingFieldRef = new lunr.FieldRef (matchingDocumentRef, field), + metadata = fieldPosting[matchingDocumentRef], + fieldMatch + + if ((fieldMatch = matchingFields[matchingFieldRef]) === undefined) { + matchingFields[matchingFieldRef] = new lunr.MatchData (expandedTerm, field, metadata) + } else { + fieldMatch.add(expandedTerm, field, metadata) + } + + } + + termFieldCache[termField] = true + } + } + } + + /** + * If the presence was required we need to update the requiredMatches field sets. + * We do this after all fields for the term have collected their matches because + * the clause terms presence is required in _any_ of the fields not _all_ of the + * fields. + */ + if (clause.presence === lunr.Query.presence.REQUIRED) { + for (var k = 0; k < clause.fields.length; k++) { + var field = clause.fields[k] + requiredMatches[field] = requiredMatches[field].intersect(clauseMatches) + } + } + } + + /** + * Need to combine the field scoped required and prohibited + * matching documents into a global set of required and prohibited + * matches + */ + var allRequiredMatches = lunr.Set.complete, + allProhibitedMatches = lunr.Set.empty + + for (var i = 0; i < this.fields.length; i++) { + var field = this.fields[i] + + if (requiredMatches[field]) { + allRequiredMatches = allRequiredMatches.intersect(requiredMatches[field]) + } + + if (prohibitedMatches[field]) { + allProhibitedMatches = allProhibitedMatches.union(prohibitedMatches[field]) + } + } + + var matchingFieldRefs = Object.keys(matchingFields), + results = [], + matches = Object.create(null) + + /* + * If the query is negated (contains only prohibited terms) + * we need to get _all_ fieldRefs currently existing in the + * index. This is only done when we know that the query is + * entirely prohibited terms to avoid any cost of getting all + * fieldRefs unnecessarily. + * + * Additionally, blank MatchData must be created to correctly + * populate the results. + */ + if (query.isNegated()) { + matchingFieldRefs = Object.keys(this.fieldVectors) + + for (var i = 0; i < matchingFieldRefs.length; i++) { + var matchingFieldRef = matchingFieldRefs[i] + var fieldRef = lunr.FieldRef.fromString(matchingFieldRef) + matchingFields[matchingFieldRef] = new lunr.MatchData + } + } + + for (var i = 0; i < matchingFieldRefs.length; i++) { + /* + * Currently we have document fields that match the query, but we + * need to return documents. The matchData and scores are combined + * from multiple fields belonging to the same document. + * + * Scores are calculated by field, using the query vectors created + * above, and combined into a final document score using addition. + */ + var fieldRef = lunr.FieldRef.fromString(matchingFieldRefs[i]), + docRef = fieldRef.docRef + + if (!allRequiredMatches.contains(docRef)) { + continue + } + + if (allProhibitedMatches.contains(docRef)) { + continue + } + + var fieldVector = this.fieldVectors[fieldRef], + score = queryVectors[fieldRef.fieldName].similarity(fieldVector), + docMatch + + if ((docMatch = matches[docRef]) !== undefined) { + docMatch.score += score + docMatch.matchData.combine(matchingFields[fieldRef]) + } else { + var match = { + ref: docRef, + score: score, + matchData: matchingFields[fieldRef] + } + matches[docRef] = match + results.push(match) + } + } + + /* + * Sort the results objects by score, highest first. + */ + return results.sort(function (a, b) { + return b.score - a.score + }) +} + +/** + * Prepares the index for JSON serialization. + * + * The schema for this JSON blob will be described in a + * separate JSON schema file. + * + * @returns {Object} + */ +lunr.Index.prototype.toJSON = function () { + var invertedIndex = Object.keys(this.invertedIndex) + .sort() + .map(function (term) { + return [term, this.invertedIndex[term]] + }, this) + + var fieldVectors = Object.keys(this.fieldVectors) + .map(function (ref) { + return [ref, this.fieldVectors[ref].toJSON()] + }, this) + + return { + version: lunr.version, + fields: this.fields, + fieldVectors: fieldVectors, + invertedIndex: invertedIndex, + pipeline: this.pipeline.toJSON() + } +} + +/** + * Loads a previously serialized lunr.Index + * + * @param {Object} serializedIndex - A previously serialized lunr.Index + * @returns {lunr.Index} + */ +lunr.Index.load = function (serializedIndex) { + var attrs = {}, + fieldVectors = {}, + serializedVectors = serializedIndex.fieldVectors, + invertedIndex = Object.create(null), + serializedInvertedIndex = serializedIndex.invertedIndex, + tokenSetBuilder = new lunr.TokenSet.Builder, + pipeline = lunr.Pipeline.load(serializedIndex.pipeline) + + if (serializedIndex.version != lunr.version) { + lunr.utils.warn("Version mismatch when loading serialised index. Current version of lunr '" + lunr.version + "' does not match serialized index '" + serializedIndex.version + "'") + } + + for (var i = 0; i < serializedVectors.length; i++) { + var tuple = serializedVectors[i], + ref = tuple[0], + elements = tuple[1] + + fieldVectors[ref] = new lunr.Vector(elements) + } + + for (var i = 0; i < serializedInvertedIndex.length; i++) { + var tuple = serializedInvertedIndex[i], + term = tuple[0], + posting = tuple[1] + + tokenSetBuilder.insert(term) + invertedIndex[term] = posting + } + + tokenSetBuilder.finish() + + attrs.fields = serializedIndex.fields + + attrs.fieldVectors = fieldVectors + attrs.invertedIndex = invertedIndex + attrs.tokenSet = tokenSetBuilder.root + attrs.pipeline = pipeline + + return new lunr.Index(attrs) +} +/*! + * lunr.Builder + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * lunr.Builder performs indexing on a set of documents and + * returns instances of lunr.Index ready for querying. + * + * All configuration of the index is done via the builder, the + * fields to index, the document reference, the text processing + * pipeline and document scoring parameters are all set on the + * builder before indexing. + * + * @constructor + * @property {string} _ref - Internal reference to the document reference field. + * @property {string[]} _fields - Internal reference to the document fields to index. + * @property {object} invertedIndex - The inverted index maps terms to document fields. + * @property {object} documentTermFrequencies - Keeps track of document term frequencies. + * @property {object} documentLengths - Keeps track of the length of documents added to the index. + * @property {lunr.tokenizer} tokenizer - Function for splitting strings into tokens for indexing. + * @property {lunr.Pipeline} pipeline - The pipeline performs text processing on tokens before indexing. + * @property {lunr.Pipeline} searchPipeline - A pipeline for processing search terms before querying the index. + * @property {number} documentCount - Keeps track of the total number of documents indexed. + * @property {number} _b - A parameter to control field length normalization, setting this to 0 disabled normalization, 1 fully normalizes field lengths, the default value is 0.75. + * @property {number} _k1 - A parameter to control how quickly an increase in term frequency results in term frequency saturation, the default value is 1.2. + * @property {number} termIndex - A counter incremented for each unique term, used to identify a terms position in the vector space. + * @property {array} metadataWhitelist - A list of metadata keys that have been whitelisted for entry in the index. + */ +lunr.Builder = function () { + this._ref = "id" + this._fields = Object.create(null) + this._documents = Object.create(null) + this.invertedIndex = Object.create(null) + this.fieldTermFrequencies = {} + this.fieldLengths = {} + this.tokenizer = lunr.tokenizer + this.pipeline = new lunr.Pipeline + this.searchPipeline = new lunr.Pipeline + this.documentCount = 0 + this._b = 0.75 + this._k1 = 1.2 + this.termIndex = 0 + this.metadataWhitelist = [] +} + +/** + * Sets the document field used as the document reference. Every document must have this field. + * The type of this field in the document should be a string, if it is not a string it will be + * coerced into a string by calling toString. + * + * The default ref is 'id'. + * + * The ref should _not_ be changed during indexing, it should be set before any documents are + * added to the index. Changing it during indexing can lead to inconsistent results. + * + * @param {string} ref - The name of the reference field in the document. + */ +lunr.Builder.prototype.ref = function (ref) { + this._ref = ref +} + +/** + * A function that is used to extract a field from a document. + * + * Lunr expects a field to be at the top level of a document, if however the field + * is deeply nested within a document an extractor function can be used to extract + * the right field for indexing. + * + * @callback fieldExtractor + * @param {object} doc - The document being added to the index. + * @returns {?(string|object|object[])} obj - The object that will be indexed for this field. + * @example Extracting a nested field + * function (doc) { return doc.nested.field } + */ + +/** + * Adds a field to the list of document fields that will be indexed. Every document being + * indexed should have this field. Null values for this field in indexed documents will + * not cause errors but will limit the chance of that document being retrieved by searches. + * + * All fields should be added before adding documents to the index. Adding fields after + * a document has been indexed will have no effect on already indexed documents. + * + * Fields can be boosted at build time. This allows terms within that field to have more + * importance when ranking search results. Use a field boost to specify that matches within + * one field are more important than other fields. + * + * @param {string} fieldName - The name of a field to index in all documents. + * @param {object} attributes - Optional attributes associated with this field. + * @param {number} [attributes.boost=1] - Boost applied to all terms within this field. + * @param {fieldExtractor} [attributes.extractor] - Function to extract a field from a document. + * @throws {RangeError} fieldName cannot contain unsupported characters '/' + */ +lunr.Builder.prototype.field = function (fieldName, attributes) { + if (/\//.test(fieldName)) { + throw new RangeError ("Field '" + fieldName + "' contains illegal character '/'") + } + + this._fields[fieldName] = attributes || {} +} + +/** + * A parameter to tune the amount of field length normalisation that is applied when + * calculating relevance scores. A value of 0 will completely disable any normalisation + * and a value of 1 will fully normalise field lengths. The default is 0.75. Values of b + * will be clamped to the range 0 - 1. + * + * @param {number} number - The value to set for this tuning parameter. + */ +lunr.Builder.prototype.b = function (number) { + if (number < 0) { + this._b = 0 + } else if (number > 1) { + this._b = 1 + } else { + this._b = number + } +} + +/** + * A parameter that controls the speed at which a rise in term frequency results in term + * frequency saturation. The default value is 1.2. Setting this to a higher value will give + * slower saturation levels, a lower value will result in quicker saturation. + * + * @param {number} number - The value to set for this tuning parameter. + */ +lunr.Builder.prototype.k1 = function (number) { + this._k1 = number +} + +/** + * Adds a document to the index. + * + * Before adding fields to the index the index should have been fully setup, with the document + * ref and all fields to index already having been specified. + * + * The document must have a field name as specified by the ref (by default this is 'id') and + * it should have all fields defined for indexing, though null or undefined values will not + * cause errors. + * + * Entire documents can be boosted at build time. Applying a boost to a document indicates that + * this document should rank higher in search results than other documents. + * + * @param {object} doc - The document to add to the index. + * @param {object} attributes - Optional attributes associated with this document. + * @param {number} [attributes.boost=1] - Boost applied to all terms within this document. + */ +lunr.Builder.prototype.add = function (doc, attributes) { + var docRef = doc[this._ref], + fields = Object.keys(this._fields) + + this._documents[docRef] = attributes || {} + this.documentCount += 1 + + for (var i = 0; i < fields.length; i++) { + var fieldName = fields[i], + extractor = this._fields[fieldName].extractor, + field = extractor ? extractor(doc) : doc[fieldName], + tokens = this.tokenizer(field, { + fields: [fieldName] + }), + terms = this.pipeline.run(tokens), + fieldRef = new lunr.FieldRef (docRef, fieldName), + fieldTerms = Object.create(null) + + this.fieldTermFrequencies[fieldRef] = fieldTerms + this.fieldLengths[fieldRef] = 0 + + // store the length of this field for this document + this.fieldLengths[fieldRef] += terms.length + + // calculate term frequencies for this field + for (var j = 0; j < terms.length; j++) { + var term = terms[j] + + if (fieldTerms[term] == undefined) { + fieldTerms[term] = 0 + } + + fieldTerms[term] += 1 + + // add to inverted index + // create an initial posting if one doesn't exist + if (this.invertedIndex[term] == undefined) { + var posting = Object.create(null) + posting["_index"] = this.termIndex + this.termIndex += 1 + + for (var k = 0; k < fields.length; k++) { + posting[fields[k]] = Object.create(null) + } + + this.invertedIndex[term] = posting + } + + // add an entry for this term/fieldName/docRef to the invertedIndex + if (this.invertedIndex[term][fieldName][docRef] == undefined) { + this.invertedIndex[term][fieldName][docRef] = Object.create(null) + } + + // store all whitelisted metadata about this token in the + // inverted index + for (var l = 0; l < this.metadataWhitelist.length; l++) { + var metadataKey = this.metadataWhitelist[l], + metadata = term.metadata[metadataKey] + + if (this.invertedIndex[term][fieldName][docRef][metadataKey] == undefined) { + this.invertedIndex[term][fieldName][docRef][metadataKey] = [] + } + + this.invertedIndex[term][fieldName][docRef][metadataKey].push(metadata) + } + } + + } +} + +/** + * Calculates the average document length for this index + * + * @private + */ +lunr.Builder.prototype.calculateAverageFieldLengths = function () { + + var fieldRefs = Object.keys(this.fieldLengths), + numberOfFields = fieldRefs.length, + accumulator = {}, + documentsWithField = {} + + for (var i = 0; i < numberOfFields; i++) { + var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]), + field = fieldRef.fieldName + + documentsWithField[field] || (documentsWithField[field] = 0) + documentsWithField[field] += 1 + + accumulator[field] || (accumulator[field] = 0) + accumulator[field] += this.fieldLengths[fieldRef] + } + + var fields = Object.keys(this._fields) + + for (var i = 0; i < fields.length; i++) { + var fieldName = fields[i] + accumulator[fieldName] = accumulator[fieldName] / documentsWithField[fieldName] + } + + this.averageFieldLength = accumulator +} + +/** + * Builds a vector space model of every document using lunr.Vector + * + * @private + */ +lunr.Builder.prototype.createFieldVectors = function () { + var fieldVectors = {}, + fieldRefs = Object.keys(this.fieldTermFrequencies), + fieldRefsLength = fieldRefs.length, + termIdfCache = Object.create(null) + + for (var i = 0; i < fieldRefsLength; i++) { + var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]), + fieldName = fieldRef.fieldName, + fieldLength = this.fieldLengths[fieldRef], + fieldVector = new lunr.Vector, + termFrequencies = this.fieldTermFrequencies[fieldRef], + terms = Object.keys(termFrequencies), + termsLength = terms.length + + + var fieldBoost = this._fields[fieldName].boost || 1, + docBoost = this._documents[fieldRef.docRef].boost || 1 + + for (var j = 0; j < termsLength; j++) { + var term = terms[j], + tf = termFrequencies[term], + termIndex = this.invertedIndex[term]._index, + idf, score, scoreWithPrecision + + if (termIdfCache[term] === undefined) { + idf = lunr.idf(this.invertedIndex[term], this.documentCount) + termIdfCache[term] = idf + } else { + idf = termIdfCache[term] + } + + score = idf * ((this._k1 + 1) * tf) / (this._k1 * (1 - this._b + this._b * (fieldLength / this.averageFieldLength[fieldName])) + tf) + score *= fieldBoost + score *= docBoost + scoreWithPrecision = Math.round(score * 1000) / 1000 + // Converts 1.23456789 to 1.234. + // Reducing the precision so that the vectors take up less + // space when serialised. Doing it now so that they behave + // the same before and after serialisation. Also, this is + // the fastest approach to reducing a number's precision in + // JavaScript. + + fieldVector.insert(termIndex, scoreWithPrecision) + } + + fieldVectors[fieldRef] = fieldVector + } + + this.fieldVectors = fieldVectors +} + +/** + * Creates a token set of all tokens in the index using lunr.TokenSet + * + * @private + */ +lunr.Builder.prototype.createTokenSet = function () { + this.tokenSet = lunr.TokenSet.fromArray( + Object.keys(this.invertedIndex).sort() + ) +} + +/** + * Builds the index, creating an instance of lunr.Index. + * + * This completes the indexing process and should only be called + * once all documents have been added to the index. + * + * @returns {lunr.Index} + */ +lunr.Builder.prototype.build = function () { + this.calculateAverageFieldLengths() + this.createFieldVectors() + this.createTokenSet() + + return new lunr.Index({ + invertedIndex: this.invertedIndex, + fieldVectors: this.fieldVectors, + tokenSet: this.tokenSet, + fields: Object.keys(this._fields), + pipeline: this.searchPipeline + }) +} + +/** + * Applies a plugin to the index builder. + * + * A plugin is a function that is called with the index builder as its context. + * Plugins can be used to customise or extend the behaviour of the index + * in some way. A plugin is just a function, that encapsulated the custom + * behaviour that should be applied when building the index. + * + * The plugin function will be called with the index builder as its argument, additional + * arguments can also be passed when calling use. The function will be called + * with the index builder as its context. + * + * @param {Function} plugin The plugin to apply. + */ +lunr.Builder.prototype.use = function (fn) { + var args = Array.prototype.slice.call(arguments, 1) + args.unshift(this) + fn.apply(this, args) +} +/** + * Contains and collects metadata about a matching document. + * A single instance of lunr.MatchData is returned as part of every + * lunr.Index~Result. + * + * @constructor + * @param {string} term - The term this match data is associated with + * @param {string} field - The field in which the term was found + * @param {object} metadata - The metadata recorded about this term in this field + * @property {object} metadata - A cloned collection of metadata associated with this document. + * @see {@link lunr.Index~Result} + */ +lunr.MatchData = function (term, field, metadata) { + var clonedMetadata = Object.create(null), + metadataKeys = Object.keys(metadata || {}) + + // Cloning the metadata to prevent the original + // being mutated during match data combination. + // Metadata is kept in an array within the inverted + // index so cloning the data can be done with + // Array#slice + for (var i = 0; i < metadataKeys.length; i++) { + var key = metadataKeys[i] + clonedMetadata[key] = metadata[key].slice() + } + + this.metadata = Object.create(null) + + if (term !== undefined) { + this.metadata[term] = Object.create(null) + this.metadata[term][field] = clonedMetadata + } +} + +/** + * An instance of lunr.MatchData will be created for every term that matches a + * document. However only one instance is required in a lunr.Index~Result. This + * method combines metadata from another instance of lunr.MatchData with this + * objects metadata. + * + * @param {lunr.MatchData} otherMatchData - Another instance of match data to merge with this one. + * @see {@link lunr.Index~Result} + */ +lunr.MatchData.prototype.combine = function (otherMatchData) { + var terms = Object.keys(otherMatchData.metadata) + + for (var i = 0; i < terms.length; i++) { + var term = terms[i], + fields = Object.keys(otherMatchData.metadata[term]) + + if (this.metadata[term] == undefined) { + this.metadata[term] = Object.create(null) + } + + for (var j = 0; j < fields.length; j++) { + var field = fields[j], + keys = Object.keys(otherMatchData.metadata[term][field]) + + if (this.metadata[term][field] == undefined) { + this.metadata[term][field] = Object.create(null) + } + + for (var k = 0; k < keys.length; k++) { + var key = keys[k] + + if (this.metadata[term][field][key] == undefined) { + this.metadata[term][field][key] = otherMatchData.metadata[term][field][key] + } else { + this.metadata[term][field][key] = this.metadata[term][field][key].concat(otherMatchData.metadata[term][field][key]) + } + + } + } + } +} + +/** + * Add metadata for a term/field pair to this instance of match data. + * + * @param {string} term - The term this match data is associated with + * @param {string} field - The field in which the term was found + * @param {object} metadata - The metadata recorded about this term in this field + */ +lunr.MatchData.prototype.add = function (term, field, metadata) { + if (!(term in this.metadata)) { + this.metadata[term] = Object.create(null) + this.metadata[term][field] = metadata + return + } + + if (!(field in this.metadata[term])) { + this.metadata[term][field] = metadata + return + } + + var metadataKeys = Object.keys(metadata) + + for (var i = 0; i < metadataKeys.length; i++) { + var key = metadataKeys[i] + + if (key in this.metadata[term][field]) { + this.metadata[term][field][key] = this.metadata[term][field][key].concat(metadata[key]) + } else { + this.metadata[term][field][key] = metadata[key] + } + } +} +/** + * A lunr.Query provides a programmatic way of defining queries to be performed + * against a {@link lunr.Index}. + * + * Prefer constructing a lunr.Query using the {@link lunr.Index#query} method + * so the query object is pre-initialized with the right index fields. + * + * @constructor + * @property {lunr.Query~Clause[]} clauses - An array of query clauses. + * @property {string[]} allFields - An array of all available fields in a lunr.Index. + */ +lunr.Query = function (allFields) { + this.clauses = [] + this.allFields = allFields +} + +/** + * Constants for indicating what kind of automatic wildcard insertion will be used when constructing a query clause. + * + * This allows wildcards to be added to the beginning and end of a term without having to manually do any string + * concatenation. + * + * The wildcard constants can be bitwise combined to select both leading and trailing wildcards. + * + * @constant + * @default + * @property {number} wildcard.NONE - The term will have no wildcards inserted, this is the default behaviour + * @property {number} wildcard.LEADING - Prepend the term with a wildcard, unless a leading wildcard already exists + * @property {number} wildcard.TRAILING - Append a wildcard to the term, unless a trailing wildcard already exists + * @see lunr.Query~Clause + * @see lunr.Query#clause + * @see lunr.Query#term + * @example query term with trailing wildcard + * query.term('foo', { wildcard: lunr.Query.wildcard.TRAILING }) + * @example query term with leading and trailing wildcard + * query.term('foo', { + * wildcard: lunr.Query.wildcard.LEADING | lunr.Query.wildcard.TRAILING + * }) + */ + +lunr.Query.wildcard = new String ("*") +lunr.Query.wildcard.NONE = 0 +lunr.Query.wildcard.LEADING = 1 +lunr.Query.wildcard.TRAILING = 2 + +/** + * Constants for indicating what kind of presence a term must have in matching documents. + * + * @constant + * @enum {number} + * @see lunr.Query~Clause + * @see lunr.Query#clause + * @see lunr.Query#term + * @example query term with required presence + * query.term('foo', { presence: lunr.Query.presence.REQUIRED }) + */ +lunr.Query.presence = { + /** + * Term's presence in a document is optional, this is the default value. + */ + OPTIONAL: 1, + + /** + * Term's presence in a document is required, documents that do not contain + * this term will not be returned. + */ + REQUIRED: 2, + + /** + * Term's presence in a document is prohibited, documents that do contain + * this term will not be returned. + */ + PROHIBITED: 3 +} + +/** + * A single clause in a {@link lunr.Query} contains a term and details on how to + * match that term against a {@link lunr.Index}. + * + * @typedef {Object} lunr.Query~Clause + * @property {string[]} fields - The fields in an index this clause should be matched against. + * @property {number} [boost=1] - Any boost that should be applied when matching this clause. + * @property {number} [editDistance] - Whether the term should have fuzzy matching applied, and how fuzzy the match should be. + * @property {boolean} [usePipeline] - Whether the term should be passed through the search pipeline. + * @property {number} [wildcard=lunr.Query.wildcard.NONE] - Whether the term should have wildcards appended or prepended. + * @property {number} [presence=lunr.Query.presence.OPTIONAL] - The terms presence in any matching documents. + */ + +/** + * Adds a {@link lunr.Query~Clause} to this query. + * + * Unless the clause contains the fields to be matched all fields will be matched. In addition + * a default boost of 1 is applied to the clause. + * + * @param {lunr.Query~Clause} clause - The clause to add to this query. + * @see lunr.Query~Clause + * @returns {lunr.Query} + */ +lunr.Query.prototype.clause = function (clause) { + if (!('fields' in clause)) { + clause.fields = this.allFields + } + + if (!('boost' in clause)) { + clause.boost = 1 + } + + if (!('usePipeline' in clause)) { + clause.usePipeline = true + } + + if (!('wildcard' in clause)) { + clause.wildcard = lunr.Query.wildcard.NONE + } + + if ((clause.wildcard & lunr.Query.wildcard.LEADING) && (clause.term.charAt(0) != lunr.Query.wildcard)) { + clause.term = "*" + clause.term + } + + if ((clause.wildcard & lunr.Query.wildcard.TRAILING) && (clause.term.slice(-1) != lunr.Query.wildcard)) { + clause.term = "" + clause.term + "*" + } + + if (!('presence' in clause)) { + clause.presence = lunr.Query.presence.OPTIONAL + } + + this.clauses.push(clause) + + return this +} + +/** + * A negated query is one in which every clause has a presence of + * prohibited. These queries require some special processing to return + * the expected results. + * + * @returns boolean + */ +lunr.Query.prototype.isNegated = function () { + for (var i = 0; i < this.clauses.length; i++) { + if (this.clauses[i].presence != lunr.Query.presence.PROHIBITED) { + return false + } + } + + return true +} + +/** + * Adds a term to the current query, under the covers this will create a {@link lunr.Query~Clause} + * to the list of clauses that make up this query. + * + * The term is used as is, i.e. no tokenization will be performed by this method. Instead conversion + * to a token or token-like string should be done before calling this method. + * + * The term will be converted to a string by calling `toString`. Multiple terms can be passed as an + * array, each term in the array will share the same options. + * + * @param {object|object[]} term - The term(s) to add to the query. + * @param {object} [options] - Any additional properties to add to the query clause. + * @returns {lunr.Query} + * @see lunr.Query#clause + * @see lunr.Query~Clause + * @example adding a single term to a query + * query.term("foo") + * @example adding a single term to a query and specifying search fields, term boost and automatic trailing wildcard + * query.term("foo", { + * fields: ["title"], + * boost: 10, + * wildcard: lunr.Query.wildcard.TRAILING + * }) + * @example using lunr.tokenizer to convert a string to tokens before using them as terms + * query.term(lunr.tokenizer("foo bar")) + */ +lunr.Query.prototype.term = function (term, options) { + if (Array.isArray(term)) { + term.forEach(function (t) { this.term(t, lunr.utils.clone(options)) }, this) + return this + } + + var clause = options || {} + clause.term = term.toString() + + this.clause(clause) + + return this +} +lunr.QueryParseError = function (message, start, end) { + this.name = "QueryParseError" + this.message = message + this.start = start + this.end = end +} + +lunr.QueryParseError.prototype = new Error +lunr.QueryLexer = function (str) { + this.lexemes = [] + this.str = str + this.length = str.length + this.pos = 0 + this.start = 0 + this.escapeCharPositions = [] +} + +lunr.QueryLexer.prototype.run = function () { + var state = lunr.QueryLexer.lexText + + while (state) { + state = state(this) + } +} + +lunr.QueryLexer.prototype.sliceString = function () { + var subSlices = [], + sliceStart = this.start, + sliceEnd = this.pos + + for (var i = 0; i < this.escapeCharPositions.length; i++) { + sliceEnd = this.escapeCharPositions[i] + subSlices.push(this.str.slice(sliceStart, sliceEnd)) + sliceStart = sliceEnd + 1 + } + + subSlices.push(this.str.slice(sliceStart, this.pos)) + this.escapeCharPositions.length = 0 + + return subSlices.join('') +} + +lunr.QueryLexer.prototype.emit = function (type) { + this.lexemes.push({ + type: type, + str: this.sliceString(), + start: this.start, + end: this.pos + }) + + this.start = this.pos +} + +lunr.QueryLexer.prototype.escapeCharacter = function () { + this.escapeCharPositions.push(this.pos - 1) + this.pos += 1 +} + +lunr.QueryLexer.prototype.next = function () { + if (this.pos >= this.length) { + return lunr.QueryLexer.EOS + } + + var char = this.str.charAt(this.pos) + this.pos += 1 + return char +} + +lunr.QueryLexer.prototype.width = function () { + return this.pos - this.start +} + +lunr.QueryLexer.prototype.ignore = function () { + if (this.start == this.pos) { + this.pos += 1 + } + + this.start = this.pos +} + +lunr.QueryLexer.prototype.backup = function () { + this.pos -= 1 +} + +lunr.QueryLexer.prototype.acceptDigitRun = function () { + var char, charCode + + do { + char = this.next() + charCode = char.charCodeAt(0) + } while (charCode > 47 && charCode < 58) + + if (char != lunr.QueryLexer.EOS) { + this.backup() + } +} + +lunr.QueryLexer.prototype.more = function () { + return this.pos < this.length +} + +lunr.QueryLexer.EOS = 'EOS' +lunr.QueryLexer.FIELD = 'FIELD' +lunr.QueryLexer.TERM = 'TERM' +lunr.QueryLexer.EDIT_DISTANCE = 'EDIT_DISTANCE' +lunr.QueryLexer.BOOST = 'BOOST' +lunr.QueryLexer.PRESENCE = 'PRESENCE' + +lunr.QueryLexer.lexField = function (lexer) { + lexer.backup() + lexer.emit(lunr.QueryLexer.FIELD) + lexer.ignore() + return lunr.QueryLexer.lexText +} + +lunr.QueryLexer.lexTerm = function (lexer) { + if (lexer.width() > 1) { + lexer.backup() + lexer.emit(lunr.QueryLexer.TERM) + } + + lexer.ignore() + + if (lexer.more()) { + return lunr.QueryLexer.lexText + } +} + +lunr.QueryLexer.lexEditDistance = function (lexer) { + lexer.ignore() + lexer.acceptDigitRun() + lexer.emit(lunr.QueryLexer.EDIT_DISTANCE) + return lunr.QueryLexer.lexText +} + +lunr.QueryLexer.lexBoost = function (lexer) { + lexer.ignore() + lexer.acceptDigitRun() + lexer.emit(lunr.QueryLexer.BOOST) + return lunr.QueryLexer.lexText +} + +lunr.QueryLexer.lexEOS = function (lexer) { + if (lexer.width() > 0) { + lexer.emit(lunr.QueryLexer.TERM) + } +} + +// This matches the separator used when tokenising fields +// within a document. These should match otherwise it is +// not possible to search for some tokens within a document. +// +// It is possible for the user to change the separator on the +// tokenizer so it _might_ clash with any other of the special +// characters already used within the search string, e.g. :. +// +// This means that it is possible to change the separator in +// such a way that makes some words unsearchable using a search +// string. +lunr.QueryLexer.termSeparator = lunr.tokenizer.separator + +lunr.QueryLexer.lexText = function (lexer) { + while (true) { + var char = lexer.next() + + if (char == lunr.QueryLexer.EOS) { + return lunr.QueryLexer.lexEOS + } + + // Escape character is '\' + if (char.charCodeAt(0) == 92) { + lexer.escapeCharacter() + continue + } + + if (char == ":") { + return lunr.QueryLexer.lexField + } + + if (char == "~") { + lexer.backup() + if (lexer.width() > 0) { + lexer.emit(lunr.QueryLexer.TERM) + } + return lunr.QueryLexer.lexEditDistance + } + + if (char == "^") { + lexer.backup() + if (lexer.width() > 0) { + lexer.emit(lunr.QueryLexer.TERM) + } + return lunr.QueryLexer.lexBoost + } + + // "+" indicates term presence is required + // checking for length to ensure that only + // leading "+" are considered + if (char == "+" && lexer.width() === 1) { + lexer.emit(lunr.QueryLexer.PRESENCE) + return lunr.QueryLexer.lexText + } + + // "-" indicates term presence is prohibited + // checking for length to ensure that only + // leading "-" are considered + if (char == "-" && lexer.width() === 1) { + lexer.emit(lunr.QueryLexer.PRESENCE) + return lunr.QueryLexer.lexText + } + + if (char.match(lunr.QueryLexer.termSeparator)) { + return lunr.QueryLexer.lexTerm + } + } +} + +lunr.QueryParser = function (str, query) { + this.lexer = new lunr.QueryLexer (str) + this.query = query + this.currentClause = {} + this.lexemeIdx = 0 +} + +lunr.QueryParser.prototype.parse = function () { + this.lexer.run() + this.lexemes = this.lexer.lexemes + + var state = lunr.QueryParser.parseClause + + while (state) { + state = state(this) + } + + return this.query +} + +lunr.QueryParser.prototype.peekLexeme = function () { + return this.lexemes[this.lexemeIdx] +} + +lunr.QueryParser.prototype.consumeLexeme = function () { + var lexeme = this.peekLexeme() + this.lexemeIdx += 1 + return lexeme +} + +lunr.QueryParser.prototype.nextClause = function () { + var completedClause = this.currentClause + this.query.clause(completedClause) + this.currentClause = {} +} + +lunr.QueryParser.parseClause = function (parser) { + var lexeme = parser.peekLexeme() + + if (lexeme == undefined) { + return + } + + switch (lexeme.type) { + case lunr.QueryLexer.PRESENCE: + return lunr.QueryParser.parsePresence + case lunr.QueryLexer.FIELD: + return lunr.QueryParser.parseField + case lunr.QueryLexer.TERM: + return lunr.QueryParser.parseTerm + default: + var errorMessage = "expected either a field or a term, found " + lexeme.type + + if (lexeme.str.length >= 1) { + errorMessage += " with value '" + lexeme.str + "'" + } + + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } +} + +lunr.QueryParser.parsePresence = function (parser) { + var lexeme = parser.consumeLexeme() + + if (lexeme == undefined) { + return + } + + switch (lexeme.str) { + case "-": + parser.currentClause.presence = lunr.Query.presence.PROHIBITED + break + case "+": + parser.currentClause.presence = lunr.Query.presence.REQUIRED + break + default: + var errorMessage = "unrecognised presence operator'" + lexeme.str + "'" + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } + + var nextLexeme = parser.peekLexeme() + + if (nextLexeme == undefined) { + var errorMessage = "expecting term or field, found nothing" + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } + + switch (nextLexeme.type) { + case lunr.QueryLexer.FIELD: + return lunr.QueryParser.parseField + case lunr.QueryLexer.TERM: + return lunr.QueryParser.parseTerm + default: + var errorMessage = "expecting term or field, found '" + nextLexeme.type + "'" + throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end) + } +} + +lunr.QueryParser.parseField = function (parser) { + var lexeme = parser.consumeLexeme() + + if (lexeme == undefined) { + return + } + + if (parser.query.allFields.indexOf(lexeme.str) == -1) { + var possibleFields = parser.query.allFields.map(function (f) { return "'" + f + "'" }).join(', '), + errorMessage = "unrecognised field '" + lexeme.str + "', possible fields: " + possibleFields + + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } + + parser.currentClause.fields = [lexeme.str] + + var nextLexeme = parser.peekLexeme() + + if (nextLexeme == undefined) { + var errorMessage = "expecting term, found nothing" + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } + + switch (nextLexeme.type) { + case lunr.QueryLexer.TERM: + return lunr.QueryParser.parseTerm + default: + var errorMessage = "expecting term, found '" + nextLexeme.type + "'" + throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end) + } +} + +lunr.QueryParser.parseTerm = function (parser) { + var lexeme = parser.consumeLexeme() + + if (lexeme == undefined) { + return + } + + parser.currentClause.term = lexeme.str.toLowerCase() + + if (lexeme.str.indexOf("*") != -1) { + parser.currentClause.usePipeline = false + } + + var nextLexeme = parser.peekLexeme() + + if (nextLexeme == undefined) { + parser.nextClause() + return + } + + switch (nextLexeme.type) { + case lunr.QueryLexer.TERM: + parser.nextClause() + return lunr.QueryParser.parseTerm + case lunr.QueryLexer.FIELD: + parser.nextClause() + return lunr.QueryParser.parseField + case lunr.QueryLexer.EDIT_DISTANCE: + return lunr.QueryParser.parseEditDistance + case lunr.QueryLexer.BOOST: + return lunr.QueryParser.parseBoost + case lunr.QueryLexer.PRESENCE: + parser.nextClause() + return lunr.QueryParser.parsePresence + default: + var errorMessage = "Unexpected lexeme type '" + nextLexeme.type + "'" + throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end) + } +} + +lunr.QueryParser.parseEditDistance = function (parser) { + var lexeme = parser.consumeLexeme() + + if (lexeme == undefined) { + return + } + + var editDistance = parseInt(lexeme.str, 10) + + if (isNaN(editDistance)) { + var errorMessage = "edit distance must be numeric" + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } + + parser.currentClause.editDistance = editDistance + + var nextLexeme = parser.peekLexeme() + + if (nextLexeme == undefined) { + parser.nextClause() + return + } + + switch (nextLexeme.type) { + case lunr.QueryLexer.TERM: + parser.nextClause() + return lunr.QueryParser.parseTerm + case lunr.QueryLexer.FIELD: + parser.nextClause() + return lunr.QueryParser.parseField + case lunr.QueryLexer.EDIT_DISTANCE: + return lunr.QueryParser.parseEditDistance + case lunr.QueryLexer.BOOST: + return lunr.QueryParser.parseBoost + case lunr.QueryLexer.PRESENCE: + parser.nextClause() + return lunr.QueryParser.parsePresence + default: + var errorMessage = "Unexpected lexeme type '" + nextLexeme.type + "'" + throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end) + } +} + +lunr.QueryParser.parseBoost = function (parser) { + var lexeme = parser.consumeLexeme() + + if (lexeme == undefined) { + return + } + + var boost = parseInt(lexeme.str, 10) + + if (isNaN(boost)) { + var errorMessage = "boost must be numeric" + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } + + parser.currentClause.boost = boost + + var nextLexeme = parser.peekLexeme() + + if (nextLexeme == undefined) { + parser.nextClause() + return + } + + switch (nextLexeme.type) { + case lunr.QueryLexer.TERM: + parser.nextClause() + return lunr.QueryParser.parseTerm + case lunr.QueryLexer.FIELD: + parser.nextClause() + return lunr.QueryParser.parseField + case lunr.QueryLexer.EDIT_DISTANCE: + return lunr.QueryParser.parseEditDistance + case lunr.QueryLexer.BOOST: + return lunr.QueryParser.parseBoost + case lunr.QueryLexer.PRESENCE: + parser.nextClause() + return lunr.QueryParser.parsePresence + default: + var errorMessage = "Unexpected lexeme type '" + nextLexeme.type + "'" + throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end) + } +} + + /** + * export the module via AMD, CommonJS or as a browser global + * Export code from https://github.com/umdjs/umd/blob/master/returnExports.js + */ + ;(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(factory) + } else if (typeof exports === 'object') { + /** + * Node. Does not work with strict CommonJS, but + * only CommonJS-like enviroments that support module.exports, + * like Node. + */ + module.exports = factory() + } else { + // Browser globals (root is window) + root.lunr = factory() + } + }(this, function () { + /** + * Just return a value to define the module export. + * This example returns an object, but the module + * can return a function as the exported value. + */ + return lunr + })) +})(); diff --git a/search/main.js b/search/main.js new file mode 100644 index 000000000..a5e469d7c --- /dev/null +++ b/search/main.js @@ -0,0 +1,109 @@ +function getSearchTermFromLocation() { + var sPageURL = window.location.search.substring(1); + var sURLVariables = sPageURL.split('&'); + for (var i = 0; i < sURLVariables.length; i++) { + var sParameterName = sURLVariables[i].split('='); + if (sParameterName[0] == 'q') { + return decodeURIComponent(sParameterName[1].replace(/\+/g, '%20')); + } + } +} + +function joinUrl (base, path) { + if (path.substring(0, 1) === "/") { + // path starts with `/`. Thus it is absolute. + return path; + } + if (base.substring(base.length-1) === "/") { + // base ends with `/` + return base + path; + } + return base + "/" + path; +} + +function escapeHtml (value) { + return value.replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>'); +} + +function formatResult (location, title, summary) { + return ''; +} + +function displayResults (results) { + var search_results = document.getElementById("mkdocs-search-results"); + while (search_results.firstChild) { + search_results.removeChild(search_results.firstChild); + } + if (results.length > 0){ + for (var i=0; i < results.length; i++){ + var result = results[i]; + var html = formatResult(result.location, result.title, result.summary); + search_results.insertAdjacentHTML('beforeend', html); + } + } else { + var noResultsText = search_results.getAttribute('data-no-results-text'); + if (!noResultsText) { + noResultsText = "No results found"; + } + search_results.insertAdjacentHTML('beforeend', '

' + noResultsText + '

'); + } +} + +function doSearch () { + var query = document.getElementById('mkdocs-search-query').value; + if (query.length > min_search_length) { + if (!window.Worker) { + displayResults(search(query)); + } else { + searchWorker.postMessage({query: query}); + } + } else { + // Clear results for short queries + displayResults([]); + } +} + +function initSearch () { + var search_input = document.getElementById('mkdocs-search-query'); + if (search_input) { + search_input.addEventListener("keyup", doSearch); + } + var term = getSearchTermFromLocation(); + if (term) { + search_input.value = term; + doSearch(); + } +} + +function onWorkerMessage (e) { + if (e.data.allowSearch) { + initSearch(); + } else if (e.data.results) { + var results = e.data.results; + displayResults(results); + } else if (e.data.config) { + min_search_length = e.data.config.min_search_length-1; + } +} + +if (!window.Worker) { + console.log('Web Worker API not supported'); + // load index in main thread + $.getScript(joinUrl(base_url, "search/worker.js")).done(function () { + console.log('Loaded worker'); + init(); + window.postMessage = function (msg) { + onWorkerMessage({data: msg}); + }; + }).fail(function (jqxhr, settings, exception) { + console.error('Could not load worker.js'); + }); +} else { + // Wrap search in a web worker + var searchWorker = new Worker(joinUrl(base_url, "search/worker.js")); + searchWorker.postMessage({init: true}); + searchWorker.onmessage = onWorkerMessage; +} diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 000000000..a75b33624 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Welcome to Drycc \u00b6 Drycc Workflow is an open source container cloud platform. Usually we also call it Container as a Service(CaaS) that adds a developer-friendly layer to any Kubernetes cluster, making it easy to deploy and manage applications. Drycc Workflow includes capabilities for building and deploying from source via git push , simple application configuration, creating and rolling back releases, managing domain names and SSL certificates, providing seamless edge routing, aggregating logs, and sharing applications with teams. All of this is exposed through a simple REST API and command line interface. Getting Started \u00b6 To get started with Workflow, follow our Quick Start guide. Take a deep dive into Drycc Workflow in our Concepts , Architecture , and Components sections. Feel like contibuting some code or want to get started as a maintainer? Pick an issue tagged as an easy fix or help wanted and start contributing! Service and Support \u00b6 Coming soon.","title":"Home"},{"location":"#welcome-to-drycc","text":"Drycc Workflow is an open source container cloud platform. Usually we also call it Container as a Service(CaaS) that adds a developer-friendly layer to any Kubernetes cluster, making it easy to deploy and manage applications. Drycc Workflow includes capabilities for building and deploying from source via git push , simple application configuration, creating and rolling back releases, managing domain names and SSL certificates, providing seamless edge routing, aggregating logs, and sharing applications with teams. All of this is exposed through a simple REST API and command line interface.","title":"Welcome to Drycc"},{"location":"#getting-started","text":"To get started with Workflow, follow our Quick Start guide. Take a deep dive into Drycc Workflow in our Concepts , Architecture , and Components sections. Feel like contibuting some code or want to get started as a maintainer? Pick an issue tagged as an easy fix or help wanted and start contributing!","title":"Getting Started"},{"location":"#service-and-support","text":"Coming soon.","title":"Service and Support"},{"location":"_includes/install-workflow/","text":"Check Your Setup \u00b6 First check that the helm command is available and the version is v2.5.0 or newer. $ helm version Client: &version.Version{SemVer:\"v2.5.0\", GitCommit:\"012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6\", GitTreeState:\"clean\"} Server: &version.Version{SemVer:\"v2.5.0\", GitCommit:\"012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6\", GitTreeState:\"clean\"} Ensure the kubectl client is installed and can connect to your Kubernetes cluster. Install Drycc Workflow \u00b6 Now that Helm is installed and the repository has been added, install Workflow by running: $ helm install drycc oci://registry.drycc.cc/charts/workflow --namespace drycc Helm will install a variety of Kubernetes resources in the drycc namespace. Wait for the pods that Helm launched to be ready. Monitor their status by running: $ kubectl --namespace=drycc get pods If it's preferred to have kubectl automatically update as the pod states change, run (type Ctrl-C to stop the watch): $ kubectl --namespace=drycc get pods -w Depending on the order in which the Workflow components initialize, some pods may restart. This is common during the installation: if a component's dependencies are not yet available, that component will exit and Kubernetes will automatically restart it. Here, it can be seen that the controller, builder and registry all took a few loops before they were able to start: $ kubectl --namespace=drycc get pods NAME READY STATUS RESTARTS AGE drycc-builder-hy3xv 1/1 Running 5 5m drycc-controller-g3cu8 1/1 Running 5 5m drycc-controller-celery-cmxxn 3/3 Running 0 5m drycc-database-rad1o 1/1 Running 0 5m drycc-logger-fluentbit-1v8uk 1/1 Running 0 5m drycc-logger-fluentbit-esm60 1/1 Running 0 5m drycc-logger-sm8b3 1/1 Running 0 5m drycc-storage-4ww3t 1/1 Running 0 5m drycc-registry-asozo 1/1 Running 1 5m drycc-rabbitmq-0 1/1 Running 0 5m Once all of the pods are in the READY state, Drycc Workflow is up and running!","title":"Install workflow"},{"location":"_includes/install-workflow/#check-your-setup","text":"First check that the helm command is available and the version is v2.5.0 or newer. $ helm version Client: &version.Version{SemVer:\"v2.5.0\", GitCommit:\"012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6\", GitTreeState:\"clean\"} Server: &version.Version{SemVer:\"v2.5.0\", GitCommit:\"012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6\", GitTreeState:\"clean\"} Ensure the kubectl client is installed and can connect to your Kubernetes cluster.","title":"Check Your Setup"},{"location":"_includes/install-workflow/#install-drycc-workflow","text":"Now that Helm is installed and the repository has been added, install Workflow by running: $ helm install drycc oci://registry.drycc.cc/charts/workflow --namespace drycc Helm will install a variety of Kubernetes resources in the drycc namespace. Wait for the pods that Helm launched to be ready. Monitor their status by running: $ kubectl --namespace=drycc get pods If it's preferred to have kubectl automatically update as the pod states change, run (type Ctrl-C to stop the watch): $ kubectl --namespace=drycc get pods -w Depending on the order in which the Workflow components initialize, some pods may restart. This is common during the installation: if a component's dependencies are not yet available, that component will exit and Kubernetes will automatically restart it. Here, it can be seen that the controller, builder and registry all took a few loops before they were able to start: $ kubectl --namespace=drycc get pods NAME READY STATUS RESTARTS AGE drycc-builder-hy3xv 1/1 Running 5 5m drycc-controller-g3cu8 1/1 Running 5 5m drycc-controller-celery-cmxxn 3/3 Running 0 5m drycc-database-rad1o 1/1 Running 0 5m drycc-logger-fluentbit-1v8uk 1/1 Running 0 5m drycc-logger-fluentbit-esm60 1/1 Running 0 5m drycc-logger-sm8b3 1/1 Running 0 5m drycc-storage-4ww3t 1/1 Running 0 5m drycc-registry-asozo 1/1 Running 1 5m drycc-rabbitmq-0 1/1 Running 0 5m Once all of the pods are in the READY state, Drycc Workflow is up and running!","title":"Install Drycc Workflow"},{"location":"applications/deploying-apps/","text":"Deploying an Application \u00b6 An Application is deployed to Drycc using git push or the drycc client. Supported Applications \u00b6 Drycc Workflow can deploy any application or service that can run inside a container. In order to be scaled horizontally, applications must follow the Twelve-Factor App methodology and store any application state in external backing services. For example, if your application persists state to the local filesystem -- common with content management systems like Wordpress and Drupal -- it cannot be scaled horizontally using drycc scale . Fortunately, most modern applications feature a stateless application tier that can scale horizontally inside Drycc. Login to the Controller \u00b6 Important if you haven't yet, now is a good time to install the client and register . Before deploying an application, users must first authenticate against the Drycc Controller using the URL supplied by their Drycc administrator. $ drycc login http://drycc.example.com Opening browser to http://drycc.example.com/v2/login/drycc/?key=4ccc81ee2dce4349ad5261ceffe72c71 Waiting for login... .o.Logged in as admin Configuration file written to /root/.drycc/client.json Select a Build Process \u00b6 Drycc Workflow supports three different ways of building applications: Buildpacks \u00b6 Cloud Native Buildpacks are useful if you want to follow cnb's docs for building applications. Learn how to deploy applications using Buildpacks . Dockerfiles \u00b6 Dockerfiles are a powerful way to define a portable execution environment built on a base OS of your choosing. Learn how to deploy applications using Dockerfiles . Container Image \u00b6 Deploying a Container image onto Drycc allows you to take a Container image from either a public or a private registry and copy it over bit-for-bit, ensuring that you are running the same image in development or in your CI pipeline as you are in production. Learn how to deploy applications using Container images . Tuning Application Settings \u00b6 It is possible to configure a few of the globally tunable settings on per application basis using config:set . Setting Description DRYCC_DISABLE_CACHE if set, this will disable the [imagebuilder cache][] (default: not set) DRYCC_DEPLOY_BATCHES the number of pods to bring up and take down sequentially during a scale (default: number of available nodes) DRYCC_DEPLOY_TIMEOUT deploy timeout in seconds per deploy batch (default: 120) IMAGE_PULL_POLICY the kubernetes [image pull policy][pull-policy] for application images (default: \"IfNotPresent\") (allowed values: \"Always\", \"IfNotPresent\") KUBERNETES_DEPLOYMENTS_REVISION_HISTORY_LIMIT how many revisions Kubernetes keeps around of a given Deployment (default: all revisions) KUBERNETES_POD_TERMINATION_GRACE_PERIOD_SECONDS how many seconds kubernetes waits for a pod to finish work after a SIGTERM before sending SIGKILL (default: 30) Deploy Timeout \u00b6 Deploy timeout in seconds - There are 2 deploy methods, Deployments (see below) and RC (versions prior to 2.4) and this setting affects those a bit differently. Deployments \u00b6 Deployments behave a little bit differently from the RC based deployment strategy. Kubernetes takes care of the entire deploy, doing rolling updates in the background. As a result, there is only an overall deployment timeout instead of a configurable per-batch timeout. The base timeout is multiplied with DRYCC_DEPLOY_BATCHES to create an overall timeout. This would be 240 (timeout) * 4 (batches) = 960 second overall timeout. RC deploy \u00b6 This deploy timeout defines how long to wait for each batch to complete in DRYCC_DEPLOY_BATCHES . Additions to the base timeout \u00b6 The base timeout is extended as well with healthchecks using initialDelaySeconds on liveness and readiness where the bigger of those two is applied. Additionally the timeout system accounts for slow image pulls by adding an additional 10 minutes when it has seen an image pull take over 1 minute. This allows the timeout values to be reasonable without having to account for image pull slowness in the base deploy timeout. Deployments \u00b6 Workflow uses Deployments for deploys. In prior versions ReplicationControllers were used with the ability to turn on Deployments via DRYCC_KUBERNETES_DEPLOYMENTS=1 . The advantage of Deployments is that rolling-updates will happen server-side in Kubernetes instead of in Drycc Workflow Controller, along with a few other Pod management related functionality. This allows a deploy to continue even when the CLI connection is interrupted. Behind the scenes your application deploy will be built up of a Deployment object per process type, each having multiple ReplicaSets (one per release) which in turn manage the Pods running your application. Drycc Workflow will behave the same way with DRYCC_KUBERNETES_DEPLOYMENTS enabled or disabled (only applicable to versions prior to 2.4). The changes are behind the scenes. Where you will see differences while using the CLI is drycc ps:list will output Pod names differently.","title":"Deploying Apps"},{"location":"applications/deploying-apps/#deploying-an-application","text":"An Application is deployed to Drycc using git push or the drycc client.","title":"Deploying an Application"},{"location":"applications/deploying-apps/#supported-applications","text":"Drycc Workflow can deploy any application or service that can run inside a container. In order to be scaled horizontally, applications must follow the Twelve-Factor App methodology and store any application state in external backing services. For example, if your application persists state to the local filesystem -- common with content management systems like Wordpress and Drupal -- it cannot be scaled horizontally using drycc scale . Fortunately, most modern applications feature a stateless application tier that can scale horizontally inside Drycc.","title":"Supported Applications"},{"location":"applications/deploying-apps/#login-to-the-controller","text":"Important if you haven't yet, now is a good time to install the client and register . Before deploying an application, users must first authenticate against the Drycc Controller using the URL supplied by their Drycc administrator. $ drycc login http://drycc.example.com Opening browser to http://drycc.example.com/v2/login/drycc/?key=4ccc81ee2dce4349ad5261ceffe72c71 Waiting for login... .o.Logged in as admin Configuration file written to /root/.drycc/client.json","title":"Login to the Controller"},{"location":"applications/deploying-apps/#select-a-build-process","text":"Drycc Workflow supports three different ways of building applications:","title":"Select a Build Process"},{"location":"applications/deploying-apps/#buildpacks","text":"Cloud Native Buildpacks are useful if you want to follow cnb's docs for building applications. Learn how to deploy applications using Buildpacks .","title":"Buildpacks"},{"location":"applications/deploying-apps/#dockerfiles","text":"Dockerfiles are a powerful way to define a portable execution environment built on a base OS of your choosing. Learn how to deploy applications using Dockerfiles .","title":"Dockerfiles"},{"location":"applications/deploying-apps/#container-image","text":"Deploying a Container image onto Drycc allows you to take a Container image from either a public or a private registry and copy it over bit-for-bit, ensuring that you are running the same image in development or in your CI pipeline as you are in production. Learn how to deploy applications using Container images .","title":"Container Image"},{"location":"applications/deploying-apps/#tuning-application-settings","text":"It is possible to configure a few of the globally tunable settings on per application basis using config:set . Setting Description DRYCC_DISABLE_CACHE if set, this will disable the [imagebuilder cache][] (default: not set) DRYCC_DEPLOY_BATCHES the number of pods to bring up and take down sequentially during a scale (default: number of available nodes) DRYCC_DEPLOY_TIMEOUT deploy timeout in seconds per deploy batch (default: 120) IMAGE_PULL_POLICY the kubernetes [image pull policy][pull-policy] for application images (default: \"IfNotPresent\") (allowed values: \"Always\", \"IfNotPresent\") KUBERNETES_DEPLOYMENTS_REVISION_HISTORY_LIMIT how many revisions Kubernetes keeps around of a given Deployment (default: all revisions) KUBERNETES_POD_TERMINATION_GRACE_PERIOD_SECONDS how many seconds kubernetes waits for a pod to finish work after a SIGTERM before sending SIGKILL (default: 30)","title":"Tuning Application Settings"},{"location":"applications/deploying-apps/#deploy-timeout","text":"Deploy timeout in seconds - There are 2 deploy methods, Deployments (see below) and RC (versions prior to 2.4) and this setting affects those a bit differently.","title":"Deploy Timeout"},{"location":"applications/deploying-apps/#deployments","text":"Deployments behave a little bit differently from the RC based deployment strategy. Kubernetes takes care of the entire deploy, doing rolling updates in the background. As a result, there is only an overall deployment timeout instead of a configurable per-batch timeout. The base timeout is multiplied with DRYCC_DEPLOY_BATCHES to create an overall timeout. This would be 240 (timeout) * 4 (batches) = 960 second overall timeout.","title":"Deployments"},{"location":"applications/deploying-apps/#rc-deploy","text":"This deploy timeout defines how long to wait for each batch to complete in DRYCC_DEPLOY_BATCHES .","title":"RC deploy"},{"location":"applications/deploying-apps/#additions-to-the-base-timeout","text":"The base timeout is extended as well with healthchecks using initialDelaySeconds on liveness and readiness where the bigger of those two is applied. Additionally the timeout system accounts for slow image pulls by adding an additional 10 minutes when it has seen an image pull take over 1 minute. This allows the timeout values to be reasonable without having to account for image pull slowness in the base deploy timeout.","title":"Additions to the base timeout"},{"location":"applications/deploying-apps/#deployments_1","text":"Workflow uses Deployments for deploys. In prior versions ReplicationControllers were used with the ability to turn on Deployments via DRYCC_KUBERNETES_DEPLOYMENTS=1 . The advantage of Deployments is that rolling-updates will happen server-side in Kubernetes instead of in Drycc Workflow Controller, along with a few other Pod management related functionality. This allows a deploy to continue even when the CLI connection is interrupted. Behind the scenes your application deploy will be built up of a Deployment object per process type, each having multiple ReplicaSets (one per release) which in turn manage the Pods running your application. Drycc Workflow will behave the same way with DRYCC_KUBERNETES_DEPLOYMENTS enabled or disabled (only applicable to versions prior to 2.4). The changes are behind the scenes. Where you will see differences while using the CLI is drycc ps:list will output Pod names differently.","title":"Deployments"},{"location":"applications/domains-and-routing/","text":"Domains and Routing \u00b6 You can use drycc domains to add or remove custom domains to the application: $ drycc domains:add hello.bacongobbler.com Adding hello.bacongobbler.com to finest-woodshed... done Once that's done, you can go into a DNS registrar and set up a CNAME from the new appname to the old one: $ dig hello.dryccapp.com [...] ;; ANSWER SECTION: hello.bacongobbler.com. 1759 IN CNAME finest-woodshed.dryccapp.com. finest-woodshed.dryccapp.com. 270 IN A 172.17.8.100 Note Setting a CNAME for a root domain can cause issues. Setting an @ record to be a CNAME causes all traffic to go to the other domain, including mail and the SOA (\"start-of-authority\") records. It is highly recommended that you bind a subdomain to an application, however you can work around this by pointing the @ record to the address of the load balancer (if any). To add or remove the application from the routing mesh, use drycc routing : $ drycc routing:disable Disabling routing for finest-woodshed... done This will make the application unreachable through the Router , but the application is still reachable internally through its Kubernetes Service . To re-enable routing: $ drycc routing:enable Enabling routing for finest-woodshed... done","title":"Domains and Routing"},{"location":"applications/domains-and-routing/#domains-and-routing","text":"You can use drycc domains to add or remove custom domains to the application: $ drycc domains:add hello.bacongobbler.com Adding hello.bacongobbler.com to finest-woodshed... done Once that's done, you can go into a DNS registrar and set up a CNAME from the new appname to the old one: $ dig hello.dryccapp.com [...] ;; ANSWER SECTION: hello.bacongobbler.com. 1759 IN CNAME finest-woodshed.dryccapp.com. finest-woodshed.dryccapp.com. 270 IN A 172.17.8.100 Note Setting a CNAME for a root domain can cause issues. Setting an @ record to be a CNAME causes all traffic to go to the other domain, including mail and the SOA (\"start-of-authority\") records. It is highly recommended that you bind a subdomain to an application, however you can work around this by pointing the @ record to the address of the load balancer (if any). To add or remove the application from the routing mesh, use drycc routing : $ drycc routing:disable Disabling routing for finest-woodshed... done This will make the application unreachable through the Router , but the application is still reachable internally through its Kubernetes Service . To re-enable routing: $ drycc routing:enable Enabling routing for finest-woodshed... done","title":"Domains and Routing"},{"location":"applications/inter-app-communication/","text":"Inter-app Communication \u00b6 A common architecture pattern of multi-process applications is to have one process serve public requests while having multiple other processes supporting the public one to, for example, perform actions on a schedule or process work items from a queue. To implement this system of apps in Drycc Workflow, set up the apps to communicate using DNS resolution, as shown above, and hide the supporting processes from public view by removing them from the Drycc Workflow router. DNS Service Discovery \u00b6 Drycc Workflow supports deploying a single app composed of a system of processes. Each Drycc Workflow app communicates on a single port, so communicating with another Workflow app means finding that app's address and port. All Workflow apps are mapped to port 80 externally, so finding its IP address is the only challenge. Workflow creates a Kubernetes Service for each app, which effectively assigns a name and one cluster-internal IP address to an app. The DNS service running in the cluster adds and removes DNS records which point from the app name to its IP address as services are added and removed. Drycc Workflow apps, then, can simply send requests to the domain name given to the service, which is \"app-name.app-namespace\".","title":"Inter-app Communication"},{"location":"applications/inter-app-communication/#inter-app-communication","text":"A common architecture pattern of multi-process applications is to have one process serve public requests while having multiple other processes supporting the public one to, for example, perform actions on a schedule or process work items from a queue. To implement this system of apps in Drycc Workflow, set up the apps to communicate using DNS resolution, as shown above, and hide the supporting processes from public view by removing them from the Drycc Workflow router.","title":"Inter-app Communication"},{"location":"applications/inter-app-communication/#dns-service-discovery","text":"Drycc Workflow supports deploying a single app composed of a system of processes. Each Drycc Workflow app communicates on a single port, so communicating with another Workflow app means finding that app's address and port. All Workflow apps are mapped to port 80 externally, so finding its IP address is the only challenge. Workflow creates a Kubernetes Service for each app, which effectively assigns a name and one cluster-internal IP address to an app. The DNS service running in the cluster adds and removes DNS records which point from the app name to its IP address as services are added and removed. Drycc Workflow apps, then, can simply send requests to the domain name given to the service, which is \"app-name.app-namespace\".","title":"DNS Service Discovery"},{"location":"applications/managing-app-configuration/","text":"Configuring an Application \u00b6 A Drycc application stores config in environment variables . Setting Environment Variables \u00b6 Use drycc config to modify environment variables for a deployed application. $ drycc help config Valid commands for config: config:list list environment variables for an app config:set set environment variables for an app config:unset unset environment variables for an app config:pull extract environment variables to .env config:push set environment variables from .env Use `drycc help [command]` to learn more. When config is changed, a new release is created and deployed automatically. You can set multiple environment variables with one drycc config:set command, or with drycc config:push and a local .env file. $ drycc config:set FOO=1 BAR=baz && drycc config:pull $ cat .env FOO=1 BAR=baz $ echo \"TIDE=high\" >> .env $ drycc config:push Creating config... done, v4 === yuppie-earthman DRYCC_APP: yuppie-earthman FOO: 1 BAR: baz TIDE: high Attach to Backing Services \u00b6 Drycc treats backing services like databases, caches and queues as attached resources . Attachments are performed using environment variables. For example, use drycc config to set a DATABASE_URL that attaches the application to an external PostgreSQL database. $ drycc config:set DATABASE_URL=postgres://user:pass@example.com:5432/db === peachy-waxworks DATABASE_URL: postgres://user:pass@example.com:5432/db Detachments can be performed with drycc config:unset . Buildpacks Cache \u00b6 By default, apps using the [Imagebuilder][] will reuse the latest image data. When deploying applications that depend on third-party libraries that have to be fetched, this could speed up deployments a lot. In order to make use of this, the buildpack must implement the cache by writing to the cache directory. Most buildpacks already implement this, but when using custom buildpacks, it might need to be changed to make full use of the cache. Disabling and re-enabling the cache \u00b6 In some cases, cache might not speed up your application. To disable caching, you can set the DRYCC_DISABLE_CACHE variable with drycc config:set DRYCC_DISABLE_CACHE=1 . When you disable the cache, Drycc will clear up files it created to store the cache. After having it turned off, run drycc config:unset DRYCC_DISABLE_CACHE to re-enable the cache. Clearing the cache \u00b6 Use the following procedure to clear the cache: $ drycc config:set DRYCC_DISABLE_CACHE=1 $ git commit --allow-empty -m \"Clearing Drycc cache\" $ git push drycc # (if you use a different remote, you should use your remote name) $ drycc config:unset DRYCC_DISABLE_CACHE Custom Health Checks \u00b6 By default, Workflow only checks that the application starts in their Container. If it is preferred to have Kubernetes respond to application health, a health check may be added by configuring a health check probe for the application. The health checks are implemented as Kubernetes container probes . A liveness and a readiness probe can be configured, and each probe can be of type httpGet , exec , or tcpSocket depending on the type of probe the container requires. A liveness probe is useful for applications running for long periods of time, eventually transitioning to broken states and cannot recover except by restarting them. Other times, a readiness probe is useful when the container is only temporarily unable to serve, and will recover on its own. In this case, if a container fails its readiness probe, the container will not be shut down, but rather the container will stop receiving incoming requests. httpGet probes are just as it sounds: it performs a HTTP GET operation on the Container. A response code inside the 200-399 range is considered a pass. exec probes run a command inside the Container to determine its health, such as cat /var/run/myapp.pid or a script that determines when the application is ready. An exit code of zero is considered a pass, while a non-zero status code is considered a fail. tcpSocket probes attempt to open a socket in the Container. The Container is only considered healthy if the check can establish a connection. tcpSocket probes accept a port number to perform the socket connection on the Container. Health checks can be configured on a per-proctype basis for each application using drycc healthchecks:set . If no type is mentioned then the health checks are applied to default proc types, web or cmd, whichever is present. To configure a httpGet liveness probe: $ drycc healthchecks:set liveness httpGet 80 --type cmd === peachy-waxworks Healthchecks cmd: Liveness -------- Initial Delay (seconds): 50 Timeout (seconds): 50 Period (seconds): 10 Success Threshold: 1 Failure Threshold: 3 Exec Probe: N/A HTTP GET Probe: Path=\"/\" Port=80 HTTPHeaders=[] TCP Socket Probe: N/A Readiness --------- No readiness probe configured. If the application relies on certain headers being set (such as the Host header) or a specific URL path relative to the root, you can also send specific HTTP headers: $ drycc healthchecks:set liveness httpGet 80 \\ --path /welcome/index.html \\ --headers \"X-Client-Version:v1.0,X-Foo:bar\" === peachy-waxworks Healthchecks web/cmd: Liveness -------- Initial Delay (seconds): 50 Timeout (seconds): 50 Period (seconds): 10 Success Threshold: 1 Failure Threshold: 3 Exec Probe: N/A HTTP GET Probe: Path=\"/welcome/index.html\" Port=80 HTTPHeaders=[X-Client-Version=v1.0] TCP Socket Probe: N/A Readiness --------- No readiness probe configured. To configure an exec readiness probe: $ drycc healthchecks:set readiness exec -- /bin/echo -n hello --type cmd === peachy-waxworks Healthchecks cmd: Liveness -------- No liveness probe configured. Readiness --------- Initial Delay (seconds): 50 Timeout (seconds): 50 Period (seconds): 10 Success Threshold: 1 Failure Threshold: 3 Exec Probe: Command=[/bin/echo -n hello] HTTP GET Probe: N/A TCP Socket Probe: N/A You can overwrite a probe by running drycc healthchecks:set again: $ drycc healthchecks:set readiness httpGet 80 --type cmd === peachy-waxworks Healthchecks cmd: Liveness -------- No liveness probe configured. Readiness --------- Initial Delay (seconds): 50 Timeout (seconds): 50 Period (seconds): 10 Success Threshold: 1 Failure Threshold: 3 Exec Probe: N/A HTTP GET Probe: Path=\"/\" Port=80 HTTPHeaders=[] TCP Socket Probe: N/A Configured health checks also modify the default application deploy behavior. When starting a new Pod, Workflow will wait for the health check to pass before moving onto the next Pod. Isolate the Application \u00b6 Workflow supports isolating applications onto a set of nodes using drycc tags . Note In order to use tags, you must first launch your cluster with the proper node labels. If you do not, tag commands will fail. Learn more by reading \"Assigning Pods to Nodes\" . Once your nodes are configured with appropriate label selectors, use drycc tags:set to restrict the application to those nodes: $ drycc tags:set environ=prod Applying tags... done, v4 environ prod","title":"Managing App Configuration"},{"location":"applications/managing-app-configuration/#configuring-an-application","text":"A Drycc application stores config in environment variables .","title":"Configuring an Application"},{"location":"applications/managing-app-configuration/#setting-environment-variables","text":"Use drycc config to modify environment variables for a deployed application. $ drycc help config Valid commands for config: config:list list environment variables for an app config:set set environment variables for an app config:unset unset environment variables for an app config:pull extract environment variables to .env config:push set environment variables from .env Use `drycc help [command]` to learn more. When config is changed, a new release is created and deployed automatically. You can set multiple environment variables with one drycc config:set command, or with drycc config:push and a local .env file. $ drycc config:set FOO=1 BAR=baz && drycc config:pull $ cat .env FOO=1 BAR=baz $ echo \"TIDE=high\" >> .env $ drycc config:push Creating config... done, v4 === yuppie-earthman DRYCC_APP: yuppie-earthman FOO: 1 BAR: baz TIDE: high","title":"Setting Environment Variables"},{"location":"applications/managing-app-configuration/#attach-to-backing-services","text":"Drycc treats backing services like databases, caches and queues as attached resources . Attachments are performed using environment variables. For example, use drycc config to set a DATABASE_URL that attaches the application to an external PostgreSQL database. $ drycc config:set DATABASE_URL=postgres://user:pass@example.com:5432/db === peachy-waxworks DATABASE_URL: postgres://user:pass@example.com:5432/db Detachments can be performed with drycc config:unset .","title":"Attach to Backing Services"},{"location":"applications/managing-app-configuration/#buildpacks-cache","text":"By default, apps using the [Imagebuilder][] will reuse the latest image data. When deploying applications that depend on third-party libraries that have to be fetched, this could speed up deployments a lot. In order to make use of this, the buildpack must implement the cache by writing to the cache directory. Most buildpacks already implement this, but when using custom buildpacks, it might need to be changed to make full use of the cache.","title":"Buildpacks Cache"},{"location":"applications/managing-app-configuration/#disabling-and-re-enabling-the-cache","text":"In some cases, cache might not speed up your application. To disable caching, you can set the DRYCC_DISABLE_CACHE variable with drycc config:set DRYCC_DISABLE_CACHE=1 . When you disable the cache, Drycc will clear up files it created to store the cache. After having it turned off, run drycc config:unset DRYCC_DISABLE_CACHE to re-enable the cache.","title":"Disabling and re-enabling the cache"},{"location":"applications/managing-app-configuration/#clearing-the-cache","text":"Use the following procedure to clear the cache: $ drycc config:set DRYCC_DISABLE_CACHE=1 $ git commit --allow-empty -m \"Clearing Drycc cache\" $ git push drycc # (if you use a different remote, you should use your remote name) $ drycc config:unset DRYCC_DISABLE_CACHE","title":"Clearing the cache"},{"location":"applications/managing-app-configuration/#custom-health-checks","text":"By default, Workflow only checks that the application starts in their Container. If it is preferred to have Kubernetes respond to application health, a health check may be added by configuring a health check probe for the application. The health checks are implemented as Kubernetes container probes . A liveness and a readiness probe can be configured, and each probe can be of type httpGet , exec , or tcpSocket depending on the type of probe the container requires. A liveness probe is useful for applications running for long periods of time, eventually transitioning to broken states and cannot recover except by restarting them. Other times, a readiness probe is useful when the container is only temporarily unable to serve, and will recover on its own. In this case, if a container fails its readiness probe, the container will not be shut down, but rather the container will stop receiving incoming requests. httpGet probes are just as it sounds: it performs a HTTP GET operation on the Container. A response code inside the 200-399 range is considered a pass. exec probes run a command inside the Container to determine its health, such as cat /var/run/myapp.pid or a script that determines when the application is ready. An exit code of zero is considered a pass, while a non-zero status code is considered a fail. tcpSocket probes attempt to open a socket in the Container. The Container is only considered healthy if the check can establish a connection. tcpSocket probes accept a port number to perform the socket connection on the Container. Health checks can be configured on a per-proctype basis for each application using drycc healthchecks:set . If no type is mentioned then the health checks are applied to default proc types, web or cmd, whichever is present. To configure a httpGet liveness probe: $ drycc healthchecks:set liveness httpGet 80 --type cmd === peachy-waxworks Healthchecks cmd: Liveness -------- Initial Delay (seconds): 50 Timeout (seconds): 50 Period (seconds): 10 Success Threshold: 1 Failure Threshold: 3 Exec Probe: N/A HTTP GET Probe: Path=\"/\" Port=80 HTTPHeaders=[] TCP Socket Probe: N/A Readiness --------- No readiness probe configured. If the application relies on certain headers being set (such as the Host header) or a specific URL path relative to the root, you can also send specific HTTP headers: $ drycc healthchecks:set liveness httpGet 80 \\ --path /welcome/index.html \\ --headers \"X-Client-Version:v1.0,X-Foo:bar\" === peachy-waxworks Healthchecks web/cmd: Liveness -------- Initial Delay (seconds): 50 Timeout (seconds): 50 Period (seconds): 10 Success Threshold: 1 Failure Threshold: 3 Exec Probe: N/A HTTP GET Probe: Path=\"/welcome/index.html\" Port=80 HTTPHeaders=[X-Client-Version=v1.0] TCP Socket Probe: N/A Readiness --------- No readiness probe configured. To configure an exec readiness probe: $ drycc healthchecks:set readiness exec -- /bin/echo -n hello --type cmd === peachy-waxworks Healthchecks cmd: Liveness -------- No liveness probe configured. Readiness --------- Initial Delay (seconds): 50 Timeout (seconds): 50 Period (seconds): 10 Success Threshold: 1 Failure Threshold: 3 Exec Probe: Command=[/bin/echo -n hello] HTTP GET Probe: N/A TCP Socket Probe: N/A You can overwrite a probe by running drycc healthchecks:set again: $ drycc healthchecks:set readiness httpGet 80 --type cmd === peachy-waxworks Healthchecks cmd: Liveness -------- No liveness probe configured. Readiness --------- Initial Delay (seconds): 50 Timeout (seconds): 50 Period (seconds): 10 Success Threshold: 1 Failure Threshold: 3 Exec Probe: N/A HTTP GET Probe: Path=\"/\" Port=80 HTTPHeaders=[] TCP Socket Probe: N/A Configured health checks also modify the default application deploy behavior. When starting a new Pod, Workflow will wait for the health check to pass before moving onto the next Pod.","title":"Custom Health Checks"},{"location":"applications/managing-app-configuration/#isolate-the-application","text":"Workflow supports isolating applications onto a set of nodes using drycc tags . Note In order to use tags, you must first launch your cluster with the proper node labels. If you do not, tag commands will fail. Learn more by reading \"Assigning Pods to Nodes\" . Once your nodes are configured with appropriate label selectors, use drycc tags:set to restrict the application to those nodes: $ drycc tags:set environ=prod Applying tags... done, v4 environ prod","title":"Isolate the Application"},{"location":"applications/managing-app-gateway/","text":"About gateway for an Application \u00b6 A Gateway describes how traffic can be translated to Services within the cluster. That is, it defines a request for a way to translate traffic from somewhere that does not know about Kubernetes to somewhere that does. For example, traffic sent to a Kubernetes Service by a cloud load balancer, an in-cluster proxy, or an external hardware load balancer. While many use cases have client traffic originating \u201coutside\u201d the cluster, this is not a requirement. Create Gateway for an Application \u00b6 Gateway is a way of exposing services externally, which generates an external IP address to connect route and service. Create service for an Application \u00b6 Service is a way of exposing services internally, creating a service generates an internal DNS that can access procfile_type . Create Route for an Application \u00b6 A Gateway may be attached to one or more Route references which serve to direct traffic for a subset of traffic to a specific service.","title":"Managing App Gateway"},{"location":"applications/managing-app-gateway/#about-gateway-for-an-application","text":"A Gateway describes how traffic can be translated to Services within the cluster. That is, it defines a request for a way to translate traffic from somewhere that does not know about Kubernetes to somewhere that does. For example, traffic sent to a Kubernetes Service by a cloud load balancer, an in-cluster proxy, or an external hardware load balancer. While many use cases have client traffic originating \u201coutside\u201d the cluster, this is not a requirement.","title":"About gateway for an Application"},{"location":"applications/managing-app-gateway/#create-gateway-for-an-application","text":"Gateway is a way of exposing services externally, which generates an external IP address to connect route and service.","title":"Create Gateway for an Application"},{"location":"applications/managing-app-gateway/#create-service-for-an-application","text":"Service is a way of exposing services internally, creating a service generates an internal DNS that can access procfile_type .","title":"Create service for an Application"},{"location":"applications/managing-app-gateway/#create-route-for-an-application","text":"A Gateway may be attached to one or more Route references which serve to direct traffic for a subset of traffic to a specific service.","title":"Create Route for an Application"},{"location":"applications/managing-app-lifecycle/","text":"Managing an Application \u00b6 Track Application Changes \u00b6 Drycc Workflow tracks all changes to your application. Application changes are the result of either new application code pushed to the platform (via git push drycc master ), or an update to application configuration (via drycc config:set KEY=VAL ). Each time a build or config change is made to your application a new release is created. These release numbers increase monotonically. You can see a record of changes to your application using drycc releases : $ drycc releases === peachy-waxworks Releases v4 3 minutes ago gabrtv deployed d3ccc05 v3 1 hour 17 minutes ago gabrtv added DATABASE_URL v2 6 hours 2 minutes ago gabrtv deployed 7cb3321 v1 6 hours 2 minutes ago gabrtv deployed drycc/helloworld Rollback a Release \u00b6 Drycc Workflow also supports rolling back go previous releases. If buggy code or an errant configuration change is pushed to your application, you may rollback to a previously known, good release. Note All rollbacks create a new, numbered release. But will reference the build/code and configuration from the desired rollback point. In this example, the application is currently running release v4. Using drycc rollback v2 tells Workflow to deploy the build and configuration that was used for release v2. This creates a new release named v5 whose contents are the source and configuration from release v2: $ drycc releases === folksy-offshoot Releases v4 4 minutes ago gabrtv deployed d3ccc05 v3 1 hour 18 minutes ago gabrtv added DATABASE_URL v2 6 hours 2 minutes ago gabrtv deployed 7cb3321 v1 6 hours 3 minutes ago gabrtv deployed drycc/helloworld $ drycc rollback v2 Rolled back to v2 $ drycc releases === folksy-offshoot Releases v5 Just now gabrtv rolled back to v2 v4 4 minutes ago gabrtv deployed d3ccc05 v3 1 hour 18 minutes ago gabrtv added DATABASE_URL v2 6 hours 2 minutes ago gabrtv deployed 7cb3321 v1 6 hours 3 minutes ago gabrtv deployed drycc/helloworld Run One-off Administration Tasks \u00b6 Drycc applications use one-off processes for admin tasks like database migrations and other commands that must run against the live application. Use drycc run to execute commands on the deployed application. $ drycc run 'ls -l' Running `ls -l`... total 28 -rw-r--r-- 1 root root 553 Dec 2 23:59 LICENSE -rw-r--r-- 1 root root 60 Dec 2 23:59 Procfile -rw-r--r-- 1 root root 33 Dec 2 23:59 README.md -rw-r--r-- 1 root root 1622 Dec 2 23:59 pom.xml drwxr-xr-x 3 root root 4096 Dec 2 23:59 src -rw-r--r-- 1 root root 25 Dec 2 23:59 system.properties drwxr-xr-x 6 root root 4096 Dec 3 00:00 target Share an Application \u00b6 Use drycc perms:create to allow another Drycc user to collaborate on your application. $ drycc perms:create otheruser Adding otheruser to peachy-waxworks collaborators... done Use drycc perms to see who an application is currently shared with, and drycc perms:delete to remove a collaborator. Note Collaborators can do anything with an application that its owner can do, except delete the application. When working with an application that has been shared with you, clone the original repository and add Drycc' git remote entry before attempting to git push any changes to Drycc. $ git clone https://github.com/drycc/example-java-jetty.git Cloning into 'example-java-jetty'... done $ cd example-java-jetty $ git remote add -f drycc ssh://git@local3.dryccapp.com:2222/peachy-waxworks.git Updating drycc From drycc-controller.local:peachy-waxworks * [new branch] master -> drycc/master Application Troubleshooting \u00b6 Applications deployed on Drycc Workflow treat logs as event streams . Drycc Workflow aggregates stdout and stderr from every Container making it easy to troubleshoot problems with your application. Use drycc logs to view the log output from your deployed application. $ drycc logs -f Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.5]: INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null} Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.8]: INFO:oejs.Server:jetty-7.6.0.v20120127 Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.5]: INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:10005 Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.6]: INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null} Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.7]: INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null} Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.6]: INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:10006 Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.8]: INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null} Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.7]: INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:10007 Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.8]: INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:10008","title":"Managing App Lifecycle"},{"location":"applications/managing-app-lifecycle/#managing-an-application","text":"","title":"Managing an Application"},{"location":"applications/managing-app-lifecycle/#track-application-changes","text":"Drycc Workflow tracks all changes to your application. Application changes are the result of either new application code pushed to the platform (via git push drycc master ), or an update to application configuration (via drycc config:set KEY=VAL ). Each time a build or config change is made to your application a new release is created. These release numbers increase monotonically. You can see a record of changes to your application using drycc releases : $ drycc releases === peachy-waxworks Releases v4 3 minutes ago gabrtv deployed d3ccc05 v3 1 hour 17 minutes ago gabrtv added DATABASE_URL v2 6 hours 2 minutes ago gabrtv deployed 7cb3321 v1 6 hours 2 minutes ago gabrtv deployed drycc/helloworld","title":"Track Application Changes"},{"location":"applications/managing-app-lifecycle/#rollback-a-release","text":"Drycc Workflow also supports rolling back go previous releases. If buggy code or an errant configuration change is pushed to your application, you may rollback to a previously known, good release. Note All rollbacks create a new, numbered release. But will reference the build/code and configuration from the desired rollback point. In this example, the application is currently running release v4. Using drycc rollback v2 tells Workflow to deploy the build and configuration that was used for release v2. This creates a new release named v5 whose contents are the source and configuration from release v2: $ drycc releases === folksy-offshoot Releases v4 4 minutes ago gabrtv deployed d3ccc05 v3 1 hour 18 minutes ago gabrtv added DATABASE_URL v2 6 hours 2 minutes ago gabrtv deployed 7cb3321 v1 6 hours 3 minutes ago gabrtv deployed drycc/helloworld $ drycc rollback v2 Rolled back to v2 $ drycc releases === folksy-offshoot Releases v5 Just now gabrtv rolled back to v2 v4 4 minutes ago gabrtv deployed d3ccc05 v3 1 hour 18 minutes ago gabrtv added DATABASE_URL v2 6 hours 2 minutes ago gabrtv deployed 7cb3321 v1 6 hours 3 minutes ago gabrtv deployed drycc/helloworld","title":"Rollback a Release"},{"location":"applications/managing-app-lifecycle/#run-one-off-administration-tasks","text":"Drycc applications use one-off processes for admin tasks like database migrations and other commands that must run against the live application. Use drycc run to execute commands on the deployed application. $ drycc run 'ls -l' Running `ls -l`... total 28 -rw-r--r-- 1 root root 553 Dec 2 23:59 LICENSE -rw-r--r-- 1 root root 60 Dec 2 23:59 Procfile -rw-r--r-- 1 root root 33 Dec 2 23:59 README.md -rw-r--r-- 1 root root 1622 Dec 2 23:59 pom.xml drwxr-xr-x 3 root root 4096 Dec 2 23:59 src -rw-r--r-- 1 root root 25 Dec 2 23:59 system.properties drwxr-xr-x 6 root root 4096 Dec 3 00:00 target","title":"Run One-off Administration Tasks"},{"location":"applications/managing-app-lifecycle/#share-an-application","text":"Use drycc perms:create to allow another Drycc user to collaborate on your application. $ drycc perms:create otheruser Adding otheruser to peachy-waxworks collaborators... done Use drycc perms to see who an application is currently shared with, and drycc perms:delete to remove a collaborator. Note Collaborators can do anything with an application that its owner can do, except delete the application. When working with an application that has been shared with you, clone the original repository and add Drycc' git remote entry before attempting to git push any changes to Drycc. $ git clone https://github.com/drycc/example-java-jetty.git Cloning into 'example-java-jetty'... done $ cd example-java-jetty $ git remote add -f drycc ssh://git@local3.dryccapp.com:2222/peachy-waxworks.git Updating drycc From drycc-controller.local:peachy-waxworks * [new branch] master -> drycc/master","title":"Share an Application"},{"location":"applications/managing-app-lifecycle/#application-troubleshooting","text":"Applications deployed on Drycc Workflow treat logs as event streams . Drycc Workflow aggregates stdout and stderr from every Container making it easy to troubleshoot problems with your application. Use drycc logs to view the log output from your deployed application. $ drycc logs -f Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.5]: INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null} Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.8]: INFO:oejs.Server:jetty-7.6.0.v20120127 Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.5]: INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:10005 Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.6]: INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null} Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.7]: INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null} Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.6]: INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:10006 Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.8]: INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null} Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.7]: INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:10007 Dec 3 00:30:31 ip-10-250-15-201 peachy-waxworks[web.8]: INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:10008","title":"Application Troubleshooting"},{"location":"applications/managing-app-processes/","text":"Managing Application Processes \u00b6 Drycc Workflow manages your application as a set of processes that can be named, scaled and configured according to their role. This gives you the flexibility to easily manage the different facets of your application. For example, you may have web-facing processes that handle HTTP traffic, background worker processes that do async work, and a helper process that streams from the Twitter API. By using a Procfile, either checked in to your application or provided via the CLI you can specify the name of the type and the application command that should run. To spawn other process types, use drycc scale = to scale those types accordingly. Default Process Types \u00b6 In the absence of a Procfile, a single, default process type is assumed for each application. Applications built using Buildpacks via git push implicitly receive a web process type, which starts the application server. Rails 4, for example, has the following process type: web: bundle exec rails server -p $PORT All applications utilizing Dockerfiles have an implied cmd process type, which runs the Dockerfile's CMD directive unmodified: $ cat Dockerfile FROM centos:latest COPY . /app WORKDIR /app CMD python -m SimpleHTTPServer 5000 EXPOSE 5000 For the above Dockerfile-based application, the cmd process type would run the Container CMD of python -m SimpleHTTPServer 5000 . Applications utilizing remote Container images , a cmd process type is also implied, and runs the CMD specified in the Container image. Note The web and cmd process types are special as they\u2019re the only process types that will receive HTTP traffic from Workflow\u2019s routers. Other process types can be named arbitrarily. Declaring Process Types \u00b6 If you use Buildpack or Dockerfile builds and want to override or specify additional process types, simply include a file named Procfile in the root of your application's source tree. The format of a Procfile is one process type per line, with each line containing the command to invoke: : The syntax is defined as: \u2013 a lowercase alphanumeric string, is a name for your command, such as web, worker, urgentworker, clock, etc. \u2013 a command line to launch the process, such as rake jobs:work . This example Procfile specifies two types, web and sleeper . The web process launches a web server on port 5000 and a simple process which sleeps for 900 seconds and exits. $ cat Procfile web: bundle exec ruby web.rb -p ${PORT:-5000} sleeper: sleep 900 If you are using remote Container images , you may define process types by either running drycc pull with a Procfile in your working directory, or by passing a stringified Procfile to the --procfile CLI option. For example, passing process types inline: $ drycc pull drycc/example-go:latest --procfile=\"cmd: /app/bin/boot\" Read a Procfile in another directory: $ drycc pull drycc/example-go:latest --procfile=\"$(cat deploy/Procfile)\" Or via a Procfile located in your current, working directory: $ cat Procfile cmd: /bin/boot sleeper: echo \"sleeping\"; sleep 900 $ drycc pull -a steely-mainsail drycc/example-go Creating build... done $ drycc scale sleeper=1 -a steely-mainsail Scaling processes... but first, coffee! done in 0s === steely-mainsail Processes --- cmd (started): 1 steely-mainsail-cmd-3291896318-nyrim up (v3) --- sleeper (started): 1 steely-mainsail-sleeper-3291896318-oq1jr up (v3) Note Only process types of web and cmd will be scaled to 1 automatically. If you have additional process types remember to scale the process counts after creation. To remove a process type simply scale it to 0: $ drycc scale sleeper=0 -a steely-mainsail Scaling processes... but first, coffee! done in 3s === steely-mainsail Processes --- cmd (started): 1 steely-mainsail-cmd-3291896318-nyrim up (v3) --- sleeper (started): 0 Scaling Processes \u00b6 Applications deployed on Drycc Workflow scale out via the process model . Use drycc scale to control the number of containers that power your app. $ drycc scale cmd=5 -a iciest-waggoner Scaling processes... but first, coffee! done in 3s === iciest-waggoner Processes --- cmd (started): 5 iciest-waggoner-web-3291896318-09j0o up (v2) iciest-waggoner-web-3291896318-3r7kp up (v2) iciest-waggoner-web-3291896318-gc4xv up (v2) iciest-waggoner-web-3291896318-lviwo up (v2) iciest-waggoner-web-3291896318-kt7vu up (v2) If you have multiple process types for your application you may scale the process count for each type separately. For example, this allows you to manage web process independently from background workers. For more information on process types see our documentation for Managing App Processes . In this example, we are scaling the process type web to 5 but leaving the process type background with one worker. $ drycc scale web=5 Scaling processes... but first, coffee! done in 4s === scenic-icehouse Processes --- web (started): 5 scenic-icehouse-web-3291896318-7lord up (v2) scenic-icehouse-web-3291896318-jn957 up (v2) scenic-icehouse-web-3291896318-rsekj up (v2) scenic-icehouse-web-3291896318-vwhnh up (v2) scenic-icehouse-web-3291896318-vokg7 up (v2) --- background (started): 1 scenic-icehouse-web-3291896318-background-yf8kh up (v2) Note The default process type for Dockerfile and Container Image applications is 'cmd' rather than 'web'. Scaling a process down, by reducing the process count, sends a TERM signal to the processes, followed by a SIGKILL if they have not exited within 30 seconds. Depending on your application, scaling down may interrupt long-running HTTP client connections. For example, scaling from 5 processes to 3: $ drycc scale web=3 Scaling processes... but first, coffee! done in 1s === scenic-icehouse Processes --- background (started): 1 scenic-icehouse-web-3291896318-background-yf8kh up (v2) --- web (started): 3 scenic-icehouse-web-3291896318-7lord up (v2) scenic-icehouse-web-3291896318-rsekj up (v2) scenic-icehouse-web-3291896318-vokg7 up (v2) Get a Shell to a Running Container \u00b6 Verify that the container is running: # drycc ps === python-getting-started Processes --- web: python-getting-started-web-69b7d4bfdc-kl4xf up (v2) Get a shell to the running container: # drycc ps:exec python-getting-started-web-69b7d4bfdc-kl4xf -it -- bash In your shell, list the root directory: # Run this inside the container ls / Running individual commands in a container # drycc ps:exec python-getting-started-web-69b7d4bfdc-kl4xf -- date Use \"drycc ps --help\" for a list of global command-line (applies to all commands). Autoscale \u00b6 Autoscale allows adding a minimum and maximum number of pods on a per process type basis. This is accomplished by specifying a target CPU usage across all available pods. This feature is built on top of Horizontal Pod Autoscaling in Kubernetes or HPA for short. Note This is an alpha feature. It is recommended to be on the latest Kubernetes when using this feature. $ drycc autoscale:set web --min=3 --max=8 --cpu-percent=75 Applying autoscale settings for process type web on scenic-icehouse... done And then review the scaling rule that was created for web $ drycc autoscale:list === scenic-icehouse Autoscale --- web: Min Replicas: 3 Max Replicas: 8 CPU: 75% Remove scaling rule $ drycc autoscale:unset web Removing autoscale for process type web on scenic-icehouse... done For autoscaling to work CPU requests have to be specified on each application Pod (can be done via drycc limits --cpu ). This allows the autoscale policies to do the appropriate calculations and make decisions on when to scale up and down. Scale up can only happen if there was no rescaling within the last 3 minutes. Scale down will wait for 5 minutes from the last rescaling. That information and more can be found at HPA algorithm page . Web vs Cmd Process Types \u00b6 When deploying to Drycc Workflow using a Heroku Buildpack, Workflow boots the web process type to boot the application server. When you deploy an application that has a Dockerfile or uses Container images , Workflow boots the cmd process type. Both act similarly in that they are exposed to the router as web applications. However, the cmd process type is special because, if left undefined, it is equivalent to running the container without any additional arguments. (i.e. The process specified by the Dockerfile or Container image's CMD directive will be used.) If migrating an application from Heroku Buildpacks to a Container-based deployment, Workflow will not automatically convert the web process type to cmd . To do this, you'll have to manually scale down the old process type and scale the new process type up. Restarting an Application Processes \u00b6 If you need to restart an application process, you may use drycc ps:restart . Behind the scenes, Drycc Workflow instructs Kubernetes to terminate the old process and launch a new one in its place. $ drycc ps === scenic-icehouse Processes --- web (started): 3 scenic-icehouse-web-3291896318-7lord up (v2) scenic-icehouse-web-3291896318-rsekj up (v2) scenic-icehouse-web-3291896318-vokg7 up (v2) --- background (started): 1 scenic-icehouse-background-3291896318-yf8kh up (v2) $ drycc ps:restart scenic-icehouse-background-3291896318-yf8kh Restarting processes... but first, coffee! done in 6s === scenic-icehouse Processes --- background (started): 1 scenic-icehouse-background-3291896318-yd87g up (v2) Notice that the process name has changed from scenic-icehouse-background-3291896318-yf8kh to scenic-icehouse-background-3291896318-yd87g . In a multi-node Kubernetes cluster, this may also have the effect of scheduling the Pod to a new node.","title":"Managing App Processes"},{"location":"applications/managing-app-processes/#managing-application-processes","text":"Drycc Workflow manages your application as a set of processes that can be named, scaled and configured according to their role. This gives you the flexibility to easily manage the different facets of your application. For example, you may have web-facing processes that handle HTTP traffic, background worker processes that do async work, and a helper process that streams from the Twitter API. By using a Procfile, either checked in to your application or provided via the CLI you can specify the name of the type and the application command that should run. To spawn other process types, use drycc scale = to scale those types accordingly.","title":"Managing Application Processes"},{"location":"applications/managing-app-processes/#default-process-types","text":"In the absence of a Procfile, a single, default process type is assumed for each application. Applications built using Buildpacks via git push implicitly receive a web process type, which starts the application server. Rails 4, for example, has the following process type: web: bundle exec rails server -p $PORT All applications utilizing Dockerfiles have an implied cmd process type, which runs the Dockerfile's CMD directive unmodified: $ cat Dockerfile FROM centos:latest COPY . /app WORKDIR /app CMD python -m SimpleHTTPServer 5000 EXPOSE 5000 For the above Dockerfile-based application, the cmd process type would run the Container CMD of python -m SimpleHTTPServer 5000 . Applications utilizing remote Container images , a cmd process type is also implied, and runs the CMD specified in the Container image. Note The web and cmd process types are special as they\u2019re the only process types that will receive HTTP traffic from Workflow\u2019s routers. Other process types can be named arbitrarily.","title":"Default Process Types"},{"location":"applications/managing-app-processes/#declaring-process-types","text":"If you use Buildpack or Dockerfile builds and want to override or specify additional process types, simply include a file named Procfile in the root of your application's source tree. The format of a Procfile is one process type per line, with each line containing the command to invoke: : The syntax is defined as: \u2013 a lowercase alphanumeric string, is a name for your command, such as web, worker, urgentworker, clock, etc. \u2013 a command line to launch the process, such as rake jobs:work . This example Procfile specifies two types, web and sleeper . The web process launches a web server on port 5000 and a simple process which sleeps for 900 seconds and exits. $ cat Procfile web: bundle exec ruby web.rb -p ${PORT:-5000} sleeper: sleep 900 If you are using remote Container images , you may define process types by either running drycc pull with a Procfile in your working directory, or by passing a stringified Procfile to the --procfile CLI option. For example, passing process types inline: $ drycc pull drycc/example-go:latest --procfile=\"cmd: /app/bin/boot\" Read a Procfile in another directory: $ drycc pull drycc/example-go:latest --procfile=\"$(cat deploy/Procfile)\" Or via a Procfile located in your current, working directory: $ cat Procfile cmd: /bin/boot sleeper: echo \"sleeping\"; sleep 900 $ drycc pull -a steely-mainsail drycc/example-go Creating build... done $ drycc scale sleeper=1 -a steely-mainsail Scaling processes... but first, coffee! done in 0s === steely-mainsail Processes --- cmd (started): 1 steely-mainsail-cmd-3291896318-nyrim up (v3) --- sleeper (started): 1 steely-mainsail-sleeper-3291896318-oq1jr up (v3) Note Only process types of web and cmd will be scaled to 1 automatically. If you have additional process types remember to scale the process counts after creation. To remove a process type simply scale it to 0: $ drycc scale sleeper=0 -a steely-mainsail Scaling processes... but first, coffee! done in 3s === steely-mainsail Processes --- cmd (started): 1 steely-mainsail-cmd-3291896318-nyrim up (v3) --- sleeper (started): 0","title":"Declaring Process Types"},{"location":"applications/managing-app-processes/#scaling-processes","text":"Applications deployed on Drycc Workflow scale out via the process model . Use drycc scale to control the number of containers that power your app. $ drycc scale cmd=5 -a iciest-waggoner Scaling processes... but first, coffee! done in 3s === iciest-waggoner Processes --- cmd (started): 5 iciest-waggoner-web-3291896318-09j0o up (v2) iciest-waggoner-web-3291896318-3r7kp up (v2) iciest-waggoner-web-3291896318-gc4xv up (v2) iciest-waggoner-web-3291896318-lviwo up (v2) iciest-waggoner-web-3291896318-kt7vu up (v2) If you have multiple process types for your application you may scale the process count for each type separately. For example, this allows you to manage web process independently from background workers. For more information on process types see our documentation for Managing App Processes . In this example, we are scaling the process type web to 5 but leaving the process type background with one worker. $ drycc scale web=5 Scaling processes... but first, coffee! done in 4s === scenic-icehouse Processes --- web (started): 5 scenic-icehouse-web-3291896318-7lord up (v2) scenic-icehouse-web-3291896318-jn957 up (v2) scenic-icehouse-web-3291896318-rsekj up (v2) scenic-icehouse-web-3291896318-vwhnh up (v2) scenic-icehouse-web-3291896318-vokg7 up (v2) --- background (started): 1 scenic-icehouse-web-3291896318-background-yf8kh up (v2) Note The default process type for Dockerfile and Container Image applications is 'cmd' rather than 'web'. Scaling a process down, by reducing the process count, sends a TERM signal to the processes, followed by a SIGKILL if they have not exited within 30 seconds. Depending on your application, scaling down may interrupt long-running HTTP client connections. For example, scaling from 5 processes to 3: $ drycc scale web=3 Scaling processes... but first, coffee! done in 1s === scenic-icehouse Processes --- background (started): 1 scenic-icehouse-web-3291896318-background-yf8kh up (v2) --- web (started): 3 scenic-icehouse-web-3291896318-7lord up (v2) scenic-icehouse-web-3291896318-rsekj up (v2) scenic-icehouse-web-3291896318-vokg7 up (v2)","title":"Scaling Processes"},{"location":"applications/managing-app-processes/#get-a-shell-to-a-running-container","text":"Verify that the container is running: # drycc ps === python-getting-started Processes --- web: python-getting-started-web-69b7d4bfdc-kl4xf up (v2) Get a shell to the running container: # drycc ps:exec python-getting-started-web-69b7d4bfdc-kl4xf -it -- bash In your shell, list the root directory: # Run this inside the container ls / Running individual commands in a container # drycc ps:exec python-getting-started-web-69b7d4bfdc-kl4xf -- date Use \"drycc ps --help\" for a list of global command-line (applies to all commands).","title":"Get a Shell to a Running Container"},{"location":"applications/managing-app-processes/#autoscale","text":"Autoscale allows adding a minimum and maximum number of pods on a per process type basis. This is accomplished by specifying a target CPU usage across all available pods. This feature is built on top of Horizontal Pod Autoscaling in Kubernetes or HPA for short. Note This is an alpha feature. It is recommended to be on the latest Kubernetes when using this feature. $ drycc autoscale:set web --min=3 --max=8 --cpu-percent=75 Applying autoscale settings for process type web on scenic-icehouse... done And then review the scaling rule that was created for web $ drycc autoscale:list === scenic-icehouse Autoscale --- web: Min Replicas: 3 Max Replicas: 8 CPU: 75% Remove scaling rule $ drycc autoscale:unset web Removing autoscale for process type web on scenic-icehouse... done For autoscaling to work CPU requests have to be specified on each application Pod (can be done via drycc limits --cpu ). This allows the autoscale policies to do the appropriate calculations and make decisions on when to scale up and down. Scale up can only happen if there was no rescaling within the last 3 minutes. Scale down will wait for 5 minutes from the last rescaling. That information and more can be found at HPA algorithm page .","title":"Autoscale"},{"location":"applications/managing-app-processes/#web-vs-cmd-process-types","text":"When deploying to Drycc Workflow using a Heroku Buildpack, Workflow boots the web process type to boot the application server. When you deploy an application that has a Dockerfile or uses Container images , Workflow boots the cmd process type. Both act similarly in that they are exposed to the router as web applications. However, the cmd process type is special because, if left undefined, it is equivalent to running the container without any additional arguments. (i.e. The process specified by the Dockerfile or Container image's CMD directive will be used.) If migrating an application from Heroku Buildpacks to a Container-based deployment, Workflow will not automatically convert the web process type to cmd . To do this, you'll have to manually scale down the old process type and scale the new process type up.","title":"Web vs Cmd Process Types"},{"location":"applications/managing-app-processes/#restarting-an-application-processes","text":"If you need to restart an application process, you may use drycc ps:restart . Behind the scenes, Drycc Workflow instructs Kubernetes to terminate the old process and launch a new one in its place. $ drycc ps === scenic-icehouse Processes --- web (started): 3 scenic-icehouse-web-3291896318-7lord up (v2) scenic-icehouse-web-3291896318-rsekj up (v2) scenic-icehouse-web-3291896318-vokg7 up (v2) --- background (started): 1 scenic-icehouse-background-3291896318-yf8kh up (v2) $ drycc ps:restart scenic-icehouse-background-3291896318-yf8kh Restarting processes... but first, coffee! done in 6s === scenic-icehouse Processes --- background (started): 1 scenic-icehouse-background-3291896318-yd87g up (v2) Notice that the process name has changed from scenic-icehouse-background-3291896318-yf8kh to scenic-icehouse-background-3291896318-yd87g . In a multi-node Kubernetes cluster, this may also have the effect of scheduling the Pod to a new node.","title":"Restarting an Application Processes"},{"location":"applications/managing-app-resources/","text":"Managing resources for an Application \u00b6 We can use blow command to create resources and bind which resource is created. This command depend on service-catalog . Use drycc resources to create and bind a resource for a deployed application. $ drycc help resources Valid commands for resources: resources:services list all available resource services resources:plans list all available plans for an resource services resources:create create a resource for the application resources:list list resources in the application resources:describe get a resource detail info in the application resources:update update a resource from the application resources:destroy delete a resource from the applicationa resources:bind bind a resource to servicebroker resources:unbind unbind a resource from servicebroker Use 'drycc help [command]' to learn more. List all available resource services \u00b6 You can list available resource services with one drycc resources:services command $ drycc resources:services +------------+------------+ | NAME | UPDATEABLE | +------------+------------+ | mysql | true | | postgresql | true | | memcached | true | | redis | true | +------------+------------+ List all available plans for an resource services \u00b6 You can list all available plans for an resource services with one drycc resources:plans command $ drycc resources:plans redis +-------+--------------------------------+ | NAME | DESCRIPTION | +-------+--------------------------------+ | 40000 | Redis 40000 plan which limit | | | resources memory size 40Gi. | | 250 | Redis 250 plan which limit | | | resources memory size 250Mi. | | 20000 | Redis 20000 plan which limit | | | resources memory size 20Gi. | | 5000 | Redis 5000 plan which limit | | | resources memory size 5Gi. | | 500 | Redis 500 plan which limit | | | resources memory size 500Mi. | | 128 | Redis 128 plan which limit | | | resources memory size 128Mi. | | 50000 | Redis 50000 plan which limit | | | resources memory size 50Gi. | | 2500 | Redis 2500 plan which limit | | | resources memory size 2.5Gi. | | 30000 | Redis 30000 plan which limit | | | resources memory size 30Gi. | | 10000 | Redis 10000 plan which limit | | | resources memory size 10Gi. | | 1000 | Redis 1000 plan which limit | | | resources memory size 1Gi. | +-------+--------------------------------+ Create resource in application \u00b6 You can create a resource with one drycc resources:create command $ drycc resources:create redis:1000 redis Creating redis to scenic-icehouse... done After resources are created, you can list the resources in this application. $ drycc resources:list === scenic-icehouse resources redis redis:1000 Bind resources \u00b6 The resource which is named redis is created, you can bind the redis to the application, use the command of drycc resources:bind redis . $ drycc resources:bind redis Binding resource... done Describe resources \u00b6 And use drycc resources:describe show the binding detail. If the binding is successful, this command will show the information of connect to the resource. $ drycc resources:describe redis === scenic-icehouse resource redis plan: redis:1000 status: Ready binding: Ready REDISPORT: 6379 REDIS_PASSWORD: RzG87SJWG1 SENTINELHOST: 172.16.0.2 SENTINELPORT: 26379 Update resources \u00b6 You can use the drycc resources:update command to upgrade a new plan. An example of how to upgrade the plan's capacity to 100MB: $ drycc resources:update redis:10000 redis Updating redis to scenic-icehouse... done Remove the resource \u00b6 If you don't need resources, use drycc resources:unbind to unbind the resource and then use drycc resources:destroy to delete the resource from the application. Before deleting the resource, the resource must be unbinded. $ drycc resources:unbind redis Unbinding resource... done $ drycc resources:destroy redis Deleting redis from scenic-icehouse... done","title":"Managing App Resources"},{"location":"applications/managing-app-resources/#managing-resources-for-an-application","text":"We can use blow command to create resources and bind which resource is created. This command depend on service-catalog . Use drycc resources to create and bind a resource for a deployed application. $ drycc help resources Valid commands for resources: resources:services list all available resource services resources:plans list all available plans for an resource services resources:create create a resource for the application resources:list list resources in the application resources:describe get a resource detail info in the application resources:update update a resource from the application resources:destroy delete a resource from the applicationa resources:bind bind a resource to servicebroker resources:unbind unbind a resource from servicebroker Use 'drycc help [command]' to learn more.","title":"Managing resources for an Application"},{"location":"applications/managing-app-resources/#list-all-available-resource-services","text":"You can list available resource services with one drycc resources:services command $ drycc resources:services +------------+------------+ | NAME | UPDATEABLE | +------------+------------+ | mysql | true | | postgresql | true | | memcached | true | | redis | true | +------------+------------+","title":"List all available resource services"},{"location":"applications/managing-app-resources/#list-all-available-plans-for-an-resource-services","text":"You can list all available plans for an resource services with one drycc resources:plans command $ drycc resources:plans redis +-------+--------------------------------+ | NAME | DESCRIPTION | +-------+--------------------------------+ | 40000 | Redis 40000 plan which limit | | | resources memory size 40Gi. | | 250 | Redis 250 plan which limit | | | resources memory size 250Mi. | | 20000 | Redis 20000 plan which limit | | | resources memory size 20Gi. | | 5000 | Redis 5000 plan which limit | | | resources memory size 5Gi. | | 500 | Redis 500 plan which limit | | | resources memory size 500Mi. | | 128 | Redis 128 plan which limit | | | resources memory size 128Mi. | | 50000 | Redis 50000 plan which limit | | | resources memory size 50Gi. | | 2500 | Redis 2500 plan which limit | | | resources memory size 2.5Gi. | | 30000 | Redis 30000 plan which limit | | | resources memory size 30Gi. | | 10000 | Redis 10000 plan which limit | | | resources memory size 10Gi. | | 1000 | Redis 1000 plan which limit | | | resources memory size 1Gi. | +-------+--------------------------------+","title":"List all available plans for an resource services"},{"location":"applications/managing-app-resources/#create-resource-in-application","text":"You can create a resource with one drycc resources:create command $ drycc resources:create redis:1000 redis Creating redis to scenic-icehouse... done After resources are created, you can list the resources in this application. $ drycc resources:list === scenic-icehouse resources redis redis:1000","title":"Create resource in application"},{"location":"applications/managing-app-resources/#bind-resources","text":"The resource which is named redis is created, you can bind the redis to the application, use the command of drycc resources:bind redis . $ drycc resources:bind redis Binding resource... done","title":"Bind resources"},{"location":"applications/managing-app-resources/#describe-resources","text":"And use drycc resources:describe show the binding detail. If the binding is successful, this command will show the information of connect to the resource. $ drycc resources:describe redis === scenic-icehouse resource redis plan: redis:1000 status: Ready binding: Ready REDISPORT: 6379 REDIS_PASSWORD: RzG87SJWG1 SENTINELHOST: 172.16.0.2 SENTINELPORT: 26379","title":"Describe resources"},{"location":"applications/managing-app-resources/#update-resources","text":"You can use the drycc resources:update command to upgrade a new plan. An example of how to upgrade the plan's capacity to 100MB: $ drycc resources:update redis:10000 redis Updating redis to scenic-icehouse... done","title":"Update resources"},{"location":"applications/managing-app-resources/#remove-the-resource","text":"If you don't need resources, use drycc resources:unbind to unbind the resource and then use drycc resources:destroy to delete the resource from the application. Before deleting the resource, the resource must be unbinded. $ drycc resources:unbind redis Unbinding resource... done $ drycc resources:destroy redis Deleting redis from scenic-icehouse... done","title":"Remove the resource"},{"location":"applications/managing-app-volumes/","text":"Mounting volumes for an Application \u00b6 We can use the blow command to create volumes and mount the created volumes. Drycc create volume support ReadWriteMany , so before deploying drycc, you need to have a StorageClass ready which can support ReadWriteMany. Deploying drycc, set controller.appStorageClass to this StorageClass. Use drycc volumes to mount a volume for a deployed application's processes. $ drycc help volumes Valid commands for volumes: volumes:create create a volume for the application volumes:list list volumes in the application volumes:delete delete a volume from the application volumes:mount mount a volume to process of the application volumes:unmount unmount a volume from process of the application Use 'drycc help [command]' to learn more. Create a volume for the application \u00b6 You can create a volume with the drycc volumes:create command $ drycc volumes:create myvolume 200M Creating myvolumes to scenic-icehouse... done List volumes in the application \u00b6 After volume is created, you can list the volumes in this application. $ drycc volumes:list === scenic-icehouse volumes --- myvolumes 200M Mount a volume \u00b6 The volume which is named myvolumes is created, you can mount the volume with process of the application, use the command of drycc volumes:mount . When volume is mounted, a new release will be created and deployed automatically. $ drycc volumes:mount myvolumes web=/data/web Mounting volume... done And use drycc volumes:list show mount detail. $ drycc volumes:list === scenic-icehouse volumes --- myvolumes 200M web /data/web If you don't need the volume, use drycc volumes:unmount to unmount the volume and then use drycc volumes:delete to delete the volume from the application. Before deleting volume, the volume has to be unmounted. $ drycc volumes:unmount myvolumes web Unmounting volume... done $ drycc volumes:delete myvolumes Deleting myvolumes from scenic-icehouse... done","title":"Managing App Volumes"},{"location":"applications/managing-app-volumes/#mounting-volumes-for-an-application","text":"We can use the blow command to create volumes and mount the created volumes. Drycc create volume support ReadWriteMany , so before deploying drycc, you need to have a StorageClass ready which can support ReadWriteMany. Deploying drycc, set controller.appStorageClass to this StorageClass. Use drycc volumes to mount a volume for a deployed application's processes. $ drycc help volumes Valid commands for volumes: volumes:create create a volume for the application volumes:list list volumes in the application volumes:delete delete a volume from the application volumes:mount mount a volume to process of the application volumes:unmount unmount a volume from process of the application Use 'drycc help [command]' to learn more.","title":"Mounting volumes for an Application"},{"location":"applications/managing-app-volumes/#create-a-volume-for-the-application","text":"You can create a volume with the drycc volumes:create command $ drycc volumes:create myvolume 200M Creating myvolumes to scenic-icehouse... done","title":"Create a volume for the application"},{"location":"applications/managing-app-volumes/#list-volumes-in-the-application","text":"After volume is created, you can list the volumes in this application. $ drycc volumes:list === scenic-icehouse volumes --- myvolumes 200M","title":"List volumes in the application"},{"location":"applications/managing-app-volumes/#mount-a-volume","text":"The volume which is named myvolumes is created, you can mount the volume with process of the application, use the command of drycc volumes:mount . When volume is mounted, a new release will be created and deployed automatically. $ drycc volumes:mount myvolumes web=/data/web Mounting volume... done And use drycc volumes:list show mount detail. $ drycc volumes:list === scenic-icehouse volumes --- myvolumes 200M web /data/web If you don't need the volume, use drycc volumes:unmount to unmount the volume and then use drycc volumes:delete to delete the volume from the application. Before deleting volume, the volume has to be unmounted. $ drycc volumes:unmount myvolumes web Unmounting volume... done $ drycc volumes:delete myvolumes Deleting myvolumes from scenic-icehouse... done","title":"Mount a volume"},{"location":"applications/managing-resource-limits/","text":"Managing Application Resource Limits \u00b6 Drycc Workflow supports restricting memory and CPU shares of each process. Requests/Limits set on a per-process type are given to Kubernetes as a requests and limits. Which means you guarantee amount of resource for a process as well as limit the process from using more than . By default, Kubernetes will set equal to if we don't explicitly set value. Please keep in mind that 0 <= requests <= limits . Limiting Memory \u00b6 If you set a requests/limits that is out of range for your cluster, Kubernetes will be unable to schedule your application processes into the cluster! Available units for memory are: Unit Amount B Bytes K KiB (Power of 2) M MiB (Power of 2) G GiB (Power of 2) Important The minimum memory limit allowed is 4MiB. Use drycc limits:set = to restrict memory by process type, where value can be or / format : $ drycc limits:set web=64M Applying limits... done === indoor-whitecap Limits --- Memory web 64M --- CPU Unlimited $ drycc limits:set cmd=32M/64M Applying limits... done === outdoor-whitecap Limits --- Memory cmd 32M/64M --- CPU Unlimited If you would like to remove any configured memory limits use drycc limits:unset web : $ drycc limits:unset web Applying limits... done === indoor-whitecap Limits --- Memory Unlimited --- CPU Unlimited Limiting CPU \u00b6 You can also use drycc limits:set = --cpu to restrict CPU shares, where value can be or / format. CPU shares are tracked in milli-cores. One CPU core is equivalent to 1000 milli-cores. To dedicate half a core to your process, you would need 500 milli-cores or 500m. Unit Amount 1000m 1000 milli-cores == 100% CPU core 500m 500 milli-cores == 50% CPU core 250m 250 milli-cores == 25% CPU core 100m 100 milli-cores == 10% CPU core $ drycc limits:set web=250m --cpu Applying limits... done === indoor-whitecap Limits --- Memory web 64M --- CPU web 250m $ drycc limits:set web=1500m/2000m --cpu Applying limits... done === indoor-whitecap Limits --- Memory web 64M --- CPU web 1500m/2000m You can verify the CPU and memory limits by inspecting the application process Pod with kubectl : $ drycc ps === indoor-whitecap Processes --- web (started): 1 indoor-whitecap-v14-web-8slcj up (v14) $ kubectl --namespace=indoor-whitecap describe po indoor-whitecap-v14-web-8slcj Name: indoor-whitecap-v14-web-8slcj Containers: QoS Tier: cpu: Guaranteed memory: Guaranteed Limits: cpu: 2000m memory: 64Mi Requests: memory: 64Mi cpu: 1500m Important If you restrict resources to the point where containers do not start, the limits:set command will hang. If this happens, use CTRL-C to break out of limits:set and use limits:unset to revert. To unset a CPU limit use drycc limits:unset web --cpu : $ drycc limits:unset web --cpu Applying limits... done === indoor-whitecap Limits --- Memory Unlimited --- CPU Unlimited","title":"Resource Limits"},{"location":"applications/managing-resource-limits/#managing-application-resource-limits","text":"Drycc Workflow supports restricting memory and CPU shares of each process. Requests/Limits set on a per-process type are given to Kubernetes as a requests and limits. Which means you guarantee amount of resource for a process as well as limit the process from using more than . By default, Kubernetes will set equal to if we don't explicitly set value. Please keep in mind that 0 <= requests <= limits .","title":"Managing Application Resource Limits"},{"location":"applications/managing-resource-limits/#limiting-memory","text":"If you set a requests/limits that is out of range for your cluster, Kubernetes will be unable to schedule your application processes into the cluster! Available units for memory are: Unit Amount B Bytes K KiB (Power of 2) M MiB (Power of 2) G GiB (Power of 2) Important The minimum memory limit allowed is 4MiB. Use drycc limits:set = to restrict memory by process type, where value can be or / format : $ drycc limits:set web=64M Applying limits... done === indoor-whitecap Limits --- Memory web 64M --- CPU Unlimited $ drycc limits:set cmd=32M/64M Applying limits... done === outdoor-whitecap Limits --- Memory cmd 32M/64M --- CPU Unlimited If you would like to remove any configured memory limits use drycc limits:unset web : $ drycc limits:unset web Applying limits... done === indoor-whitecap Limits --- Memory Unlimited --- CPU Unlimited","title":"Limiting Memory"},{"location":"applications/managing-resource-limits/#limiting-cpu","text":"You can also use drycc limits:set = --cpu to restrict CPU shares, where value can be or / format. CPU shares are tracked in milli-cores. One CPU core is equivalent to 1000 milli-cores. To dedicate half a core to your process, you would need 500 milli-cores or 500m. Unit Amount 1000m 1000 milli-cores == 100% CPU core 500m 500 milli-cores == 50% CPU core 250m 250 milli-cores == 25% CPU core 100m 100 milli-cores == 10% CPU core $ drycc limits:set web=250m --cpu Applying limits... done === indoor-whitecap Limits --- Memory web 64M --- CPU web 250m $ drycc limits:set web=1500m/2000m --cpu Applying limits... done === indoor-whitecap Limits --- Memory web 64M --- CPU web 1500m/2000m You can verify the CPU and memory limits by inspecting the application process Pod with kubectl : $ drycc ps === indoor-whitecap Processes --- web (started): 1 indoor-whitecap-v14-web-8slcj up (v14) $ kubectl --namespace=indoor-whitecap describe po indoor-whitecap-v14-web-8slcj Name: indoor-whitecap-v14-web-8slcj Containers: QoS Tier: cpu: Guaranteed memory: Guaranteed Limits: cpu: 2000m memory: 64Mi Requests: memory: 64Mi cpu: 1500m Important If you restrict resources to the point where containers do not start, the limits:set command will hang. If this happens, use CTRL-C to break out of limits:set and use limits:unset to revert. To unset a CPU limit use drycc limits:unset web --cpu : $ drycc limits:unset web --cpu Applying limits... done === indoor-whitecap Limits --- Memory Unlimited --- CPU Unlimited","title":"Limiting CPU"},{"location":"applications/ssl-certificates/","text":"Application SSL Certificates \u00b6 SSL is a cryptographic protocol that provides end-to-end encryption and integrity for all web requests. Apps that transmit sensitive data should enable SSL to ensure all information is transmitted securely. To enable SSL on a custom domain, e.g., www.example.com , use the SSL endpoint. Note drycc certs is only useful for custom domains. Default application domains are SSL-enabled already and can be accessed simply by using https, e.g. https://foo.dryccapp.com (provided that you have installed your wildcard certificate on the routers or on the load balancer). Overview \u00b6 Because of the unique nature of SSL validation, provisioning SSL for your domain is a multi-step process that involves several third-parties. You will need to: Purchase an SSL certificate from your SSL provider Upload the cert to Drycc Acquire SSL Certificate \u00b6 Purchasing an SSL cert varies in cost and process depending on the vendor. RapidSSL offers a simple way to purchase a certificate and is a recommended solution. If you\u2019re able to use this provider, see buy an SSL certificate with RapidSSL for instructions. DNS and Domain Configuration \u00b6 Once the SSL certificate is provisioned and your cert is confirmed, you must route requests for your domain through Drycc. Unless you've already done so, add the domain specified when generating the CSR to your app with: $ drycc domains:add www.example.com -a foo Adding www.example.com to foo... done Add a Certificate \u00b6 Add your certificate, any intermediate certificates, and private key to the endpoint with the certs:add command. $ drycc certs:add example-com server.crt server.key Adding SSL endpoint... done www.example.com Note The name given to the certificate can only contain a-z (lowercase), 0-9 and hyphens The Drycc platform will investigate the certificate and extract any relevant information from it such as the Common Name, Subject Alt Names (SAN), fingerprint and more. This allows for wildcard certificates and multiple domains in the SAN without uploading duplicates. Add a Certificate Chain \u00b6 Sometimes, your certificates (such as a self-signed or a cheap certificate) need additional certificates to establish the chain of trust. What you need to do is bundle all the certificates into one file and give that to Drycc. Importantly, your site\u2019s certificate must be the first one: $ cat server.crt server.ca > server.bundle After that, you can add them to Drycc with the certs:add command: $ drycc certs:add example-com server.bundle server.key Adding SSL endpoint... done www.example.com Attach SSL certificate to a domain \u00b6 Certificates are not automagically connected up to domains, instead you will have to attach a certificate to a domain $ drycc certs:attach example-com example.com Each certificate can be connected to many domains. There is no need to upload duplicates. To remove an association $ drycc certs:detach example-com example.com Endpoint overview \u00b6 You can verify the details of your domain's SSL configuration with drycc certs . $ drycc certs Name | Common Name | SubjectAltName | Expires | Fingerprint | Domains | Updated | Created +-------------+-------------------+-------------------+-------------------------+-----------------+--------------+-------------+-------------+ example-com | example.com | blog.example.com | 31 Dec 2017 (in 1 year) | 8F:8E[...]CD:EB | example.com | 30 Jan 2016 | 29 Jan 2016 or by looking at at each certificates detailed information $ drycc certs:info example-com === bar-com Certificate Common Name(s): example.com Expires At: 2017-01-14 23:57:57 +0000 UTC Starts At: 2016-01-15 23:57:57 +0000 UTC Fingerprint: 7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0 Subject Alt Name: blog.example.com Issuer: /C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=example.com/emailAddress=engineering@drycc.cc Subject: /C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=example.com/emailAddress=engineering@drycc.cc Connected Domains: example.com Owner: admin-user Created: 2016-01-28 19:07:41 +0000 UTC Updated: 2016-01-30 00:10:02 +0000 UTC Testing SSL \u00b6 Use a command line utility like curl to test that everything is configured correctly for your secure domain. Note The -k option flag tells curl to ignore untrusted certificates. Pay attention to the output. It should print SSL certificate verify ok . If it prints something like common name: www.example.com (does not match 'www.somedomain.com') then something is not configured correctly. Enforcing SSL at the Router \u00b6 To enforce all HTTP requests be redirected to HTTPS, TLS can be enforced at the router level by running $ drycc tls:force:enable -a foo Enabling https-only requests for foo... done Users hitting the HTTP endpoint for the application will now receive a 301 redirect to the HTTPS endpoint. To disable enforced TLS, run $ drycc tls:force:disable -a foo Disabling https-only requests for foo... done Automated Certificate Management \u00b6 With Automated Certificate Management (ACM), Drycc automatically manages TLS certificates for apps with Hobby and Professional dynos on the Common Runtime, and for apps in Private Spaces that enable the feature. Certificates handled by ACM automatically renew one month before they expire, and new certificates are created automatically whenever you add or remove a custom domain. All applications with paid dynos include ACM for free. Automated Certificate Management uses Let\u2019s Encrypt, the free, automated, and open certificate authority for managing your application\u2019s TLS certificates. Let\u2019s Encrypt is run for the public benefit by the Internet Security Research Group (ISRG). To enable ACM with the following command: $ drycc tls:auto:enable -a foo To disable ACM with the following command: $ drycc tls:auto:disable -a foo Remove Certificate \u00b6 You can remove a certificate using the certs:remove command: $ drycc certs:remove my-cert Removing www.example.com... Done. Swapping out certificates \u00b6 Over the lifetime of an application an operator will have to acquire certificates with new expire dates and apply it to all relevant applications, below is the recommended way to swap out certificates. Be intentional with certificate names, name them example-com-2017 when possible, where the year signifies the expiry year. This allows for example-com-2018 when a new certificate is purchased. Assuming all applications are already using example-com-2017 the following commands can be ran, chained together or otherwise: $ drycc certs:detach example-com-2017 example.com $ drycc certs:attach example-com-2018 example.com This will take care of a singular domain which allows the operator to verify everything went as planned and slowly roll it out to any other application using the same method. Troubleshooting \u00b6 Here are some steps you can follow if your SSL endpoint is not working as you'd expect. Untrusted Certificate \u00b6 In some cases when accessing the SSL endpoint, it may list your certificate as untrusted. If this occurs, it may be because it is not trusted by Mozilla\u2019s list of root CAs . If this is the case, your certificate may be considered untrusted for many browsers. If you have uploaded a certificate that was signed by a root authority but you get the message that it is not trusted, then something is wrong with the certificate. For example, it may be missing intermediary certificates . If so, download the intermediary certificates from your SSL provider, remove the certificate from Drycc and re-run the certs:add command.","title":"SSL Certificates"},{"location":"applications/ssl-certificates/#application-ssl-certificates","text":"SSL is a cryptographic protocol that provides end-to-end encryption and integrity for all web requests. Apps that transmit sensitive data should enable SSL to ensure all information is transmitted securely. To enable SSL on a custom domain, e.g., www.example.com , use the SSL endpoint. Note drycc certs is only useful for custom domains. Default application domains are SSL-enabled already and can be accessed simply by using https, e.g. https://foo.dryccapp.com (provided that you have installed your wildcard certificate on the routers or on the load balancer).","title":"Application SSL Certificates"},{"location":"applications/ssl-certificates/#overview","text":"Because of the unique nature of SSL validation, provisioning SSL for your domain is a multi-step process that involves several third-parties. You will need to: Purchase an SSL certificate from your SSL provider Upload the cert to Drycc","title":"Overview"},{"location":"applications/ssl-certificates/#acquire-ssl-certificate","text":"Purchasing an SSL cert varies in cost and process depending on the vendor. RapidSSL offers a simple way to purchase a certificate and is a recommended solution. If you\u2019re able to use this provider, see buy an SSL certificate with RapidSSL for instructions.","title":"Acquire SSL Certificate"},{"location":"applications/ssl-certificates/#dns-and-domain-configuration","text":"Once the SSL certificate is provisioned and your cert is confirmed, you must route requests for your domain through Drycc. Unless you've already done so, add the domain specified when generating the CSR to your app with: $ drycc domains:add www.example.com -a foo Adding www.example.com to foo... done","title":"DNS and Domain Configuration"},{"location":"applications/ssl-certificates/#add-a-certificate","text":"Add your certificate, any intermediate certificates, and private key to the endpoint with the certs:add command. $ drycc certs:add example-com server.crt server.key Adding SSL endpoint... done www.example.com Note The name given to the certificate can only contain a-z (lowercase), 0-9 and hyphens The Drycc platform will investigate the certificate and extract any relevant information from it such as the Common Name, Subject Alt Names (SAN), fingerprint and more. This allows for wildcard certificates and multiple domains in the SAN without uploading duplicates.","title":"Add a Certificate"},{"location":"applications/ssl-certificates/#add-a-certificate-chain","text":"Sometimes, your certificates (such as a self-signed or a cheap certificate) need additional certificates to establish the chain of trust. What you need to do is bundle all the certificates into one file and give that to Drycc. Importantly, your site\u2019s certificate must be the first one: $ cat server.crt server.ca > server.bundle After that, you can add them to Drycc with the certs:add command: $ drycc certs:add example-com server.bundle server.key Adding SSL endpoint... done www.example.com","title":"Add a Certificate Chain"},{"location":"applications/ssl-certificates/#attach-ssl-certificate-to-a-domain","text":"Certificates are not automagically connected up to domains, instead you will have to attach a certificate to a domain $ drycc certs:attach example-com example.com Each certificate can be connected to many domains. There is no need to upload duplicates. To remove an association $ drycc certs:detach example-com example.com","title":"Attach SSL certificate to a domain"},{"location":"applications/ssl-certificates/#endpoint-overview","text":"You can verify the details of your domain's SSL configuration with drycc certs . $ drycc certs Name | Common Name | SubjectAltName | Expires | Fingerprint | Domains | Updated | Created +-------------+-------------------+-------------------+-------------------------+-----------------+--------------+-------------+-------------+ example-com | example.com | blog.example.com | 31 Dec 2017 (in 1 year) | 8F:8E[...]CD:EB | example.com | 30 Jan 2016 | 29 Jan 2016 or by looking at at each certificates detailed information $ drycc certs:info example-com === bar-com Certificate Common Name(s): example.com Expires At: 2017-01-14 23:57:57 +0000 UTC Starts At: 2016-01-15 23:57:57 +0000 UTC Fingerprint: 7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0 Subject Alt Name: blog.example.com Issuer: /C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=example.com/emailAddress=engineering@drycc.cc Subject: /C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=example.com/emailAddress=engineering@drycc.cc Connected Domains: example.com Owner: admin-user Created: 2016-01-28 19:07:41 +0000 UTC Updated: 2016-01-30 00:10:02 +0000 UTC","title":"Endpoint overview"},{"location":"applications/ssl-certificates/#testing-ssl","text":"Use a command line utility like curl to test that everything is configured correctly for your secure domain. Note The -k option flag tells curl to ignore untrusted certificates. Pay attention to the output. It should print SSL certificate verify ok . If it prints something like common name: www.example.com (does not match 'www.somedomain.com') then something is not configured correctly.","title":"Testing SSL"},{"location":"applications/ssl-certificates/#enforcing-ssl-at-the-router","text":"To enforce all HTTP requests be redirected to HTTPS, TLS can be enforced at the router level by running $ drycc tls:force:enable -a foo Enabling https-only requests for foo... done Users hitting the HTTP endpoint for the application will now receive a 301 redirect to the HTTPS endpoint. To disable enforced TLS, run $ drycc tls:force:disable -a foo Disabling https-only requests for foo... done","title":"Enforcing SSL at the Router"},{"location":"applications/ssl-certificates/#automated-certificate-management","text":"With Automated Certificate Management (ACM), Drycc automatically manages TLS certificates for apps with Hobby and Professional dynos on the Common Runtime, and for apps in Private Spaces that enable the feature. Certificates handled by ACM automatically renew one month before they expire, and new certificates are created automatically whenever you add or remove a custom domain. All applications with paid dynos include ACM for free. Automated Certificate Management uses Let\u2019s Encrypt, the free, automated, and open certificate authority for managing your application\u2019s TLS certificates. Let\u2019s Encrypt is run for the public benefit by the Internet Security Research Group (ISRG). To enable ACM with the following command: $ drycc tls:auto:enable -a foo To disable ACM with the following command: $ drycc tls:auto:disable -a foo","title":"Automated Certificate Management"},{"location":"applications/ssl-certificates/#remove-certificate","text":"You can remove a certificate using the certs:remove command: $ drycc certs:remove my-cert Removing www.example.com... Done.","title":"Remove Certificate"},{"location":"applications/ssl-certificates/#swapping-out-certificates","text":"Over the lifetime of an application an operator will have to acquire certificates with new expire dates and apply it to all relevant applications, below is the recommended way to swap out certificates. Be intentional with certificate names, name them example-com-2017 when possible, where the year signifies the expiry year. This allows for example-com-2018 when a new certificate is purchased. Assuming all applications are already using example-com-2017 the following commands can be ran, chained together or otherwise: $ drycc certs:detach example-com-2017 example.com $ drycc certs:attach example-com-2018 example.com This will take care of a singular domain which allows the operator to verify everything went as planned and slowly roll it out to any other application using the same method.","title":"Swapping out certificates"},{"location":"applications/ssl-certificates/#troubleshooting","text":"Here are some steps you can follow if your SSL endpoint is not working as you'd expect.","title":"Troubleshooting"},{"location":"applications/ssl-certificates/#untrusted-certificate","text":"In some cases when accessing the SSL endpoint, it may list your certificate as untrusted. If this occurs, it may be because it is not trusted by Mozilla\u2019s list of root CAs . If this is the case, your certificate may be considered untrusted for many browsers. If you have uploaded a certificate that was signed by a root authority but you get the message that it is not trusted, then something is wrong with the certificate. For example, it may be missing intermediary certificates . If so, download the intermediary certificates from your SSL provider, remove the certificate from Drycc and re-run the certs:add command.","title":"Untrusted Certificate"},{"location":"applications/using-buildpacks/","text":"Using Buildpacks \u00b6 Drycc supports deploying applications via Cloud Native Buildpacks . Cloud Native Buildpacks are useful if you want to follow cnb's docs for building applications. Add SSH Key \u00b6 For Buildpack based application deploys via git push , Drycc Workflow identifies users via SSH keys. SSH keys are pushed to the platform and must be unique to each user. See this document for instructions on how to generate an SSH key. Run drycc keys:add to upload your SSH key to Drycc Workflow. $ drycc keys:add ~/.ssh/id_drycc.pub Uploading id_drycc.pub to drycc... done Read more about adding/removing SSH Keys here . Prepare an Application \u00b6 If you do not have an existing application, you can clone an example application that demonstrates the Heroku Buildpack workflow. $ git clone https://github.com/drycc/example-go.git $ cd example-go Create an Application \u00b6 Use drycc create to create an application on the Controller . $ drycc create Creating application... done, created skiing-keypunch Git remote drycc added Push to Deploy \u00b6 Use git push drycc master to deploy your application. $ git push drycc master Counting objects: 75, done. Delta compression using up to 8 threads. Compressing objects: 100% (48/48), done. Writing objects: 100% (75/75), 18.28 KiB | 0 bytes/s, done. Total 75 (delta 30), reused 58 (delta 22) remote: ---> Starting build... but first, coffee! ---> Waiting podman running. ---> Process podman started. ---> Waiting caddy running. ---> Process caddy started. ---> Building pack ---> Using builder registry.drycc.cc/drycc/buildpacks:bookworm Builder 'registry.drycc.cc/drycc/buildpacks:bookworm' is trusted Pulling image 'registry.drycc.cc/drycc/buildpacks:bookworm' Resolving \"drycc/buildpacks\" using unqualified-search registries (/etc/containers/registries.conf) Trying to pull registry.drycc.cc/drycc/buildpacks:bookworm... Getting image source signatures ... ---> Skip generate base layer ---> Python Buildpack ---> Downloading and extracting Python 3.10.0 ---> Installing requirements with pip Collecting Django==3.2.8 Downloading Django-3.2.8-py3-none-any.whl (7.9 MB) Collecting gunicorn==20.1.0 Downloading gunicorn-20.1.0-py3-none-any.whl (79 kB) Collecting sqlparse>=0.2.2 Downloading sqlparse-0.4.2-py3-none-any.whl (42 kB) Collecting pytz Downloading pytz-2021.3-py2.py3-none-any.whl (503 kB) Collecting asgiref<4,>=3.3.2 Downloading asgiref-3.4.1-py3-none-any.whl (25 kB) Requirement already satisfied: setuptools>=3.0 in /layers/drycc_python/python/lib/python3.10/site-packages (from gunicorn==20.1.0->-r requirements.txt (line 2)) (57.5.0) Installing collected packages: sqlparse, pytz, asgiref, gunicorn, Django Successfully installed Django-3.2.8 asgiref-3.4.1 gunicorn-20.1.0 pytz-2021.3 sqlparse-0.4.2 ---> Generate Launcher ... Build complete. Launching App... ... Done, skiing-keypunch:v2 deployed to Workflow Use 'drycc open' to view this application in your browser To learn more, use 'drycc help' or visit https://www.drycc.cc To ssh://git@drycc.staging-2.drycc.cc:2222/skiing-keypunch.git * [new branch] master -> master $ curl -s http://skiing-keypunch.example.com Powered by Drycc Release v2 on skiing-keypunch-v2-web-02zb9 Because a Buildpacks-style application is detected, the web process type is automatically scaled to 1 on first deploy. Use drycc scale web=3 to increase web processes to 3, for example. Scaling a process type directly changes the number of pods running that process. Included Buildpacks \u00b6 For convenience, a number of buildpacks come bundled with Drycc: Go Buildpack Java Buildpack Nodejs Buildpack PHP Buildpack Python Buildpack Ruby Buildpack Rust Buildpack Drycc will cycle through the bin/detect script of each buildpack to match the code you are pushing. Note If you're testing against the [Scala Buildpack][], the Builder requires at least 512MB of free memory to execute the Scala Build Tool. Using a Custom Buildpack \u00b6 To use a custom buildpack, you need create a .pack_builder file in your root path app. $ tee > .pack_builder << EOF > registry.drycc.cc/drycc/buildpacks:bookworm > EOF On your next git push , the custom buildpack will be used. Using Private Repositories \u00b6 To pull code from private repositories, set the SSH_KEY environment variable to a private key which has access. Use either the path of a private key file or the raw key material: $ drycc config:set SSH_KEY=/home/user/.ssh/id_rsa $ drycc config:set SSH_KEY=\"\"\"-----BEGIN RSA PRIVATE KEY----- (...) -----END RSA PRIVATE KEY-----\"\"\" For example, to use a custom buildpack hosted at a private GitHub URL, ensure that an SSH public key exists in your GitHub settings . Then set SSH_KEY to the corresponding SSH private key and set .pack_builder to the builder image: $ tee > .pack_builder << EOF > registry.drycc.cc/drycc/buildpacks:bookworm > EOF $ git add .buildpack $ git commit -m \"chore(buildpack): modify the pack_builder\" $ git push drycc master Builder selector \u00b6 Which way to build a project conforms to the following principles: If Dockerfile exists in the project, the stack uses container If Procfile exists in the project, the stack uses buildpack If both exist, container is used by default You can also set the DRYCC_STACK to container or buildpack determine which stack to use.","title":"Buildpacks"},{"location":"applications/using-buildpacks/#using-buildpacks","text":"Drycc supports deploying applications via Cloud Native Buildpacks . Cloud Native Buildpacks are useful if you want to follow cnb's docs for building applications.","title":"Using Buildpacks"},{"location":"applications/using-buildpacks/#add-ssh-key","text":"For Buildpack based application deploys via git push , Drycc Workflow identifies users via SSH keys. SSH keys are pushed to the platform and must be unique to each user. See this document for instructions on how to generate an SSH key. Run drycc keys:add to upload your SSH key to Drycc Workflow. $ drycc keys:add ~/.ssh/id_drycc.pub Uploading id_drycc.pub to drycc... done Read more about adding/removing SSH Keys here .","title":"Add SSH Key"},{"location":"applications/using-buildpacks/#prepare-an-application","text":"If you do not have an existing application, you can clone an example application that demonstrates the Heroku Buildpack workflow. $ git clone https://github.com/drycc/example-go.git $ cd example-go","title":"Prepare an Application"},{"location":"applications/using-buildpacks/#create-an-application","text":"Use drycc create to create an application on the Controller . $ drycc create Creating application... done, created skiing-keypunch Git remote drycc added","title":"Create an Application"},{"location":"applications/using-buildpacks/#push-to-deploy","text":"Use git push drycc master to deploy your application. $ git push drycc master Counting objects: 75, done. Delta compression using up to 8 threads. Compressing objects: 100% (48/48), done. Writing objects: 100% (75/75), 18.28 KiB | 0 bytes/s, done. Total 75 (delta 30), reused 58 (delta 22) remote: ---> Starting build... but first, coffee! ---> Waiting podman running. ---> Process podman started. ---> Waiting caddy running. ---> Process caddy started. ---> Building pack ---> Using builder registry.drycc.cc/drycc/buildpacks:bookworm Builder 'registry.drycc.cc/drycc/buildpacks:bookworm' is trusted Pulling image 'registry.drycc.cc/drycc/buildpacks:bookworm' Resolving \"drycc/buildpacks\" using unqualified-search registries (/etc/containers/registries.conf) Trying to pull registry.drycc.cc/drycc/buildpacks:bookworm... Getting image source signatures ... ---> Skip generate base layer ---> Python Buildpack ---> Downloading and extracting Python 3.10.0 ---> Installing requirements with pip Collecting Django==3.2.8 Downloading Django-3.2.8-py3-none-any.whl (7.9 MB) Collecting gunicorn==20.1.0 Downloading gunicorn-20.1.0-py3-none-any.whl (79 kB) Collecting sqlparse>=0.2.2 Downloading sqlparse-0.4.2-py3-none-any.whl (42 kB) Collecting pytz Downloading pytz-2021.3-py2.py3-none-any.whl (503 kB) Collecting asgiref<4,>=3.3.2 Downloading asgiref-3.4.1-py3-none-any.whl (25 kB) Requirement already satisfied: setuptools>=3.0 in /layers/drycc_python/python/lib/python3.10/site-packages (from gunicorn==20.1.0->-r requirements.txt (line 2)) (57.5.0) Installing collected packages: sqlparse, pytz, asgiref, gunicorn, Django Successfully installed Django-3.2.8 asgiref-3.4.1 gunicorn-20.1.0 pytz-2021.3 sqlparse-0.4.2 ---> Generate Launcher ... Build complete. Launching App... ... Done, skiing-keypunch:v2 deployed to Workflow Use 'drycc open' to view this application in your browser To learn more, use 'drycc help' or visit https://www.drycc.cc To ssh://git@drycc.staging-2.drycc.cc:2222/skiing-keypunch.git * [new branch] master -> master $ curl -s http://skiing-keypunch.example.com Powered by Drycc Release v2 on skiing-keypunch-v2-web-02zb9 Because a Buildpacks-style application is detected, the web process type is automatically scaled to 1 on first deploy. Use drycc scale web=3 to increase web processes to 3, for example. Scaling a process type directly changes the number of pods running that process.","title":"Push to Deploy"},{"location":"applications/using-buildpacks/#included-buildpacks","text":"For convenience, a number of buildpacks come bundled with Drycc: Go Buildpack Java Buildpack Nodejs Buildpack PHP Buildpack Python Buildpack Ruby Buildpack Rust Buildpack Drycc will cycle through the bin/detect script of each buildpack to match the code you are pushing. Note If you're testing against the [Scala Buildpack][], the Builder requires at least 512MB of free memory to execute the Scala Build Tool.","title":"Included Buildpacks"},{"location":"applications/using-buildpacks/#using-a-custom-buildpack","text":"To use a custom buildpack, you need create a .pack_builder file in your root path app. $ tee > .pack_builder << EOF > registry.drycc.cc/drycc/buildpacks:bookworm > EOF On your next git push , the custom buildpack will be used.","title":"Using a Custom Buildpack"},{"location":"applications/using-buildpacks/#using-private-repositories","text":"To pull code from private repositories, set the SSH_KEY environment variable to a private key which has access. Use either the path of a private key file or the raw key material: $ drycc config:set SSH_KEY=/home/user/.ssh/id_rsa $ drycc config:set SSH_KEY=\"\"\"-----BEGIN RSA PRIVATE KEY----- (...) -----END RSA PRIVATE KEY-----\"\"\" For example, to use a custom buildpack hosted at a private GitHub URL, ensure that an SSH public key exists in your GitHub settings . Then set SSH_KEY to the corresponding SSH private key and set .pack_builder to the builder image: $ tee > .pack_builder << EOF > registry.drycc.cc/drycc/buildpacks:bookworm > EOF $ git add .buildpack $ git commit -m \"chore(buildpack): modify the pack_builder\" $ git push drycc master","title":"Using Private Repositories"},{"location":"applications/using-buildpacks/#builder-selector","text":"Which way to build a project conforms to the following principles: If Dockerfile exists in the project, the stack uses container If Procfile exists in the project, the stack uses buildpack If both exist, container is used by default You can also set the DRYCC_STACK to container or buildpack determine which stack to use.","title":"Builder selector"},{"location":"applications/using-container-images/","text":"Using Docker Images \u00b6 Drycc supports deploying applications via an existing Docker Image . This is useful for integrating Drycc into Docker-based CI/CD pipelines. Prepare an Application \u00b6 Start by cloning an example application: $ git clone https://github.com/drycc/example-dockerfile-http.git $ cd example-dockerfile-http Next use your local docker client to build the image and push it to DockerHub . $ docker build -t /example-dockerfile-http . $ docker push /example-dockerfile-http Docker Image Requirements \u00b6 In order to deploy Docker images, they must conform to the following requirements: The Dockerfile must use the EXPOSE directive to expose exactly one port. That port must be listening for an HTTP connection. The Dockerfile must use the CMD directive to define the default process that will run within the container. The Docker image must contain bash to run processes. Note Note that if you are using a private registry of any kind ( gcr or other) the application environment must include a $PORT config variable that matches the EXPOSE 'd port, example: drycc config:set PORT=5000 . See Configuring Registry for more info. Create an Application \u00b6 Use drycc create to create an application on the controller . $ mkdir -p /tmp/example-dockerfile-http && cd /tmp/example-dockerfile-http $ drycc create example-dockerfile-http --no-remote Creating application... done, created example-dockerfile-http Note For all commands except for drycc create , the drycc client uses the name of the current directory as the app name if you don't specify it explicitly with --app . Deploy the Application \u00b6 Use drycc pull to deploy your application from DockerHub or a public registry. $ drycc pull /example-dockerfile-http:latest Creating build... done, v2 $ curl -s http://example-dockerfile-http.local3.dryccapp.com Powered by Drycc Because you are deploying a Docker image, the cmd process type is automatically scaled to 1 on first deploy. Use drycc scale cmd=3 to increase cmd processes to 3, for example. Scaling a process type directly changes the number of Containers running that process. Private Registry \u00b6 To deploy Docker images from a private registry or from a private repository, use drycc registry to attach credentials to your application. These credentials are the same as you'd use when running docker login at your private registry. To deploy private Docker images, take the following steps: Gather the username and password for the registry, such as a Quay.io Robot Account or a GCR.io Long Lived Token Run drycc registry:set username= password= -a Now perform drycc pull as normal, against an image in the private registry When using a GCR.io Long Lived Token , the JSON blob will have to be compacted first using a tool like jq and then used in the password field in drycc registry:set . For the username, use _json_key . For example: drycc registry:set username=_json_key password=\"$(cat google_cloud_cred.json | jq -c .)\" When using a private registry the docker images are no longer pulled into the Drycc Internal Registry via the Drycc Workflow Controller but rather is managed by Kubernetes. This will increase security and overall speed, however the application port information can no longer be discovered. Instead the application port information can be set via drycc config:set PORT=80 prior to setting the registry information. Note Currently GCR.io and ECR in short lived auth token mode are not supported.","title":"Container Images"},{"location":"applications/using-container-images/#using-docker-images","text":"Drycc supports deploying applications via an existing Docker Image . This is useful for integrating Drycc into Docker-based CI/CD pipelines.","title":"Using Docker Images"},{"location":"applications/using-container-images/#prepare-an-application","text":"Start by cloning an example application: $ git clone https://github.com/drycc/example-dockerfile-http.git $ cd example-dockerfile-http Next use your local docker client to build the image and push it to DockerHub . $ docker build -t /example-dockerfile-http . $ docker push /example-dockerfile-http","title":"Prepare an Application"},{"location":"applications/using-container-images/#docker-image-requirements","text":"In order to deploy Docker images, they must conform to the following requirements: The Dockerfile must use the EXPOSE directive to expose exactly one port. That port must be listening for an HTTP connection. The Dockerfile must use the CMD directive to define the default process that will run within the container. The Docker image must contain bash to run processes. Note Note that if you are using a private registry of any kind ( gcr or other) the application environment must include a $PORT config variable that matches the EXPOSE 'd port, example: drycc config:set PORT=5000 . See Configuring Registry for more info.","title":"Docker Image Requirements"},{"location":"applications/using-container-images/#create-an-application","text":"Use drycc create to create an application on the controller . $ mkdir -p /tmp/example-dockerfile-http && cd /tmp/example-dockerfile-http $ drycc create example-dockerfile-http --no-remote Creating application... done, created example-dockerfile-http Note For all commands except for drycc create , the drycc client uses the name of the current directory as the app name if you don't specify it explicitly with --app .","title":"Create an Application"},{"location":"applications/using-container-images/#deploy-the-application","text":"Use drycc pull to deploy your application from DockerHub or a public registry. $ drycc pull /example-dockerfile-http:latest Creating build... done, v2 $ curl -s http://example-dockerfile-http.local3.dryccapp.com Powered by Drycc Because you are deploying a Docker image, the cmd process type is automatically scaled to 1 on first deploy. Use drycc scale cmd=3 to increase cmd processes to 3, for example. Scaling a process type directly changes the number of Containers running that process.","title":"Deploy the Application"},{"location":"applications/using-container-images/#private-registry","text":"To deploy Docker images from a private registry or from a private repository, use drycc registry to attach credentials to your application. These credentials are the same as you'd use when running docker login at your private registry. To deploy private Docker images, take the following steps: Gather the username and password for the registry, such as a Quay.io Robot Account or a GCR.io Long Lived Token Run drycc registry:set username= password= -a Now perform drycc pull as normal, against an image in the private registry When using a GCR.io Long Lived Token , the JSON blob will have to be compacted first using a tool like jq and then used in the password field in drycc registry:set . For the username, use _json_key . For example: drycc registry:set username=_json_key password=\"$(cat google_cloud_cred.json | jq -c .)\" When using a private registry the docker images are no longer pulled into the Drycc Internal Registry via the Drycc Workflow Controller but rather is managed by Kubernetes. This will increase security and overall speed, however the application port information can no longer be discovered. Instead the application port information can be set via drycc config:set PORT=80 prior to setting the registry information. Note Currently GCR.io and ECR in short lived auth token mode are not supported.","title":"Private Registry"},{"location":"applications/using-dockerfiles/","text":"Using Dockerfiles \u00b6 Drycc supports deploying applications via Dockerfiles. A Dockerfile automates the steps for crafting a [Container Image][]. Dockerfiles are incredibly powerful but require some extra work to define your exact application runtime environment. Add SSH Key \u00b6 For Dockerfile based application deploys via git push , Drycc Workflow identifies users via SSH keys. SSH keys are pushed to the platform and must be unique to each user. See this document for instructions on how to generate an SSH key. Run drycc keys:add to upload your SSH key to Drycc Workflow. $ drycc keys:add ~/.ssh/id_drycc.pub Uploading id_drycc.pub to drycc... done Read more about adding/removing SSH Keys here . Prepare an Application \u00b6 If you do not have an existing application, you can clone an example application that demonstrates the Dockerfile workflow. $ git clone https://github.com/drycc/helloworld.git $ cd helloworld Dockerfile Requirements \u00b6 In order to deploy Dockerfile applications, they must conform to the following requirements: The Dockerfile must use the EXPOSE directive to expose exactly one port. That port must be listening for an HTTP connection. The Dockerfile must use the CMD directive to define the default process that will run within the container. The Container image must contain bash to run processes. Note Note that if you are using a private registry of any kind ( gcr or other) the application environment must include a $PORT config variable that matches the EXPOSE 'd port, example: drycc config:set PORT=5000 . See Configuring Registry for more info. Create an Application \u00b6 Use drycc create to create an application on the Controller . $ drycc create Creating application... done, created folksy-offshoot Git remote drycc added Push to Deploy \u00b6 Use git push drycc master to deploy your application. $ git push drycc master Counting objects: 13, done. Delta compression using up to 8 threads. Compressing objects: 100% (13/13), done. Writing objects: 100% (13/13), 1.99 KiB | 0 bytes/s, done. Total 13 (delta 2), reused 0 (delta 0) -----> Building Docker image Uploading context 4.096 kB Uploading context Step 0 : FROM drycc/base:latest ---> 60024338bc63 Step 1 : RUN wget -O /tmp/go1.2.1.linux-amd64.tar.gz -q https://go.googlecode.com/files/go1.2.1.linux-amd64.tar.gz ---> Using cache ---> cf9ef8c5caa7 Step 2 : RUN tar -C /usr/local -xzf /tmp/go1.2.1.linux-amd64.tar.gz ---> Using cache ---> 515b1faf3bd8 Step 3 : RUN mkdir -p /go ---> Using cache ---> ebf4927a00e9 Step 4 : ENV GOPATH /go ---> Using cache ---> c6a276eded37 Step 5 : ENV PATH /usr/local/go/bin:/go/bin:$PATH ---> Using cache ---> 2ba6f6c9f108 Step 6 : ADD . /go/src/github.com/drycc/helloworld ---> 94ab7f4b977b Removing intermediate container 171b7d9fdb34 Step 7 : RUN cd /go/src/github.com/drycc/helloworld && go install -v . ---> Running in 0c8fbb2d2812 github.com/drycc/helloworld ---> 13b5af931393 Removing intermediate container 0c8fbb2d2812 Step 8 : ENV PORT 80 ---> Running in 9b07da36a272 ---> 2dce83167874 Removing intermediate container 9b07da36a272 Step 9 : CMD [\"/go/bin/helloworld\"] ---> Running in f7b215199940 ---> b1e55ce5195a Removing intermediate container f7b215199940 Step 10 : EXPOSE 80 ---> Running in 7eb8ec45dcb0 ---> ea1a8cc93ca3 Removing intermediate container 7eb8ec45dcb0 Successfully built ea1a8cc93ca3 -----> Pushing image to private registry Launching... done, v2 -----> folksy-offshoot deployed to Drycc http://folksy-offshoot.local3.dryccapp.com To learn more, use `drycc help` or visit https://www.drycc.cc To ssh://git@local3.dryccapp.com:2222/folksy-offshoot.git * [new branch] master -> master $ curl -s http://folksy-offshoot.local3.dryccapp.com Welcome to Drycc! See the documentation at http://docs.drycc.cc/ for more information. Because a Dockerfile application is detected, the cmd process type is automatically scaled to 1 on first deploy. Use drycc scale cmd=3 to increase cmd processes to 3, for example. Scaling a process type directly changes the number of containers running that process. Container Build Arguments \u00b6 As of Workflow v2.13.0, users can inject their application config into the Container image using Container build arguments . To opt into this, users must add a new environment variable to their application: $ drycc config:set DRYCC_DOCKER_BUILD_ARGS_ENABLED=1 Every environment variable set with drycc config:set will then be available for use inside the user's Dockerfile. For example, if a user runs drycc config:set POWERED_BY=Workflow , the user can utilize that build argument in their Dockerfile: ARG POWERED_BY RUN echo \"Powered by $POWERED_BY\" > /etc/motd","title":"Dockerfiles"},{"location":"applications/using-dockerfiles/#using-dockerfiles","text":"Drycc supports deploying applications via Dockerfiles. A Dockerfile automates the steps for crafting a [Container Image][]. Dockerfiles are incredibly powerful but require some extra work to define your exact application runtime environment.","title":"Using Dockerfiles"},{"location":"applications/using-dockerfiles/#add-ssh-key","text":"For Dockerfile based application deploys via git push , Drycc Workflow identifies users via SSH keys. SSH keys are pushed to the platform and must be unique to each user. See this document for instructions on how to generate an SSH key. Run drycc keys:add to upload your SSH key to Drycc Workflow. $ drycc keys:add ~/.ssh/id_drycc.pub Uploading id_drycc.pub to drycc... done Read more about adding/removing SSH Keys here .","title":"Add SSH Key"},{"location":"applications/using-dockerfiles/#prepare-an-application","text":"If you do not have an existing application, you can clone an example application that demonstrates the Dockerfile workflow. $ git clone https://github.com/drycc/helloworld.git $ cd helloworld","title":"Prepare an Application"},{"location":"applications/using-dockerfiles/#dockerfile-requirements","text":"In order to deploy Dockerfile applications, they must conform to the following requirements: The Dockerfile must use the EXPOSE directive to expose exactly one port. That port must be listening for an HTTP connection. The Dockerfile must use the CMD directive to define the default process that will run within the container. The Container image must contain bash to run processes. Note Note that if you are using a private registry of any kind ( gcr or other) the application environment must include a $PORT config variable that matches the EXPOSE 'd port, example: drycc config:set PORT=5000 . See Configuring Registry for more info.","title":"Dockerfile Requirements"},{"location":"applications/using-dockerfiles/#create-an-application","text":"Use drycc create to create an application on the Controller . $ drycc create Creating application... done, created folksy-offshoot Git remote drycc added","title":"Create an Application"},{"location":"applications/using-dockerfiles/#push-to-deploy","text":"Use git push drycc master to deploy your application. $ git push drycc master Counting objects: 13, done. Delta compression using up to 8 threads. Compressing objects: 100% (13/13), done. Writing objects: 100% (13/13), 1.99 KiB | 0 bytes/s, done. Total 13 (delta 2), reused 0 (delta 0) -----> Building Docker image Uploading context 4.096 kB Uploading context Step 0 : FROM drycc/base:latest ---> 60024338bc63 Step 1 : RUN wget -O /tmp/go1.2.1.linux-amd64.tar.gz -q https://go.googlecode.com/files/go1.2.1.linux-amd64.tar.gz ---> Using cache ---> cf9ef8c5caa7 Step 2 : RUN tar -C /usr/local -xzf /tmp/go1.2.1.linux-amd64.tar.gz ---> Using cache ---> 515b1faf3bd8 Step 3 : RUN mkdir -p /go ---> Using cache ---> ebf4927a00e9 Step 4 : ENV GOPATH /go ---> Using cache ---> c6a276eded37 Step 5 : ENV PATH /usr/local/go/bin:/go/bin:$PATH ---> Using cache ---> 2ba6f6c9f108 Step 6 : ADD . /go/src/github.com/drycc/helloworld ---> 94ab7f4b977b Removing intermediate container 171b7d9fdb34 Step 7 : RUN cd /go/src/github.com/drycc/helloworld && go install -v . ---> Running in 0c8fbb2d2812 github.com/drycc/helloworld ---> 13b5af931393 Removing intermediate container 0c8fbb2d2812 Step 8 : ENV PORT 80 ---> Running in 9b07da36a272 ---> 2dce83167874 Removing intermediate container 9b07da36a272 Step 9 : CMD [\"/go/bin/helloworld\"] ---> Running in f7b215199940 ---> b1e55ce5195a Removing intermediate container f7b215199940 Step 10 : EXPOSE 80 ---> Running in 7eb8ec45dcb0 ---> ea1a8cc93ca3 Removing intermediate container 7eb8ec45dcb0 Successfully built ea1a8cc93ca3 -----> Pushing image to private registry Launching... done, v2 -----> folksy-offshoot deployed to Drycc http://folksy-offshoot.local3.dryccapp.com To learn more, use `drycc help` or visit https://www.drycc.cc To ssh://git@local3.dryccapp.com:2222/folksy-offshoot.git * [new branch] master -> master $ curl -s http://folksy-offshoot.local3.dryccapp.com Welcome to Drycc! See the documentation at http://docs.drycc.cc/ for more information. Because a Dockerfile application is detected, the cmd process type is automatically scaled to 1 on first deploy. Use drycc scale cmd=3 to increase cmd processes to 3, for example. Scaling a process type directly changes the number of containers running that process.","title":"Push to Deploy"},{"location":"applications/using-dockerfiles/#container-build-arguments","text":"As of Workflow v2.13.0, users can inject their application config into the Container image using Container build arguments . To opt into this, users must add a new environment variable to their application: $ drycc config:set DRYCC_DOCKER_BUILD_ARGS_ENABLED=1 Every environment variable set with drycc config:set will then be available for use inside the user's Dockerfile. For example, if a user runs drycc config:set POWERED_BY=Workflow , the user can utilize that build argument in their Dockerfile: ARG POWERED_BY RUN echo \"Powered by $POWERED_BY\" > /etc/motd","title":"Container Build Arguments"},{"location":"changelogs/v1.0.1/","text":"The time has come for major release! We are proud to present Drycc Workflow 1.0.1 to the world. In this release, we've added a lot of new features. You can download one of our pre-built binaries from our downloads page - make sure to select the correct platform! For further details on how to install, follow our installation guide. We\u2019d like to thank all of our backers on Open Collective, who are helping us deliver a better piece of software. With that out of the way, here\u2019s what\u2019s new in Drycc version 1.0.1: substituting minio-mc for object-storage using wal-g instead of wal-e some scenarios use dep instead of glide minio adds gateway mode adding aliyun oss support In the future, we have many exciting plans, for example: Use kubernetes ingress instead of drycc-router Automatic certificate generation using cert-manager Replace golang's package management glide with dep Support for the latest version of the kubernetes API Coming soon...","title":"v1.0.1"},{"location":"changelogs/v1.1.0/","text":"Workflow ## v1.0.0 -> v1.1.0 \u00b6 Releases \u00b6 builder v1.0.0 -> v1.0.1 controller v1.0.0 -> v1.1.0 database v1.0.0 -> v1.0.1 monitor v1.0.0 -> v1.0.1 registry-proxy v1.0.0 -> v1.0.1 Features \u00b6 69c8e12 (controller) - docker: use python:3.7-alpine replace drycc/base 6a3e70c (controller) - gunicorn: use process replace threads e63cbb5 (controller) - ingress: Improving the configuration of ingress 76f75dc (controller) - charts: add rbac to cert-manager 6807b2c (controller) - certificate: add cert-manager certificate api Fixes \u00b6 f53d89e (controller) - controller: check_image_access only when using docker 896775a (controller) - docker: multiprocess should not be used in docker ecdaf9f (controller) - app: can't create app e00af7e (controller) - tls: add migrations for certs_auto_enabled Style \u00b6 bdbb7e6 (controller) - pep8: Use pep8-compliant code style Test case \u00b6 c5b5a9d (controller) - ingress: add tests to ingress Maintenance \u00b6 62a9b7d (builder) - workflow: change experimental_native_ingress to use_native_ingress 39e9cec (builder) - ingress: renmae use_native_ingress to use_ingress 7fa8134 (builder) - ingress: change global.use_ingress to ingress.enabled e245c31 (builder) - ingress: use ingressClass 18b330d (builder) - service: no longer dependent on ingress switches 95f4d3d (controller) - django: upgrade to django version 1.11.20 latest patch 6bcd79b (controller) - workflow: change experimental_native_ingress to use_native_ingress 781229a (controller) - ingress: renmae use_native_ingress to use_ingress b96b4db (controller) - ingress: change global.use_ingress to ingress.enabled e1b124f (controller) - ingress: use ingressClass fee0554 (controller) - ingress: delete ingress judgment 5cd10f3 (controller) - ingress: Ingress_class can be empty fa312bb (database) - postgres: set max_connections = 1024 c1ee2a4 (monitor) - monitor: remove copyrights.tar.gz e088da3 (registry-proxy) - ingress: renmae use_native_ingress to use_ingress","title":"v1.1.0"},{"location":"changelogs/v1.1.0/#workflow-v100-v110","text":"","title":"Workflow ## v1.0.0 -> v1.1.0"},{"location":"changelogs/v1.1.0/#releases","text":"builder v1.0.0 -> v1.0.1 controller v1.0.0 -> v1.1.0 database v1.0.0 -> v1.0.1 monitor v1.0.0 -> v1.0.1 registry-proxy v1.0.0 -> v1.0.1","title":"Releases"},{"location":"changelogs/v1.1.0/#features","text":"69c8e12 (controller) - docker: use python:3.7-alpine replace drycc/base 6a3e70c (controller) - gunicorn: use process replace threads e63cbb5 (controller) - ingress: Improving the configuration of ingress 76f75dc (controller) - charts: add rbac to cert-manager 6807b2c (controller) - certificate: add cert-manager certificate api","title":"Features"},{"location":"changelogs/v1.1.0/#fixes","text":"f53d89e (controller) - controller: check_image_access only when using docker 896775a (controller) - docker: multiprocess should not be used in docker ecdaf9f (controller) - app: can't create app e00af7e (controller) - tls: add migrations for certs_auto_enabled","title":"Fixes"},{"location":"changelogs/v1.1.0/#style","text":"bdbb7e6 (controller) - pep8: Use pep8-compliant code style","title":"Style"},{"location":"changelogs/v1.1.0/#test-case","text":"c5b5a9d (controller) - ingress: add tests to ingress","title":"Test case"},{"location":"changelogs/v1.1.0/#maintenance","text":"62a9b7d (builder) - workflow: change experimental_native_ingress to use_native_ingress 39e9cec (builder) - ingress: renmae use_native_ingress to use_ingress 7fa8134 (builder) - ingress: change global.use_ingress to ingress.enabled e245c31 (builder) - ingress: use ingressClass 18b330d (builder) - service: no longer dependent on ingress switches 95f4d3d (controller) - django: upgrade to django version 1.11.20 latest patch 6bcd79b (controller) - workflow: change experimental_native_ingress to use_native_ingress 781229a (controller) - ingress: renmae use_native_ingress to use_ingress b96b4db (controller) - ingress: change global.use_ingress to ingress.enabled e1b124f (controller) - ingress: use ingressClass fee0554 (controller) - ingress: delete ingress judgment 5cd10f3 (controller) - ingress: Ingress_class can be empty fa312bb (database) - postgres: set max_connections = 1024 c1ee2a4 (monitor) - monitor: remove copyrights.tar.gz e088da3 (registry-proxy) - ingress: renmae use_native_ingress to use_ingress","title":"Maintenance"},{"location":"changelogs/v1.2.0/","text":"Workflow ## v1.1.0 -> v1.2.0 \u00b6 Releases \u00b6 builder v1.0.1 -> v1.0.2 slugbuilder v1.0.0 -> v1.1.0 imagebuilder v1.0.0 -> v1.1.0 controller v1.1.0 -> v1.2.0 slugrunner v1.0.0 -> v1.1.0 registry v1.0.0 -> v1.0.1 registry-proxy v1.0.1 -> v1.0.2 Features \u00b6 e5584e3 (controller) - controller: add STACK support ad34dc1 (imagebuilder) - kaniko: use kaniko replace docker-py b81430e (imagebuilder) - imagebuilder: change image to image.json format 60dde96 (slugbuilder) - slugbuilder: add STACK support fe8b6e5 (slugrunner) - slugrunner: add STACK support Maintenance \u00b6 942f050 (builder) - registry: remove env DRYCC_REGISTRY_PROXY_PORT ff7a16f (builder) - registry: remove ecr and gcr registry ad13683 (builder) - builder: change DRYCC_BUILD_TYPE to DRYCC_STACK 6def637 (builder) - registry: rename DRYCC_REGISTRY_SERVICE to DRYCC_REGISTRY_PROXY 5044e22 (builder) - registry: remove registrySecretPrefix 2ea39cc (builder) - controller-go-sdk: upgrade controller-go-sdk 6aee0d7 (builder) - registry: optimizing variable naming f9c62d9 (controller) - domain: added reserved domain check f5a135b (controller) - migrations: clean old migrations 4369b2c (controller) - registry: rename DRYCC_REGISTRY_SERVICE to DRYCC_REGISTRY_PROXY 1057ca5 (controller) - registry: remove registrySecretPrefix d114b3e (controller) - docker: update docker client edbe963 (imagebuilder) - dockerfile: change base image to alpine fb35baf (imagebuilder) - registry: rename DRYCC_REGISTRY_SERVICE to DRYCC_REGISTRY_PROXY 946dbf6 (imagebuilder) - docker: remove insecure support 628d853 (imagebuilder) - proxy: add registry proxy ff27cbd (registry) - env: remove unused env 7204d72 (registry-proxy) - registry: optimizing variable naming","title":"v1.2.0"},{"location":"changelogs/v1.2.0/#workflow-v110-v120","text":"","title":"Workflow ## v1.1.0 -> v1.2.0"},{"location":"changelogs/v1.2.0/#releases","text":"builder v1.0.1 -> v1.0.2 slugbuilder v1.0.0 -> v1.1.0 imagebuilder v1.0.0 -> v1.1.0 controller v1.1.0 -> v1.2.0 slugrunner v1.0.0 -> v1.1.0 registry v1.0.0 -> v1.0.1 registry-proxy v1.0.1 -> v1.0.2","title":"Releases"},{"location":"changelogs/v1.2.0/#features","text":"e5584e3 (controller) - controller: add STACK support ad34dc1 (imagebuilder) - kaniko: use kaniko replace docker-py b81430e (imagebuilder) - imagebuilder: change image to image.json format 60dde96 (slugbuilder) - slugbuilder: add STACK support fe8b6e5 (slugrunner) - slugrunner: add STACK support","title":"Features"},{"location":"changelogs/v1.2.0/#maintenance","text":"942f050 (builder) - registry: remove env DRYCC_REGISTRY_PROXY_PORT ff7a16f (builder) - registry: remove ecr and gcr registry ad13683 (builder) - builder: change DRYCC_BUILD_TYPE to DRYCC_STACK 6def637 (builder) - registry: rename DRYCC_REGISTRY_SERVICE to DRYCC_REGISTRY_PROXY 5044e22 (builder) - registry: remove registrySecretPrefix 2ea39cc (builder) - controller-go-sdk: upgrade controller-go-sdk 6aee0d7 (builder) - registry: optimizing variable naming f9c62d9 (controller) - domain: added reserved domain check f5a135b (controller) - migrations: clean old migrations 4369b2c (controller) - registry: rename DRYCC_REGISTRY_SERVICE to DRYCC_REGISTRY_PROXY 1057ca5 (controller) - registry: remove registrySecretPrefix d114b3e (controller) - docker: update docker client edbe963 (imagebuilder) - dockerfile: change base image to alpine fb35baf (imagebuilder) - registry: rename DRYCC_REGISTRY_SERVICE to DRYCC_REGISTRY_PROXY 946dbf6 (imagebuilder) - docker: remove insecure support 628d853 (imagebuilder) - proxy: add registry proxy ff27cbd (registry) - env: remove unused env 7204d72 (registry-proxy) - registry: optimizing variable naming","title":"Maintenance"},{"location":"changelogs/v1.3.0/","text":"Workflow ## v1.2.0 -> v1.3.0 \u00b6 Releases \u00b6 builder v1.0.2 -> v1.1.0 slugbuilder v1.1.0 -> v1.1.1 imagebuilder v1.1.0 -> v1.1.1 controller v1.2.0 -> v1.2.1 slugrunner v1.1.0 -> v1.1.1 database v1.0.0 -> v1.0.1 fluentd v1.0.0 -> v1.0.1 minio v1.0.0 -> v1.0.1 monitor v1.0.0 -> v1.0.1 registry v1.0.1 -> v1.0.2 Features \u00b6 9c7cceb (builder) - builder: add app config to env Fixes \u00b6 7fe44fa (controller) - docker: docker timeout must be an int, float or None b196550 (controller) - controller: revert release.check_image_access for now Maintenance \u00b6 ef932c4 (builder) - controller-sdk-go: upgrade controller-sdk-go 4654cf6 (controller) - django-rest-framework: upgrade to 3.9.3 14121f1 (controller) - deps: bump djangorestframework from 3.9.3 to 3.9.4 in /rootfs 385acdc (controller) - deps: bump django from 1.11.20 to 1.11.21 in /rootfs fa312bb (database) - postgres: set max_connections = 1024 7ebecdf (database) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z b8878f6 (imagebuilder) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z b097451 (fluentd) - fluent: upgrade fluent to v1.4 4341f9a (minio) - mc: upgrade mc and minio c1ee2a4 (monitor) - monitor: remove copyrights.tar.gz 9854260 (registry) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z acc5627 (slugbuilder) - slugbuilder: internal support for multi buildpack d58907e (slugbuilder) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z b39a0c2 (slugrunner) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z","title":"v1.3.0"},{"location":"changelogs/v1.3.0/#workflow-v120-v130","text":"","title":"Workflow ## v1.2.0 -> v1.3.0"},{"location":"changelogs/v1.3.0/#releases","text":"builder v1.0.2 -> v1.1.0 slugbuilder v1.1.0 -> v1.1.1 imagebuilder v1.1.0 -> v1.1.1 controller v1.2.0 -> v1.2.1 slugrunner v1.1.0 -> v1.1.1 database v1.0.0 -> v1.0.1 fluentd v1.0.0 -> v1.0.1 minio v1.0.0 -> v1.0.1 monitor v1.0.0 -> v1.0.1 registry v1.0.1 -> v1.0.2","title":"Releases"},{"location":"changelogs/v1.3.0/#features","text":"9c7cceb (builder) - builder: add app config to env","title":"Features"},{"location":"changelogs/v1.3.0/#fixes","text":"7fe44fa (controller) - docker: docker timeout must be an int, float or None b196550 (controller) - controller: revert release.check_image_access for now","title":"Fixes"},{"location":"changelogs/v1.3.0/#maintenance","text":"ef932c4 (builder) - controller-sdk-go: upgrade controller-sdk-go 4654cf6 (controller) - django-rest-framework: upgrade to 3.9.3 14121f1 (controller) - deps: bump djangorestframework from 3.9.3 to 3.9.4 in /rootfs 385acdc (controller) - deps: bump django from 1.11.20 to 1.11.21 in /rootfs fa312bb (database) - postgres: set max_connections = 1024 7ebecdf (database) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z b8878f6 (imagebuilder) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z b097451 (fluentd) - fluent: upgrade fluent to v1.4 4341f9a (minio) - mc: upgrade mc and minio c1ee2a4 (monitor) - monitor: remove copyrights.tar.gz 9854260 (registry) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z acc5627 (slugbuilder) - slugbuilder: internal support for multi buildpack d58907e (slugbuilder) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z b39a0c2 (slugrunner) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z","title":"Maintenance"},{"location":"changelogs/v1.4.0/","text":"Workflow ## v1.3.0 -> v1.4.0 \u00b6 Releases \u00b6 builder v1.1.0 -> v1.2.0 slugbuilder v1.1.1 -> v1.2.0 imagebuilder v1.1.1 -> v1.1.2 controller v1.2.1 -> v1.3.0 slugrunner v1.1.1 -> v1.1.2 database v1.0.1 -> v1.0.2 fluentd v1.0.1 -> v1.1.0 redis v1.0.0 -> v1.1.0 logger v1.0.0 -> v1.1.0 minio v1.0.1 -> v1.1.0 monitor v1.0.1 -> v1.1.0 nsqd v1.0.0 -> v1.1.0 registry v1.0.2 -> v1.0.3 registry-proxy v1.0.0 -> v1.0.1 Features \u00b6 fc7d93f (builder) - builder: use go-dev 0c2159e (builder) - builder: fmt code and add create_bucket script 1b88340 (controller) - controller: remove deprecated api a92fdeb (controller) - routable: ingress support routable 1e3eab3 (controller) - maintenance: add maintenance support for ingress 56b9dd0 (controller) - crt: support containerd-ctr 5fc3b46 (controller) - controller: add ephemeral-storage restriction d677e52 (controller) - controller: add a volume command 5f1323a (controller) - controller:drycc run cmd add --mount para 74c36a5 (controller) - tasks: add distributed async task 139c3ca (controller) - tasks: change nsq reader to async f237d74 (controller) - controller:add drycc resource cmd 41b46d0 (controller) - controller:add drycc resource cmd improvement c26f7d8 (controller) - controller: add LimitRanges support 45b5d1b (controller) - users: add users status api 4e16f9b (controller) - ps:add ps:stop/start command c659fa9 (controller) - k8s: add k8s cluster domain 31a625d (controller) - ps:add ps:stop/start command 00a779a (fluentd) - fluentd: support containerd log format f3f1bd4 (fluentd) - nsqd: add stateless nsqd cluster support db7147c (fluentd) - mirrors: delete aliyun mirrors 689c12e (logger) - nsqd: add stateless nsqd cluster support 78ccc5d (logger) - redis: add redis client cluster support 9843f2c (logger) - k8s: add k8s cluster domain 6ba122e (minio) - minio: add pvc support 6973550 (monitor) - monitor: add ingress for monitor cd73305 (monitor) - charts: add volumeName support 4769fe9 (monitor) - nsqd: add stateless nsqd cluster support 87806df (monitor) - k8s: add k8s cluster domain 4db40c4 (nsqd) - nsqd: add stateless nsqd cluster support b6f3d4f (nsqd) - nsqd: add stateless nsqd cluster support 74b85bb (redis) - redis: change redis to statefulset ff98b50 (slugbuilder) - slugbuilder: delete build hook b201c2f (slugbuilder) - buildpacks: use drycc buildpacks Fixes \u00b6 0ec042d (builder) - test: fix test case error 4fb113b (builder) - build: base image replace by alpine 443df48 (builder) - minio: fix not bucket error 3dab5b0 (builder) - minio: create bucket error 734fca6 (controller) - autoscale: Fix for autoscale on k8s-1.9+ without breaking manual scaling a7dcd10 (controller) - controller: test pass 93f0f2e (controller) - controller: fix migrations error 4724375 (controller) - controller: fix test error 7bacf29 (controller) - charts: fix clusterrole 90957f7 (controller) - pod: sort events error 440b13e (controller) - controller: review table structure 0a470a6 (controller) - controller: bump tornado 5.1.1 e39218b (controller) - pynsq: no current event loop in thread 1d8630e (controller) - tests: fix test_task.py run error 1ff1202 (controller) - controller: fix test case d8c0da3 (controller) - settings: fix env name 6d8fd36 (database) - 003_restore_from_backup.sh: ignore script exit 1 e0394a9 (database) - minio: fix not bucket error f35f252 (database) - mc: fix create_bucket error 74d6886 (database) - postgres: recovery mode not run e50d0c1 (imagebuilder) - caddy: fix caddy not start f3bec7a (fluentd) - influxdb: fix influxdb host and port bc19f27 (fluentd) - charts: skipped value for daemonEnvironment: Not a table 338d623 (logger) - logger: logger not run in alpine 7788302 (minio) - minio: bump minio version 619eed0 (minio) - fix: use go mod replace dep 3b42122 (monitor) - monitor: fix host error 67998ef (monitor) - influxdb: replace drycc-monitor-influxapi to drycc-monitor-influx-api 2cc361c (registry) - registry: fix test case 548297a (registry) - minio: fix not bucket error 5412ddb (registry) - minio: create bucket error d0d629e (slugbuilder) - slugbuilder:fix normalize_storage path d76ecbe (slugbuilder) - slugbuilder: use v3 api c505e18 (slugbuilder) - shellcheck: SC2039 Style \u00b6 c893a17 (builder) - builder: fmt code bba5795 (controller) - controller: format code d36082b (controller) - controller: fix pep8 66026f2 (controller) - resource: standardize the naming of resource 03d7e2c (controller) - servicecatalog: change servicecatalog to svcat 49dbb6d (controller) - controller: flake8 upgrade cbfc108 (monitor) - monitor: format charts and dashboard ee85954 (slugbuilder) - slugbuilder: use shellcheck 3afed2e (slugbuilder) - docker: simplify dockerfile 36b7f68 (slugrunner) - docker: simplify dockerfile Maintenance \u00b6 61bb0ef (builder) - aws: upgrade aws sdk version 0f2e074 (builder) - chore: use go mode replace dep e9a2219 (builder) - builder: delete glide up bb8c518 (builder) - registry: del quay.io fa6d02f (builder) - builder: upgrade go.sum 9d61e8d (builder) - build: upgrade go.mod d763a98 (builder) - charts: upgrade k8s newer API versions d1bc1aa (builder) - pkg: upgrade to new drycc/pkg 02b1e98 (builder) - builder: update go mod 8e17d65 (builder) - builder: change alpine repositories f32b723 (builder) - mirrors: delete aliyun mirrors e33dc61 (builder) - minio: use bin mc replace docker images 3ab4f1c (builder) - builder: update controller-sdk-go b2adfac (builder) - heroku: remove heroku-16 support f429ac8 (builder) - builder: set GIT_LOCK_TIMEOUT to 30 minutes 7197c83 (builder) - go.mod:upgrade require pkg controller-sdk-go 5f3e22d (controller) - deps: bump django from 1.11.21 to 1.11.22 in /rootfs 1db645a (controller) - deps: bump django from 1.11.22 to 1.11.23 in /rootfs fbe8067 (controller) - deps: bump django from 1.11.23 to 1.11.29 in /rootfs 537d667 (controller) - registry: del quay.io a23c65b (controller) - deps: update all deps to the latest version 546337e (controller) - charts: upgrade k8s newer API versions 06023f8 (controller) - workflow-manager: del workflow-manager bba5736 (controller) - controller: change cluster-issuer location 6c43661 (controller) - Certificatechange cluster-issuer location 39a4728 (controller) - controller:change cluster-issuer location del controller-cluster-issuer.yaml 9e96d3f (controller) - Certificate:upgrade version cert-manager.io/v1alpha2 8e68049 (controller) - docker: use INDEX_URL replace index.docker.io 8fda205 (controller) - cert_manager: change certManagerEnabled to global 6fefb6d (controller) - charts: change platformDomain to global 064b2ad (controller) - maintenance: remove maintenance support b8797c9 (controller) - workflow: remove namespace 1b20d76 (controller) - quota: add kube quota config d780075 (controller) - pod: add pod default resources support 3d72c08 (controller) - rename: rename ingress name 0aa6ab9 (controller) - mirrors: delete aliyun mirrors 7533a65 (controller) - heroku: remove heroku-16 support e5a885d (controller) - controller:check mount volume path 9014e74 (controller) - test: optimization Dockerfile.test 0b6ebb2 (controller) - tasks: change apply_async parameters 835f009 (controller) - wsgi: add tornado 6 support 67a4ad7 (controller) - utils: use threads replace asyncio a28949b (controller) - ldap: add AUTH_LDAP_USER_FLAGS_BY_GROUP a903209 (controller) - charts: add custom controller environment variables support e0e783e (controller) - ldap: change filter style d760825 (controller) - scheduler: remove debug log a25928e (controller) - wsgi: remove a wsgi.py file 7b2696e (controller) - log: disable nsq.client info log 8d5c07b (controller) - charts: add default environment 025f4a2 (controller) - controller: change quota name ebda60e (controller) - controller: review pvc code 8832ba9 (controller) - controller: change status\\binding model type and mount path check container_types 7148d04 (controller) - controller: add overcommit cpu and ram support 4d2087c (controller) - limits: modify limits unit verification af36970 (controller) - api: check cpu/memory range for api 329355b (controller) - volumes: modify the volume size 9dfee09 (controller) - LimitRanges: modify the default limits 5205bca (controller) - controller: improve the details of certificate 7ebecdf (database) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z 6415e2c (database) - postgres: upgrade to pg13 12e6806 (database) - charts: upgrade k8s newer API versions d294509 (database) - minio: use canary minio test 1bad02e (database) - mirrors: delete aliyun mirrors d51420b (database) - minio: use bin mc replace docker images 4133d05 (imagebuilder) - imagebuilder: update caddy and kaniko 6b4dd18 (imagebuilder) - minio: use bin mc replace docker images 6df9b7c (fluentd) - deps-dev: update rake requirement from ~> 10.0 to ~> 12.3 c2490f8 (fluentd) - fluentd: upgrade fluentd be4a56a (fluentd) - fluentd: add Gemfile.lock 2237f75 (fluentd) - charts: upgrade k8s newer API versions c574065 (fluentd) - charts: upgrade k8s newer API versions 52b8084 (fluentd) - router: delete obsolete router code 3b3cceb (fluentd) - fluentd: remove manifests dir 25c6702 (fluentd) - nsqd: change var name bd571be (fluentd) - nsqd: change DRYCC_NSQD_ADDRESSES to DRYCC_NSQD_ADDRS 72aa4e6 (fluentd) - influxdb: change influxdb service name bd61903 (logger) - logger: use go mod replace dep 69c63a1 (logger) - logger: update go.mod 3aa9cd7 (logger) - registry: del quay.io f058496 (logger) - nsqd: change var name 6d9787c (logger) - nsqd: change DRYCC_NSQD_ADDRESSES to DRYCC_NSQD_ADDRS 85ed307 (logger) - logger: standard naming d88e7b6 (minio) - minio: update minio api to v7 43715d2 (minio) - minio: upgrade minio 0e1239b (minio) - minio: use docker.io replace quay.io f7f047b (minio) - registry: del quay.io afa7128 (minio) - build: upgrade go.mod aff2db5 (minio) - charts: upgrade k8s newer API versions 4547f14 (minio) - pkg: upgrade to new drycc/pkg 2769b85 (minio) - minio: use bin mc replace docker images 35dde8d (monitor) - monitor: update grafana influxdb telegraf 9e3a949 (monitor) - charts: upgrade k8s newer API versions 6af0432 (monitor) - workflow-manager: remove workflow-manager 0611c07 (monitor) - router: delete obsolete router code be04824 (monitor) - cert_manager: change certManagerEnabled to global 3780165 (monitor) - charts: change platformDomain to global 50b04e1 (monitor) - influxdb: remove influxdb admin ui 6ab4d68 (monitor) - influxdb: remove unuse port f1510bd (monitor) - monitor: update grafana dashboard,telegraf inputs.kubernetes f36de2c (monitor) - pvc: upgrade to new format fc78a0a (monitor) - workflow: remove namespace e85890f (monitor) - monitor: monitoring nsqd and redis separately 694f6b1 (monitor) - mirrors: delete aliyun mirrors 4aea36a (monitor) - grafana: add ldap support for grafana 68fc30f (nsqd) - nsq: update nsq 16f32aa (nsqd) - charts: upgrade k8s newer API versions 04db389 (redis) - reids: update to redis 6 3f01bab (redis) - charts: upgrade k8s newer API versions 647e4be (registry) - registry: del quay.io 0bbce99 (registry) - charts: upgrade k8s newer API versions a982b50 (registry) - minio: use bin mc replace docker images e088da3 (registry-proxy) - ingress: renmae use_native_ingress to use_ingress 7e88337 (registry-proxy) - nginx: upgrade nginx to mainline 7204d72 (registry-proxy) - registry: optimizing variable naming 2eafc59 (registry-proxy) - registry-proxy: update nginx 071bd86 (registry-proxy) - charts: upgrade k8s newer API versions c72db96 (registry-proxy) - registry-proxy: change travis icon url ca9f962 (slugbuilder) - slugbuilder: del BUILDPACK_URL support 1b74dd5 (slugbuilder) - slugbuilder: add heroku-20 support 54d4ad2 (slugbuilder) - slugbuilder: del quay.io a78f37e (slugbuilder) - slugbuilder: add heroku-20 stack 94ac94a (slugbuilder) - minio: use bin mc replace docker images 53b4b8b (slugbuilder) - slugbuilder: modify stack priority 58e2bd2 (slugbuilder) - dockerfile: add WORKDIR /tmp b29cd04 (slugbuilder) - slugbuilder: add pre_build.sh 9d319f6 (slugbuilder) - slugbuilder: silent mc command output d1ec3c9 (slugbuilder) - heroku: remove heroku-16 support 5048534 (slugbuilder) - slugbuilder: use drycc stack-images a116537 (slugrunner) - slugrunner: add heroku-20 support a1196bf (slugrunner) - slugrunner: del quay.io 64c96d7 (slugrunner) - slugrunner: add heroku-20 stack cc3e226 (slugrunner) - minio: use bin mc replace docker images 9130bde (slugrunner) - shellcheck: shellcheck installer 4ea33e1 (slugrunner) - slugrunner: modify stack priority 5514e8b (slugrunner) - heroku: remove heroku-16 support be829fb (slugrunner) - slugrunner: use drycc stack-images e1e06be (slugrunner) - slugrunner: remove Dockerfile.heroku-16","title":"v1.4.0"},{"location":"changelogs/v1.4.0/#workflow-v130-v140","text":"","title":"Workflow ## v1.3.0 -> v1.4.0"},{"location":"changelogs/v1.4.0/#releases","text":"builder v1.1.0 -> v1.2.0 slugbuilder v1.1.1 -> v1.2.0 imagebuilder v1.1.1 -> v1.1.2 controller v1.2.1 -> v1.3.0 slugrunner v1.1.1 -> v1.1.2 database v1.0.1 -> v1.0.2 fluentd v1.0.1 -> v1.1.0 redis v1.0.0 -> v1.1.0 logger v1.0.0 -> v1.1.0 minio v1.0.1 -> v1.1.0 monitor v1.0.1 -> v1.1.0 nsqd v1.0.0 -> v1.1.0 registry v1.0.2 -> v1.0.3 registry-proxy v1.0.0 -> v1.0.1","title":"Releases"},{"location":"changelogs/v1.4.0/#features","text":"fc7d93f (builder) - builder: use go-dev 0c2159e (builder) - builder: fmt code and add create_bucket script 1b88340 (controller) - controller: remove deprecated api a92fdeb (controller) - routable: ingress support routable 1e3eab3 (controller) - maintenance: add maintenance support for ingress 56b9dd0 (controller) - crt: support containerd-ctr 5fc3b46 (controller) - controller: add ephemeral-storage restriction d677e52 (controller) - controller: add a volume command 5f1323a (controller) - controller:drycc run cmd add --mount para 74c36a5 (controller) - tasks: add distributed async task 139c3ca (controller) - tasks: change nsq reader to async f237d74 (controller) - controller:add drycc resource cmd 41b46d0 (controller) - controller:add drycc resource cmd improvement c26f7d8 (controller) - controller: add LimitRanges support 45b5d1b (controller) - users: add users status api 4e16f9b (controller) - ps:add ps:stop/start command c659fa9 (controller) - k8s: add k8s cluster domain 31a625d (controller) - ps:add ps:stop/start command 00a779a (fluentd) - fluentd: support containerd log format f3f1bd4 (fluentd) - nsqd: add stateless nsqd cluster support db7147c (fluentd) - mirrors: delete aliyun mirrors 689c12e (logger) - nsqd: add stateless nsqd cluster support 78ccc5d (logger) - redis: add redis client cluster support 9843f2c (logger) - k8s: add k8s cluster domain 6ba122e (minio) - minio: add pvc support 6973550 (monitor) - monitor: add ingress for monitor cd73305 (monitor) - charts: add volumeName support 4769fe9 (monitor) - nsqd: add stateless nsqd cluster support 87806df (monitor) - k8s: add k8s cluster domain 4db40c4 (nsqd) - nsqd: add stateless nsqd cluster support b6f3d4f (nsqd) - nsqd: add stateless nsqd cluster support 74b85bb (redis) - redis: change redis to statefulset ff98b50 (slugbuilder) - slugbuilder: delete build hook b201c2f (slugbuilder) - buildpacks: use drycc buildpacks","title":"Features"},{"location":"changelogs/v1.4.0/#fixes","text":"0ec042d (builder) - test: fix test case error 4fb113b (builder) - build: base image replace by alpine 443df48 (builder) - minio: fix not bucket error 3dab5b0 (builder) - minio: create bucket error 734fca6 (controller) - autoscale: Fix for autoscale on k8s-1.9+ without breaking manual scaling a7dcd10 (controller) - controller: test pass 93f0f2e (controller) - controller: fix migrations error 4724375 (controller) - controller: fix test error 7bacf29 (controller) - charts: fix clusterrole 90957f7 (controller) - pod: sort events error 440b13e (controller) - controller: review table structure 0a470a6 (controller) - controller: bump tornado 5.1.1 e39218b (controller) - pynsq: no current event loop in thread 1d8630e (controller) - tests: fix test_task.py run error 1ff1202 (controller) - controller: fix test case d8c0da3 (controller) - settings: fix env name 6d8fd36 (database) - 003_restore_from_backup.sh: ignore script exit 1 e0394a9 (database) - minio: fix not bucket error f35f252 (database) - mc: fix create_bucket error 74d6886 (database) - postgres: recovery mode not run e50d0c1 (imagebuilder) - caddy: fix caddy not start f3bec7a (fluentd) - influxdb: fix influxdb host and port bc19f27 (fluentd) - charts: skipped value for daemonEnvironment: Not a table 338d623 (logger) - logger: logger not run in alpine 7788302 (minio) - minio: bump minio version 619eed0 (minio) - fix: use go mod replace dep 3b42122 (monitor) - monitor: fix host error 67998ef (monitor) - influxdb: replace drycc-monitor-influxapi to drycc-monitor-influx-api 2cc361c (registry) - registry: fix test case 548297a (registry) - minio: fix not bucket error 5412ddb (registry) - minio: create bucket error d0d629e (slugbuilder) - slugbuilder:fix normalize_storage path d76ecbe (slugbuilder) - slugbuilder: use v3 api c505e18 (slugbuilder) - shellcheck: SC2039","title":"Fixes"},{"location":"changelogs/v1.4.0/#style","text":"c893a17 (builder) - builder: fmt code bba5795 (controller) - controller: format code d36082b (controller) - controller: fix pep8 66026f2 (controller) - resource: standardize the naming of resource 03d7e2c (controller) - servicecatalog: change servicecatalog to svcat 49dbb6d (controller) - controller: flake8 upgrade cbfc108 (monitor) - monitor: format charts and dashboard ee85954 (slugbuilder) - slugbuilder: use shellcheck 3afed2e (slugbuilder) - docker: simplify dockerfile 36b7f68 (slugrunner) - docker: simplify dockerfile","title":"Style"},{"location":"changelogs/v1.4.0/#maintenance","text":"61bb0ef (builder) - aws: upgrade aws sdk version 0f2e074 (builder) - chore: use go mode replace dep e9a2219 (builder) - builder: delete glide up bb8c518 (builder) - registry: del quay.io fa6d02f (builder) - builder: upgrade go.sum 9d61e8d (builder) - build: upgrade go.mod d763a98 (builder) - charts: upgrade k8s newer API versions d1bc1aa (builder) - pkg: upgrade to new drycc/pkg 02b1e98 (builder) - builder: update go mod 8e17d65 (builder) - builder: change alpine repositories f32b723 (builder) - mirrors: delete aliyun mirrors e33dc61 (builder) - minio: use bin mc replace docker images 3ab4f1c (builder) - builder: update controller-sdk-go b2adfac (builder) - heroku: remove heroku-16 support f429ac8 (builder) - builder: set GIT_LOCK_TIMEOUT to 30 minutes 7197c83 (builder) - go.mod:upgrade require pkg controller-sdk-go 5f3e22d (controller) - deps: bump django from 1.11.21 to 1.11.22 in /rootfs 1db645a (controller) - deps: bump django from 1.11.22 to 1.11.23 in /rootfs fbe8067 (controller) - deps: bump django from 1.11.23 to 1.11.29 in /rootfs 537d667 (controller) - registry: del quay.io a23c65b (controller) - deps: update all deps to the latest version 546337e (controller) - charts: upgrade k8s newer API versions 06023f8 (controller) - workflow-manager: del workflow-manager bba5736 (controller) - controller: change cluster-issuer location 6c43661 (controller) - Certificatechange cluster-issuer location 39a4728 (controller) - controller:change cluster-issuer location del controller-cluster-issuer.yaml 9e96d3f (controller) - Certificate:upgrade version cert-manager.io/v1alpha2 8e68049 (controller) - docker: use INDEX_URL replace index.docker.io 8fda205 (controller) - cert_manager: change certManagerEnabled to global 6fefb6d (controller) - charts: change platformDomain to global 064b2ad (controller) - maintenance: remove maintenance support b8797c9 (controller) - workflow: remove namespace 1b20d76 (controller) - quota: add kube quota config d780075 (controller) - pod: add pod default resources support 3d72c08 (controller) - rename: rename ingress name 0aa6ab9 (controller) - mirrors: delete aliyun mirrors 7533a65 (controller) - heroku: remove heroku-16 support e5a885d (controller) - controller:check mount volume path 9014e74 (controller) - test: optimization Dockerfile.test 0b6ebb2 (controller) - tasks: change apply_async parameters 835f009 (controller) - wsgi: add tornado 6 support 67a4ad7 (controller) - utils: use threads replace asyncio a28949b (controller) - ldap: add AUTH_LDAP_USER_FLAGS_BY_GROUP a903209 (controller) - charts: add custom controller environment variables support e0e783e (controller) - ldap: change filter style d760825 (controller) - scheduler: remove debug log a25928e (controller) - wsgi: remove a wsgi.py file 7b2696e (controller) - log: disable nsq.client info log 8d5c07b (controller) - charts: add default environment 025f4a2 (controller) - controller: change quota name ebda60e (controller) - controller: review pvc code 8832ba9 (controller) - controller: change status\\binding model type and mount path check container_types 7148d04 (controller) - controller: add overcommit cpu and ram support 4d2087c (controller) - limits: modify limits unit verification af36970 (controller) - api: check cpu/memory range for api 329355b (controller) - volumes: modify the volume size 9dfee09 (controller) - LimitRanges: modify the default limits 5205bca (controller) - controller: improve the details of certificate 7ebecdf (database) - mc: upgrade mc to RELEASE.2019-05-23T01-33-27Z 6415e2c (database) - postgres: upgrade to pg13 12e6806 (database) - charts: upgrade k8s newer API versions d294509 (database) - minio: use canary minio test 1bad02e (database) - mirrors: delete aliyun mirrors d51420b (database) - minio: use bin mc replace docker images 4133d05 (imagebuilder) - imagebuilder: update caddy and kaniko 6b4dd18 (imagebuilder) - minio: use bin mc replace docker images 6df9b7c (fluentd) - deps-dev: update rake requirement from ~> 10.0 to ~> 12.3 c2490f8 (fluentd) - fluentd: upgrade fluentd be4a56a (fluentd) - fluentd: add Gemfile.lock 2237f75 (fluentd) - charts: upgrade k8s newer API versions c574065 (fluentd) - charts: upgrade k8s newer API versions 52b8084 (fluentd) - router: delete obsolete router code 3b3cceb (fluentd) - fluentd: remove manifests dir 25c6702 (fluentd) - nsqd: change var name bd571be (fluentd) - nsqd: change DRYCC_NSQD_ADDRESSES to DRYCC_NSQD_ADDRS 72aa4e6 (fluentd) - influxdb: change influxdb service name bd61903 (logger) - logger: use go mod replace dep 69c63a1 (logger) - logger: update go.mod 3aa9cd7 (logger) - registry: del quay.io f058496 (logger) - nsqd: change var name 6d9787c (logger) - nsqd: change DRYCC_NSQD_ADDRESSES to DRYCC_NSQD_ADDRS 85ed307 (logger) - logger: standard naming d88e7b6 (minio) - minio: update minio api to v7 43715d2 (minio) - minio: upgrade minio 0e1239b (minio) - minio: use docker.io replace quay.io f7f047b (minio) - registry: del quay.io afa7128 (minio) - build: upgrade go.mod aff2db5 (minio) - charts: upgrade k8s newer API versions 4547f14 (minio) - pkg: upgrade to new drycc/pkg 2769b85 (minio) - minio: use bin mc replace docker images 35dde8d (monitor) - monitor: update grafana influxdb telegraf 9e3a949 (monitor) - charts: upgrade k8s newer API versions 6af0432 (monitor) - workflow-manager: remove workflow-manager 0611c07 (monitor) - router: delete obsolete router code be04824 (monitor) - cert_manager: change certManagerEnabled to global 3780165 (monitor) - charts: change platformDomain to global 50b04e1 (monitor) - influxdb: remove influxdb admin ui 6ab4d68 (monitor) - influxdb: remove unuse port f1510bd (monitor) - monitor: update grafana dashboard,telegraf inputs.kubernetes f36de2c (monitor) - pvc: upgrade to new format fc78a0a (monitor) - workflow: remove namespace e85890f (monitor) - monitor: monitoring nsqd and redis separately 694f6b1 (monitor) - mirrors: delete aliyun mirrors 4aea36a (monitor) - grafana: add ldap support for grafana 68fc30f (nsqd) - nsq: update nsq 16f32aa (nsqd) - charts: upgrade k8s newer API versions 04db389 (redis) - reids: update to redis 6 3f01bab (redis) - charts: upgrade k8s newer API versions 647e4be (registry) - registry: del quay.io 0bbce99 (registry) - charts: upgrade k8s newer API versions a982b50 (registry) - minio: use bin mc replace docker images e088da3 (registry-proxy) - ingress: renmae use_native_ingress to use_ingress 7e88337 (registry-proxy) - nginx: upgrade nginx to mainline 7204d72 (registry-proxy) - registry: optimizing variable naming 2eafc59 (registry-proxy) - registry-proxy: update nginx 071bd86 (registry-proxy) - charts: upgrade k8s newer API versions c72db96 (registry-proxy) - registry-proxy: change travis icon url ca9f962 (slugbuilder) - slugbuilder: del BUILDPACK_URL support 1b74dd5 (slugbuilder) - slugbuilder: add heroku-20 support 54d4ad2 (slugbuilder) - slugbuilder: del quay.io a78f37e (slugbuilder) - slugbuilder: add heroku-20 stack 94ac94a (slugbuilder) - minio: use bin mc replace docker images 53b4b8b (slugbuilder) - slugbuilder: modify stack priority 58e2bd2 (slugbuilder) - dockerfile: add WORKDIR /tmp b29cd04 (slugbuilder) - slugbuilder: add pre_build.sh 9d319f6 (slugbuilder) - slugbuilder: silent mc command output d1ec3c9 (slugbuilder) - heroku: remove heroku-16 support 5048534 (slugbuilder) - slugbuilder: use drycc stack-images a116537 (slugrunner) - slugrunner: add heroku-20 support a1196bf (slugrunner) - slugrunner: del quay.io 64c96d7 (slugrunner) - slugrunner: add heroku-20 stack cc3e226 (slugrunner) - minio: use bin mc replace docker images 9130bde (slugrunner) - shellcheck: shellcheck installer 4ea33e1 (slugrunner) - slugrunner: modify stack priority 5514e8b (slugrunner) - heroku: remove heroku-16 support be829fb (slugrunner) - slugrunner: use drycc stack-images e1e06be (slugrunner) - slugrunner: remove Dockerfile.heroku-16","title":"Maintenance"},{"location":"changelogs/v1.5.0/","text":"Workflow ## v1.4.0 -> v1.5.0 \u00b6 Releases \u00b6 passport v1.0.0 rabbitmq v1.0.0 imagebuilder v1.0.0 builder v1.2.0 -> v1.3.0 controller v1.3.0 -> v1.4.0 database v1.0.2 -> v1.1.0 fluentd v1.1.0 -> v1.2.0 redis v1.1.0 -> v1.2.0 influxdb v1.0.1 -> v1.1.0 logger v1.1.0 -> v1.2.0 minio v1.1.0 -> v1.2.0 monitor v1.1.0 -> v1.2.0 nsqd v1.1.0 -> v1.2.0 registry v1.0.3 -> v1.1.0 registry-proxy v1.0.2 -> v1.1.0 Features \u00b6 0f5f8e4 (builder) - builder: multi-platform support f269d06 (builder) - build: add buildx supportjkjkk:q 5e72fe8 (builder) - registry: use docker build 25d8a4c (builder) - docker: dealing with the change of docker in kubenetes 1.20 7a3e1c5 (builder) - charts: set the default chart version 46b75ff (builder) - builder: add cloud native buildpacks support 2db2054 (builder) - builder: unified build model 4b7f9d9 (builder) - builder: add initContainers b78c936 (controller) - token: add get token api bac52a5 (controller) - tasks: use celery replace nsqd b9b0c58 (controller) - build: add buildx support 205dcb3 (controller) - influxdb: add influxdb client ff15849 (controller) - influxdb: upgrade to influxdb 2.x 4016244 (controller) - controller: push data to influx fcfce2e (controller) - workflow-manager: add workflow-manager support 00e9bfb (controller) - influxdb: review influxdb code dd644d5 (controller) - docker: dealing with the change of docker in kubenetes 1.20 118278b (controller) - charts: set the default chart version 122a9cd (controller) - oauth2: add oauth2 support 559a5b6 (controller) - controller: use cncf buildpacks replace slugrunner 96130e6 (controller) - charts: database configuration optimization of passport and controller 2ea8508 (controller) - oauth: using passport authentication 868c437 (database) - database: multi-platform support eadd5da (database) - build: add buildx support b6eea4c (database) - docker: dealing with the change of docker in kubenetes 1.20 04a88db (database) - charts: set the default chart version 92ed309 (database) - database: add initContainer ee6b78f (fluentd) - build: add buildx support f523e30 (fluentd) - docker: dealing with the change of docker in kubenetes 1.20 ee47b53 (fluentd) - charts: set the default chart version 80a51af (influxdb) - influxdb: modify influxdb naming rules fb10030 (influxdb) - influxdb: use influxdb v2 0e87ad8 (influxdb) - docker: dealing with the change of docker in kubenetes 1.20 9d10801 (influxdb) - charts: set the default chart version d825c9f (logger) - build: add buildx support b139576 (logger) - docker: dealing with the change of docker in kubenetes 1.20 88f84ea (logger) - charts: set the default chart version 5ccae3e (logger) - dockerfile: remove chmod cmd 193aefc (logger) - logger: add initContainers baee330 (minio) - minio: multi-platform support ad5d055 (minio) - build: add buildx support 19868d4 (minio) - docker: dealing with the change of docker in kubenetes 1.20 4bd84b8 (minio) - charts: set the default chart version 79d1f2f (monitor) - database: multi-platform support 88e5a7f (monitor) - build: add buildx support 5672e99 (monitor) - influxdb: modify influxdb naming rules 8672103 (monitor) - influxdb: use influxdb v2 66cb4c8 (monitor) - docker: dealing with the change of docker in kubenetes 1.20 9576eb3 (monitor) - charts: set the default chart version 30809c9 (monitor) - monitor: add initContainers 70d140c (nsqd) - nsqd: using self compiled nsq binary 1073d4f (nsqd) - nsqd: use GOPATH replace /go e498480 (nsqd) - build: add buildx support cf9b7d5 (nsqd) - docker: dealing with the change of docker in kubenetes 1.20 c335856 (nsqd) - charts: set the default chart version efba713 (redis) - build: add buildx support c7a3b53 (redis) - docker: dealing with the change of docker in kubenetes 1.20 4cdad7b (redis) - charts: set the default chart version 652b443 (registry) - registry: multi-platform support 4060176 (registry) - registry: use docker build 7102a03 (registry) - docker: dealing with the change of docker in kubenetes 1.20 6c8600d (registry) - charts: set the default chart version 33a51c9 (registry) - registry: add initContainers bef70dc (registry-proxy) - build: add buildx support d2319c1 (registry-proxy) - docker: dealing with the change of docker in kubenetes 1.20 02fafed (registry-proxy) - charts: set the default chart version Fixes \u00b6 5499c9a (controller) - gunicorn: gunicorn not running 06e9e88 (controller) - controller: error loading shared library 01b5bd0 (controller) - controller: upgrade celery config 6e32d55 (controller) - controller: fix update resources bug 0e0d53f (controller) - chart: set the domain depends certManagerEnabled 2ac4ca8 (controller) - passport: error loading shared library libexpat.so.1 a0dd517 (fluentd) - fluentd: drone build 6eca2a3 (logger) - logger: golang lint 63b0aa0 (registry) - drone: charts url error Docs \u00b6 472cfcc (controller) - controller organize README.md document d9d6e29 (redis) - redis: delete links that do not exist Test case \u00b6 1468f57 (controller) - controller: add command unittest Maintenance \u00b6 9999bfd (builder) - builder:replace the special words cda8b58 (builder) - builder: remove docker keyword from charts dc575dd (builder) - builder: use imagebuilder replace dockerbuilder d3bb183 (builder) - docker: use the full name of registry 5fe34d1 (builder) - travis: add DEV_REGISTRY 7e36453 (builder) - CICD: use drone 52b8d9d (builder) - drone: add image_registries volumes 65963f4 (builder) - k8s: add privileged to dind d345fcf (builder) - LICENSE: revert modifications to Apache license 7975c99 (builder) - drone: always pull image 59633dd (builder) - builder: modify launch imagebuild pod 8d14e67 (builder) - builder: use Procfile in anywhere 5357fa8 (builder) - go: bump go mod 8d26ac0 (builder) - k8s: k8s deprecated api migration 0af620d (builder) - chars: change org to imageTag ae84303 (builder) - builder: run imagebuider replace pod with job 3b2c496 (builder) - builder: change docs website 5679a4c (builder) - builder: upgrade to golang1.17 a214503 (controller) - controller:replace whitelist with allowlist 375ddcc (controller) - ps:drycc ps:list show autoscale num c32e409 (controller) - ldap: canot register when ldap is enabled c46580a (controller) - controller:modify redis config fa9e87b (controller) - chart:modify controller charts 6f9fd08 (controller) - nsq: remove nsq 994b2dc (controller) - docker-buildx: add check-docker a720c3a (controller) - controller: remove docker keyword from charts e9a5c84 (controller) - docker: use the full name of registry a26614a (controller) - controller: add rabbitmq env 3df229d (controller) - controller: modify database config && remove redis port config && add env prefix with DRYCC 257e94b (controller) - controller: CELERY_BROKER use rabbitmq and modify celery-deployment cronjob f4d6ec3 (controller) - chart: pretty chart format 63e6195 (controller) - influxdb: modify influxdb code 0f6d408 (controller) - CICD: use drone 87bad28 (controller) - python: upgrade to python3.9 e8f7560 (controller) - volumes: modify mount summary 6cf6c6b (controller) - drone: add image_registries volumes a9397e8 (controller) - oauth: modify token Authentication c7f8c8b (controller) - deps: bump django from 2.2.14 to 2.2.18 in /rootfs a1a08aa (controller) - deps: bump djangorestframework from 3.11.0 to 3.11.2 in /rootfs efd78b4 (controller) - deps: bump django from 2.2.18 to 2.2.20 in /rootfs 649b044 (controller) - deps: bump django from 2.2.20 to 2.2.22 in /rootfs 41b742b (controller) - deps: bump django from 2.2.22 to 2.2.24 in /rootfs 22ffe5d (controller) - LICENSE: revert modifications to Apache license c98b468 (controller) - drone: always pull image 20e6edb (controller) - chart: modify the problem of using buildpack db16879 (controller) - controller: pretty pods list print ba6f456 (controller) - test: pretty pods list print 5fce4b7 (controller) - k8s: k8s deprecated api migration e9e0bcb (controller) - oauth: using passport authentication 0311172 (controller) - chars: change org to imageTag 150eff1 (controller) - charts: update cert-manager api version de8545a (controller) - controller: update requirements 1442207 (controller) - controller: using django native JSONFiled ab4e836 (controller) - oauth: modify passport api 5c54e06 (controller) - controller: eliminate pip warnings 870328d (controller) - controller: remove entrypoint 5e5e6ae (controller) - controller: upgrade celery config 607778f (controller) - controller: add initContainer 23dc016 (controller) - chart: set the domain depends certManagerEnabled f3cf20b (controller) - controller: remove default bash env 73f2636 (controller) - controller: modify alpinelinux repositories 498e9f2 (controller) - chart: change certManagerEnabled to boolean type 27f5308 (controller) - passport: exclude cryptography 370b75d (controller) - controller: use sh env 07585b4 (database) - postgres:replace the special words 20172dc (database) - database: remove docker keyword from charts abb9b88 (database) - docker: use the full name of registry e72f58f (database) - chart: modify the off-cluster database a91f64f (database) - travis: add DEV_REGISTRY 614fb76 (database) - tests: use add-host replace link a3428f3 (database) - CICD: use drone 239fef1 (database) - drone: add image_registries volumes 42858e1 (database) - LICENSE: revert modifications to Apache license d0fe850 (database) - drone: always pull image 34a36ad (database) - charts: Nn secret is generated during off-cluster 064ccf4 (database) - database: create database 9228992 (database) - chars: change org to imageTag 9f7810c (database) - database: upgrade to wal-g v1.1 05783f4 (fluentd) - fluentd:replace the special words 0739809 (fluentd) - influxdb:replace monitor-influx with influx f02487c (fluentd) - fluentd: remove docker keyword from charts 2c96cc0 (fluentd) - docker: use the full name of registry b20c429 (fluentd) - charts: remove port config 6dd0197 (fluentd) - travis: add DEV_REGISTRY c5bec51 (fluentd) - CICD: use drone f8524b7 (fluentd) - drone: add image_registries volumes a50878a (fluentd) - LICENSE: revert modifications to Apache license 14fe20e (fluentd) - drone: always pull image 4a2f660 (fluentd) - k8s: k8s deprecated api migration de2dd91 (fluentd) - chars: change org to imageTag a9f1944 (fluentd) - fluentd: upgrade to fluentd1.14 7cb4e95 (influxdb) - influxdb: change username to user 0fdc21b (influxdb) - influxdb: remove docker keyword from charts b2acddb (influxdb) - influxdb: change default path ba88919 (influxdb) - influxdb: add check_env function 9117401 (influxdb) - influxdb: modify init_influxdb has_bucket 092a3e6 (influxdb) - chart: pod not readiness 51de380 (influxdb) - travis: add DEV_REGISTRY 66d7667 (influxdb) - docker: replace influxdb base image 3aa3094 (influxdb) - CICD: use drone 14b9c24 (influxdb) - drone: add image_registries volumes 02b4cd1 (logger) - logger:replace the special words 114b5d5 (logger) - reids: delete the logger prefix of redis 639278a (logger) - redis: remove logger from redis conf 90195e2 (logger) - go: remove GOOS and GOARCH 31e2e27 (logger) - logger: remove docker keyword from charts 8fbd9fa (logger) - docker: use the full name of registry b39df2d (logger) - charts: remove redis\\nsqd port config 35d6d07 (logger) - travis: add DEV_REGISTRY 69aabf5 (logger) - tests: remove docker link e916644 (logger) - CICD: use drone d6872b7 (logger) - drone: add image_registries volumes 37801da (logger) - LICENSE: revert modifications to Apache license cfb4b38 (logger) - drone: always pull image 8bda3bf (logger) - go: bump go mod e13ebfc (logger) - chars: change org to imageTag 38e6d8d (minio) - minio:replace the special words d6925dd (minio) - minio: remove docker keyword from charts d56bc39 (minio) - docker: use the full name of registry e4696cc (minio) - travis: add DEV_REGISTRY 70c5c79 (minio) - minio: use latest version 773cf6c (minio) - Makefile: remove DEV_REGISTRY ?= 5ce5bc6 (minio) - CICD: use drone 5da8be3 (minio) - drone: add image_registries volumes c1f0611 (minio) - LICENSE: revert modifications to Apache license b73f792 (minio) - drone: always pull image 79d1c93 (minio) - go: bump go mod c448899 (minio) - chars: change org to imageTag 15ee49e (minio) - minio: migrate deprecated warning 9968a1a (minio) - minio: upgrade to golang1.7 14fedd2 (monitor) - monitor:replace the special works 52c431a (monitor) - reids: delete the logger prefix of redis 2c95b47 (monitor) - redis: remove logger from redis conf da9bc56 (monitor) - monitor:remove influxdb 53f47b9 (monitor) - grafana: use grafana docker image 5bdb188 (monitor) - grafana: use grafana docker image c0586dd (monitor) - monitor: remove docker keyword from charts 87d02b6 (monitor) - charts: add nodes and persistentvolumes rule 1b5598f (monitor) - monitor: modify grafana dashboard with FLUX and pretty config.toml bcbc0d5 (monitor) - docker: use the full name of registry 9418c9e (monitor) - monitor: fix upload dashboard error and modify INFLUXDB input 589f29a (monitor) - travis: add DEV_REGISTRY f776f8a (monitor) - CICD: use drone 6ca3060 (monitor) - drone: add image_registries volumes 6a9ffb2 (monitor) - LICENSE: revert modifications to Apache license 45e41ed (monitor) - drone: always pull image 654d407 (monitor) - k8s: k8s deprecated api migration 41e9b9c (monitor) - chars: change org to imageTag 99c10d3 (monitor) - charts: update cert-manager api version 9bf83c4 (monitor) - oauth: user oauth passport a128f6d (monitor) - chart: change certManagerEnabled to boolean type 8f897fe (monitor) - chart: set the domain depends certManagerEnabled ba6d793 (nsqd) - README:update travis build status 49879c4 (nsqd) - nsqd: minimum git clone code c5e2680 (nsqd) - nsqd: remove docker keyword from charts 21dd17b (nsqd) - docker: use the full name of registry 7d86b3c (nsqd) - charts: remove port config c073d95 (nsqd) - travis: add DEV_REGISTRY 55c297c (nsqd) - CICD: use drone 165c2ae (nsqd) - drone: add image_registries volumes 9c6a1f8 (nsqd) - LICENSE: revert modifications to Apache license 9283098 (nsqd) - drone: always pull image 46acf8a (nsqd) - k8s: k8s deprecated api migration 43caf80 (nsqd) - chars: change org to imageTag 6897471 (nsqd) - nsqd: use official image 297bc05 (redis) - redis:replace the special words f5f8b5e (redis) - reids: delete the logger prefix of redis af7b657 (redis) - redis: change logger-redis to redis 8dca154 (redis) - redis: remove logger from redis conf eaeda2d (redis) - redis: remove docker keyword from charts 53c6358 (redis) - docker: use the full name of registry ae37416 (redis) - charts: remove port config e985656 (redis) - travis: add DEV_REGISTRY 423336a (redis) - CICD: use drone be64ab4 (redis) - drone: add image_registries volumes 3bec735 (redis) - LICENSE: revert modifications to Apache license 4f934f6 (redis) - drone: always pull image 359b878 (redis) - chars: change org to imageTag 83b8ac2 (registry) - workflow:replace the special words 869b280 (registry) - registry: remove docker keyword from charts 999c1e9 (registry) - docker: use the full name of registry 5652da9 (registry) - travis: add DEV_REGISTRY cc8c6c2 (registry) - CICD: use drone c7bdbd0 (registry) - CICD: pretty .drone.yaml format 5c55a38 (registry) - test: use add-host replace link f8866f3 (registry) - drone: add image_registries volumes 6c8292f (registry) - LICENSE: revert modifications to Apache license 1d50f2c (registry) - drone: always pull image efbca6d (registry) - chars: change org to imageTag 2eafc59 (registry-proxy) - registry-proxy: update nginx 071bd86 (registry-proxy) - charts: upgrade k8s newer API versions c72db96 (registry-proxy) - registry-proxy: change travis icon url 63ffb92 (registry-proxy) - registry-proxy:replace the special works 1d904a6 (registry-proxy) - registry-proxy: remove docker keyword from charts c8200b1 (registry-proxy) - docker: use the full name of registry d3fa939 (registry-proxy) - travis: add DEV_REGISTRY 5a8b353 (registry-proxy) - CICD: use drone 703d05a (registry-proxy) - drone: add image_registries volumes aa71db1 (registry-proxy) - LICENSE: revert modifications to Apache license 710c126 (registry-proxy) - drone: always pull image 2dcc5e6 (registry-proxy) - chars: change org to imageTag","title":"v1.5.0"},{"location":"changelogs/v1.5.0/#workflow-v140-v150","text":"","title":"Workflow ## v1.4.0 -> v1.5.0"},{"location":"changelogs/v1.5.0/#releases","text":"passport v1.0.0 rabbitmq v1.0.0 imagebuilder v1.0.0 builder v1.2.0 -> v1.3.0 controller v1.3.0 -> v1.4.0 database v1.0.2 -> v1.1.0 fluentd v1.1.0 -> v1.2.0 redis v1.1.0 -> v1.2.0 influxdb v1.0.1 -> v1.1.0 logger v1.1.0 -> v1.2.0 minio v1.1.0 -> v1.2.0 monitor v1.1.0 -> v1.2.0 nsqd v1.1.0 -> v1.2.0 registry v1.0.3 -> v1.1.0 registry-proxy v1.0.2 -> v1.1.0","title":"Releases"},{"location":"changelogs/v1.5.0/#features","text":"0f5f8e4 (builder) - builder: multi-platform support f269d06 (builder) - build: add buildx supportjkjkk:q 5e72fe8 (builder) - registry: use docker build 25d8a4c (builder) - docker: dealing with the change of docker in kubenetes 1.20 7a3e1c5 (builder) - charts: set the default chart version 46b75ff (builder) - builder: add cloud native buildpacks support 2db2054 (builder) - builder: unified build model 4b7f9d9 (builder) - builder: add initContainers b78c936 (controller) - token: add get token api bac52a5 (controller) - tasks: use celery replace nsqd b9b0c58 (controller) - build: add buildx support 205dcb3 (controller) - influxdb: add influxdb client ff15849 (controller) - influxdb: upgrade to influxdb 2.x 4016244 (controller) - controller: push data to influx fcfce2e (controller) - workflow-manager: add workflow-manager support 00e9bfb (controller) - influxdb: review influxdb code dd644d5 (controller) - docker: dealing with the change of docker in kubenetes 1.20 118278b (controller) - charts: set the default chart version 122a9cd (controller) - oauth2: add oauth2 support 559a5b6 (controller) - controller: use cncf buildpacks replace slugrunner 96130e6 (controller) - charts: database configuration optimization of passport and controller 2ea8508 (controller) - oauth: using passport authentication 868c437 (database) - database: multi-platform support eadd5da (database) - build: add buildx support b6eea4c (database) - docker: dealing with the change of docker in kubenetes 1.20 04a88db (database) - charts: set the default chart version 92ed309 (database) - database: add initContainer ee6b78f (fluentd) - build: add buildx support f523e30 (fluentd) - docker: dealing with the change of docker in kubenetes 1.20 ee47b53 (fluentd) - charts: set the default chart version 80a51af (influxdb) - influxdb: modify influxdb naming rules fb10030 (influxdb) - influxdb: use influxdb v2 0e87ad8 (influxdb) - docker: dealing with the change of docker in kubenetes 1.20 9d10801 (influxdb) - charts: set the default chart version d825c9f (logger) - build: add buildx support b139576 (logger) - docker: dealing with the change of docker in kubenetes 1.20 88f84ea (logger) - charts: set the default chart version 5ccae3e (logger) - dockerfile: remove chmod cmd 193aefc (logger) - logger: add initContainers baee330 (minio) - minio: multi-platform support ad5d055 (minio) - build: add buildx support 19868d4 (minio) - docker: dealing with the change of docker in kubenetes 1.20 4bd84b8 (minio) - charts: set the default chart version 79d1f2f (monitor) - database: multi-platform support 88e5a7f (monitor) - build: add buildx support 5672e99 (monitor) - influxdb: modify influxdb naming rules 8672103 (monitor) - influxdb: use influxdb v2 66cb4c8 (monitor) - docker: dealing with the change of docker in kubenetes 1.20 9576eb3 (monitor) - charts: set the default chart version 30809c9 (monitor) - monitor: add initContainers 70d140c (nsqd) - nsqd: using self compiled nsq binary 1073d4f (nsqd) - nsqd: use GOPATH replace /go e498480 (nsqd) - build: add buildx support cf9b7d5 (nsqd) - docker: dealing with the change of docker in kubenetes 1.20 c335856 (nsqd) - charts: set the default chart version efba713 (redis) - build: add buildx support c7a3b53 (redis) - docker: dealing with the change of docker in kubenetes 1.20 4cdad7b (redis) - charts: set the default chart version 652b443 (registry) - registry: multi-platform support 4060176 (registry) - registry: use docker build 7102a03 (registry) - docker: dealing with the change of docker in kubenetes 1.20 6c8600d (registry) - charts: set the default chart version 33a51c9 (registry) - registry: add initContainers bef70dc (registry-proxy) - build: add buildx support d2319c1 (registry-proxy) - docker: dealing with the change of docker in kubenetes 1.20 02fafed (registry-proxy) - charts: set the default chart version","title":"Features"},{"location":"changelogs/v1.5.0/#fixes","text":"5499c9a (controller) - gunicorn: gunicorn not running 06e9e88 (controller) - controller: error loading shared library 01b5bd0 (controller) - controller: upgrade celery config 6e32d55 (controller) - controller: fix update resources bug 0e0d53f (controller) - chart: set the domain depends certManagerEnabled 2ac4ca8 (controller) - passport: error loading shared library libexpat.so.1 a0dd517 (fluentd) - fluentd: drone build 6eca2a3 (logger) - logger: golang lint 63b0aa0 (registry) - drone: charts url error","title":"Fixes"},{"location":"changelogs/v1.5.0/#docs","text":"472cfcc (controller) - controller organize README.md document d9d6e29 (redis) - redis: delete links that do not exist","title":"Docs"},{"location":"changelogs/v1.5.0/#test-case","text":"1468f57 (controller) - controller: add command unittest","title":"Test case"},{"location":"changelogs/v1.5.0/#maintenance","text":"9999bfd (builder) - builder:replace the special words cda8b58 (builder) - builder: remove docker keyword from charts dc575dd (builder) - builder: use imagebuilder replace dockerbuilder d3bb183 (builder) - docker: use the full name of registry 5fe34d1 (builder) - travis: add DEV_REGISTRY 7e36453 (builder) - CICD: use drone 52b8d9d (builder) - drone: add image_registries volumes 65963f4 (builder) - k8s: add privileged to dind d345fcf (builder) - LICENSE: revert modifications to Apache license 7975c99 (builder) - drone: always pull image 59633dd (builder) - builder: modify launch imagebuild pod 8d14e67 (builder) - builder: use Procfile in anywhere 5357fa8 (builder) - go: bump go mod 8d26ac0 (builder) - k8s: k8s deprecated api migration 0af620d (builder) - chars: change org to imageTag ae84303 (builder) - builder: run imagebuider replace pod with job 3b2c496 (builder) - builder: change docs website 5679a4c (builder) - builder: upgrade to golang1.17 a214503 (controller) - controller:replace whitelist with allowlist 375ddcc (controller) - ps:drycc ps:list show autoscale num c32e409 (controller) - ldap: canot register when ldap is enabled c46580a (controller) - controller:modify redis config fa9e87b (controller) - chart:modify controller charts 6f9fd08 (controller) - nsq: remove nsq 994b2dc (controller) - docker-buildx: add check-docker a720c3a (controller) - controller: remove docker keyword from charts e9a5c84 (controller) - docker: use the full name of registry a26614a (controller) - controller: add rabbitmq env 3df229d (controller) - controller: modify database config && remove redis port config && add env prefix with DRYCC 257e94b (controller) - controller: CELERY_BROKER use rabbitmq and modify celery-deployment cronjob f4d6ec3 (controller) - chart: pretty chart format 63e6195 (controller) - influxdb: modify influxdb code 0f6d408 (controller) - CICD: use drone 87bad28 (controller) - python: upgrade to python3.9 e8f7560 (controller) - volumes: modify mount summary 6cf6c6b (controller) - drone: add image_registries volumes a9397e8 (controller) - oauth: modify token Authentication c7f8c8b (controller) - deps: bump django from 2.2.14 to 2.2.18 in /rootfs a1a08aa (controller) - deps: bump djangorestframework from 3.11.0 to 3.11.2 in /rootfs efd78b4 (controller) - deps: bump django from 2.2.18 to 2.2.20 in /rootfs 649b044 (controller) - deps: bump django from 2.2.20 to 2.2.22 in /rootfs 41b742b (controller) - deps: bump django from 2.2.22 to 2.2.24 in /rootfs 22ffe5d (controller) - LICENSE: revert modifications to Apache license c98b468 (controller) - drone: always pull image 20e6edb (controller) - chart: modify the problem of using buildpack db16879 (controller) - controller: pretty pods list print ba6f456 (controller) - test: pretty pods list print 5fce4b7 (controller) - k8s: k8s deprecated api migration e9e0bcb (controller) - oauth: using passport authentication 0311172 (controller) - chars: change org to imageTag 150eff1 (controller) - charts: update cert-manager api version de8545a (controller) - controller: update requirements 1442207 (controller) - controller: using django native JSONFiled ab4e836 (controller) - oauth: modify passport api 5c54e06 (controller) - controller: eliminate pip warnings 870328d (controller) - controller: remove entrypoint 5e5e6ae (controller) - controller: upgrade celery config 607778f (controller) - controller: add initContainer 23dc016 (controller) - chart: set the domain depends certManagerEnabled f3cf20b (controller) - controller: remove default bash env 73f2636 (controller) - controller: modify alpinelinux repositories 498e9f2 (controller) - chart: change certManagerEnabled to boolean type 27f5308 (controller) - passport: exclude cryptography 370b75d (controller) - controller: use sh env 07585b4 (database) - postgres:replace the special words 20172dc (database) - database: remove docker keyword from charts abb9b88 (database) - docker: use the full name of registry e72f58f (database) - chart: modify the off-cluster database a91f64f (database) - travis: add DEV_REGISTRY 614fb76 (database) - tests: use add-host replace link a3428f3 (database) - CICD: use drone 239fef1 (database) - drone: add image_registries volumes 42858e1 (database) - LICENSE: revert modifications to Apache license d0fe850 (database) - drone: always pull image 34a36ad (database) - charts: Nn secret is generated during off-cluster 064ccf4 (database) - database: create database 9228992 (database) - chars: change org to imageTag 9f7810c (database) - database: upgrade to wal-g v1.1 05783f4 (fluentd) - fluentd:replace the special words 0739809 (fluentd) - influxdb:replace monitor-influx with influx f02487c (fluentd) - fluentd: remove docker keyword from charts 2c96cc0 (fluentd) - docker: use the full name of registry b20c429 (fluentd) - charts: remove port config 6dd0197 (fluentd) - travis: add DEV_REGISTRY c5bec51 (fluentd) - CICD: use drone f8524b7 (fluentd) - drone: add image_registries volumes a50878a (fluentd) - LICENSE: revert modifications to Apache license 14fe20e (fluentd) - drone: always pull image 4a2f660 (fluentd) - k8s: k8s deprecated api migration de2dd91 (fluentd) - chars: change org to imageTag a9f1944 (fluentd) - fluentd: upgrade to fluentd1.14 7cb4e95 (influxdb) - influxdb: change username to user 0fdc21b (influxdb) - influxdb: remove docker keyword from charts b2acddb (influxdb) - influxdb: change default path ba88919 (influxdb) - influxdb: add check_env function 9117401 (influxdb) - influxdb: modify init_influxdb has_bucket 092a3e6 (influxdb) - chart: pod not readiness 51de380 (influxdb) - travis: add DEV_REGISTRY 66d7667 (influxdb) - docker: replace influxdb base image 3aa3094 (influxdb) - CICD: use drone 14b9c24 (influxdb) - drone: add image_registries volumes 02b4cd1 (logger) - logger:replace the special words 114b5d5 (logger) - reids: delete the logger prefix of redis 639278a (logger) - redis: remove logger from redis conf 90195e2 (logger) - go: remove GOOS and GOARCH 31e2e27 (logger) - logger: remove docker keyword from charts 8fbd9fa (logger) - docker: use the full name of registry b39df2d (logger) - charts: remove redis\\nsqd port config 35d6d07 (logger) - travis: add DEV_REGISTRY 69aabf5 (logger) - tests: remove docker link e916644 (logger) - CICD: use drone d6872b7 (logger) - drone: add image_registries volumes 37801da (logger) - LICENSE: revert modifications to Apache license cfb4b38 (logger) - drone: always pull image 8bda3bf (logger) - go: bump go mod e13ebfc (logger) - chars: change org to imageTag 38e6d8d (minio) - minio:replace the special words d6925dd (minio) - minio: remove docker keyword from charts d56bc39 (minio) - docker: use the full name of registry e4696cc (minio) - travis: add DEV_REGISTRY 70c5c79 (minio) - minio: use latest version 773cf6c (minio) - Makefile: remove DEV_REGISTRY ?= 5ce5bc6 (minio) - CICD: use drone 5da8be3 (minio) - drone: add image_registries volumes c1f0611 (minio) - LICENSE: revert modifications to Apache license b73f792 (minio) - drone: always pull image 79d1c93 (minio) - go: bump go mod c448899 (minio) - chars: change org to imageTag 15ee49e (minio) - minio: migrate deprecated warning 9968a1a (minio) - minio: upgrade to golang1.7 14fedd2 (monitor) - monitor:replace the special works 52c431a (monitor) - reids: delete the logger prefix of redis 2c95b47 (monitor) - redis: remove logger from redis conf da9bc56 (monitor) - monitor:remove influxdb 53f47b9 (monitor) - grafana: use grafana docker image 5bdb188 (monitor) - grafana: use grafana docker image c0586dd (monitor) - monitor: remove docker keyword from charts 87d02b6 (monitor) - charts: add nodes and persistentvolumes rule 1b5598f (monitor) - monitor: modify grafana dashboard with FLUX and pretty config.toml bcbc0d5 (monitor) - docker: use the full name of registry 9418c9e (monitor) - monitor: fix upload dashboard error and modify INFLUXDB input 589f29a (monitor) - travis: add DEV_REGISTRY f776f8a (monitor) - CICD: use drone 6ca3060 (monitor) - drone: add image_registries volumes 6a9ffb2 (monitor) - LICENSE: revert modifications to Apache license 45e41ed (monitor) - drone: always pull image 654d407 (monitor) - k8s: k8s deprecated api migration 41e9b9c (monitor) - chars: change org to imageTag 99c10d3 (monitor) - charts: update cert-manager api version 9bf83c4 (monitor) - oauth: user oauth passport a128f6d (monitor) - chart: change certManagerEnabled to boolean type 8f897fe (monitor) - chart: set the domain depends certManagerEnabled ba6d793 (nsqd) - README:update travis build status 49879c4 (nsqd) - nsqd: minimum git clone code c5e2680 (nsqd) - nsqd: remove docker keyword from charts 21dd17b (nsqd) - docker: use the full name of registry 7d86b3c (nsqd) - charts: remove port config c073d95 (nsqd) - travis: add DEV_REGISTRY 55c297c (nsqd) - CICD: use drone 165c2ae (nsqd) - drone: add image_registries volumes 9c6a1f8 (nsqd) - LICENSE: revert modifications to Apache license 9283098 (nsqd) - drone: always pull image 46acf8a (nsqd) - k8s: k8s deprecated api migration 43caf80 (nsqd) - chars: change org to imageTag 6897471 (nsqd) - nsqd: use official image 297bc05 (redis) - redis:replace the special words f5f8b5e (redis) - reids: delete the logger prefix of redis af7b657 (redis) - redis: change logger-redis to redis 8dca154 (redis) - redis: remove logger from redis conf eaeda2d (redis) - redis: remove docker keyword from charts 53c6358 (redis) - docker: use the full name of registry ae37416 (redis) - charts: remove port config e985656 (redis) - travis: add DEV_REGISTRY 423336a (redis) - CICD: use drone be64ab4 (redis) - drone: add image_registries volumes 3bec735 (redis) - LICENSE: revert modifications to Apache license 4f934f6 (redis) - drone: always pull image 359b878 (redis) - chars: change org to imageTag 83b8ac2 (registry) - workflow:replace the special words 869b280 (registry) - registry: remove docker keyword from charts 999c1e9 (registry) - docker: use the full name of registry 5652da9 (registry) - travis: add DEV_REGISTRY cc8c6c2 (registry) - CICD: use drone c7bdbd0 (registry) - CICD: pretty .drone.yaml format 5c55a38 (registry) - test: use add-host replace link f8866f3 (registry) - drone: add image_registries volumes 6c8292f (registry) - LICENSE: revert modifications to Apache license 1d50f2c (registry) - drone: always pull image efbca6d (registry) - chars: change org to imageTag 2eafc59 (registry-proxy) - registry-proxy: update nginx 071bd86 (registry-proxy) - charts: upgrade k8s newer API versions c72db96 (registry-proxy) - registry-proxy: change travis icon url 63ffb92 (registry-proxy) - registry-proxy:replace the special works 1d904a6 (registry-proxy) - registry-proxy: remove docker keyword from charts c8200b1 (registry-proxy) - docker: use the full name of registry d3fa939 (registry-proxy) - travis: add DEV_REGISTRY 5a8b353 (registry-proxy) - CICD: use drone 703d05a (registry-proxy) - drone: add image_registries volumes aa71db1 (registry-proxy) - LICENSE: revert modifications to Apache license 710c126 (registry-proxy) - drone: always pull image 2dcc5e6 (registry-proxy) - chars: change org to imageTag","title":"Maintenance"},{"location":"changelogs/v1.6.0/","text":"Workflow ## v1.5.0 -> v1.6.0 \u00b6 Releases \u00b6 builder v1.3.0 -> v1.4.0 controller v1.4.0 -> v1.5.0 passport v1.0.0 -> v1.1.0 database v1.1.0 -> v1.2.0 imagebuilder v1.0.1 -> v1.1.0 fluentd v1.2.0 -> v1.3.0 logger v1.2.0 -> v1.3.0 storage v1.2.0 -> v1.3.0 monitor v1.2.0 -> v1.3.0 redis v1.2.0 -> v1.3.0 influxdb v1.1.0 -> v1.2.0 rabbitmq v1.0.0 -> v1.1.0 registry v1.1.0 -> v1.2.0 registry-proxy v1.1.0 -> v1.2.0 Features \u00b6 52517d9 (builder) - builder: update controller-sdk-go 1d78ca0 (builder) - builder: add affinity 26b6980 (builder) - builder: switch charts to oci bfd4385 (controller) - controller: add get manager user status 874208d (controller) - controller: unified measurement model cadf98f (controller) - controller: add admission webhook e0050c2 (controller) - controller: new measurement model a11ba58 (controller) - controller: multi pod restart uses async fb3c15d (controller) - controller: add check app owner status 3d78b76 (controller) - controller: add resource services api 3d6a201 (controller) - controller: add search apps api 01c443a (controller) - controller: add KUBERNETES_CPU_MEMORY_RATIO parameter 7c26232 (controller) - controller: add volume size limit 3bee749 (controller) - controller: add annotations support 23cd97c (controller) - controller: traefik v2 support e37b7db (controller) - controller: add affinity b3b367b (controller) - controller: add volume expand support a4e154a (controller) - controller: add database replica support 2f37216 (controller) - controller: switch wsgi to asgi b3314a5 (controller) - controller: add pod exec api 75df2dc (controller) - controller: add stream support for app logs 4229bad (controller) - ccontroller: switch charts to oci 89bb19b (database) - database: upgrade to pg14 9f45a5d (database) - database: add hugepages support c4008c9 (database) - database: add affinity 411a7b2 (database) - postgres: use patroni 64e5cb0 (database) - database: switch charts to oci 2bab823 (fluentd) - fluentd: switch charts to oci 337ba62 (imagebuilder) - imagebuilder: run podman as rootless 4396ffa (imagebuilder) - imagebuilder: switch to oci charts f37ae09 (influxdb) - influxdb: add affinity 04503b2 (influxdb) - influxdb: add influxdb ha 41ddad5 (influxdb) - influxdb: switch charts to oci 2006480 (logger) - logger: use redis stream replace nsqd ab23d17 (logger) - logger: add affinity 81d4e9d (logger) - logger: switch charts to oci c3d9796 (monitor) - monitor: add affinity cd9de3c (monitor) - monitor: switch to oci charts 318a73f (passport) - passport: add change user confirm 79ef100 (passport) - passport: add re login at authorize 6927bb5 (passport) - passport: add affinity 3146a09 (passport) - passport: add google reCAPTCHA 802abcd (passport) - passport: add replica database support a0dcd1b (passport) - passport: switch wsgi to asgi 4c9dbba (passport) - passport: switch charts to oci 74825f7 (rabbitmq) - rabbitmq: add rabbitmq managentment ingress 12cf7d6 (rabbitmq) - rabbitmq: add affinity 103417d (rabbitmq) - rabbitmq: switch charts to oci 5d428bb (redis) - redis: add affinity a88c1a9 (redis) - redis: switch charts to oci 541585d (registry) - registry: add affinity e9ca9d4 (registry) - registry: add garbage-collect cronjob ec62a59 (registry) - registry: switch charts to oci fde0b07 (registry-proxy) - registry-proxy: switch charts to oci be14eb4 (storage) - minio: add affinity 51af696 (storage) - storage: add k8s csi support 76a75d9 (storage) - storage: add cluster health checker a17dc8c (storage) - storage: switch charts to oci Fixes \u00b6 e4f44fb (builder) - builder: no error return e38dfc7 (builder) - builderControllerHost/ControllerPort init error ff9069f (controller) - controller: influxdb query error f7f5069 (controller) - controller: authentication 500 7e297a8 (controller) - controller: add check remote user status 9db28e1 (controller) - controller: celery MaxRetriesExceededError 4bcff08 (controller) - controller: wrong name d69fde2 (controller) - controller: traefik ingress create error a3ad743 (controller) - fixup(controller: user login error 662c8dd (controller) - controller: change influxdb port 957bdf6 (controller) - controller: validate rsa key pairing before storage 419ec4c (controller) - controller: kubernetes pod/exec cluster role a67edaa (controller) - controller: Cannot routing:disable e09e214 (controller) - controller: allowlist cannot remove 318b126 (controller) - controller: domains update error 92855eb (database) - database: premission denied bde945a (database) - fixup(postgres: support arm, fix Failed to build psutil 7854d45 (database) - fixup(postgres: user name converted to lowercase letters 57b2a07 (fluentd) - fluentd: ifconfig_path not found 20e72b9 (imagebuilder) - imagebuilder: upgrade pack version 651db8a (imagebuilder) - imagebuilder: chown uid gid order d2e9164 (influxdb) - influxdb: proxy not running 3a1d361 (monitor) - monitor: charts naming d754ae0 (monitor) - monitor: telegraf init error 63f9e34 (monitor) - monitor: affinity error 95ae1e5 (passport) - passport: yarn build fail 3f5365e (passport) - passport: wrong name 907f17b (passport) - passport: change uid gid to 1001 e3911e0 (passport) - passport: 'registration_done' not found 2ace5f0 (passport) - passport: ui style b3ba1e1 (passport) - passport privacy policy link 172e9c8 (passport) - passport: check databaseReplicaUrl error a3aeb70 (rabbitmq) - passport: change uid gid to 1001 5c73dcf (redis) - reids: DRYCC_REGISTY misspelling d7e3baf (redis) - redis: env miss cadaa91 (registry) - registry: set gid uid to 1001 d524217 (registry) - registry: storage run error 854f912 (registry) - registry: chown uid gid order e642bb7 (registry-proxy) - registry-proxy: containerPort error 8dfd029 (registry-proxy) - registry-proxy: chown uid gid order bbea364 (storage) - minio: premission denied 97deba1 (storage) - storage: node unimplemented error b9bdeff (storage) - storage: pd can not connect each other Style \u00b6 1edb10c (controller) - controller: database convention over configuration 1960cc3 (database) - database: database name convention over configuration 06d1f5d (imagebuilder) - imagebuilder: URL to Url b8a8941 (passport) - passport: database convention over configuration Maintenance \u00b6 8e9a199 (builder) - builder: upgrade controller-sdk-go 4840151 (builder) - builder: use exec runner replace docker runner 68ccfb1 (builder) - builder: canonical charts naming 8f971cb (builder) - builder: provide any additional service annotations fe2c55d (builder) - dockerfile: use drycc/base image 2b5e706 (builder) - dockerfile: change user and workdir 7a6c8d3 (builder) - builder: set gid uid to 1001 fe494f7 (builder) - dockerfile: use uid gid a7c8752 (builder) - builder: change nodes to pod affinity eb2e94c (builder) - database: bump mc 2022.04.01.23.44.48 cfaae66 (builder) - builder: use registry.drycc.cc replace docker.io d7d2890 (builder) - builder: change default imagebuilder registry ecfdb19 (builder) - imagebuilder: change python-dev registry 6da17f4 (builder) - builder: https://github.com/minio/minio/issues/14331 1a57e5b (builder) - builder: https://github.com/minio/minio/issues/14331 f1464fa (builder) - builder: https://github.com/minio/minio/issues/13799 b1e1c4f (builder) - builder: use env replace creds volume 71a4145 (builder) - builder: bump go.mod 3567688 (builder) - builder: fine management affinity 73ea38b (builder) - builder: change storage to minio 1f91321 (builder) - builder: use testify replace assert d148b9c (builder) - builder: add check storage health b768101 (builder) - builder: change initContainers 1b3bec3 (builder) - builder: add replicas 5cb0d61 (builder) - builder: upgrade to latest controller-sdk-go 98b9d58 (builder) - builder: upgrade new require 65817c3 (builder) - builder: change drycc.cc to www.drycc.cc 4e3f9d0 (controller) - controller: add celery retry mechanism f6716fe (controller) - controller: change cronjob name eb60693 (controller) - controller: refine celery task priority 66905e9 (controller) - controller: change manager auth ea20c41 (controller) - controller: remove start/stop api 4c8fc80 (controller) - controller: improve tasks error handling cf7402e (controller) - controller: add blocklist api 80f14dd (controller) - controller: use get_user_model replace auth.User ffc7bb7 (controller) - controller: use JSONField replace ArrayField 370df8c (controller) - controller: add validate metric 29084ce (controller) - controller: use user id request manager api 718fe12 (controller) - controller change urlpatterns order 71f4042 (controller) - controller: measurements uses lowercase letters e5123ea (controller) - controller: change resource unit to number 18fee9a (controller) - deps: bump celery from 5.1.2 to 5.2.2 in /rootfs ffca6c1 (controller) - controller: use exec runner replace docker runner 9ec12e1 (controller) - controller: simplify drone configuration 4b4749e (controller) - controller: set default CSRF_COOKIE_SECURE false 2ef6338 (controller) - deps: bump django from 3.2.5 to 3.2.10 in /rootfs c7570d0 (controller) - deps: bump django from 3.2.10 to 3.2.11 in /rootfs 8b17bc1 (controller) - controller: canonical charts naming c928fb0 (controller) - controller: use rabbitmq cluster f917185 (controller) - controller: provide any additional service annotations 22a8f63 (controller) - deps: bump django from 3.2.11 to 3.2.12 in /rootfs 3cc3b00 (controller) - dockerfile: use drycc/base image ee274f6 (controller) - controller: set venv profile ce6b069 (controller) - controller: set gid uid to 1001 3a105d3 (controller) - dockerfile: use uid gid 15f9b0e (controller) - controller: code review 01e6fd9 (controller) - controller: use passport user id 893ee31 (controller) - oauth2: update user info pipline 3028fb4 (controller) - user: set AnonymousUser username 5daf82d (controller) - controller: set worker_cancel_long_running_tasks_on_connection_loss 61f2c53 (controller) - controller: change nodes to pod affinity 88feb1d (controller) - imagebuilder: python=3.10.4 rabbitmq=3.9.14 914e03f (controller) - controller: use registry.drycc.cc replace docker.io a5bb548 (controller) - controller: change python-dev registry 3ecdd7c (controller) - controller: add a separate rabbitmqUrl configuration 967cb11 (controller) - controller: remove APP_STORAGE 473d2b5 (controller) - controller: use env replace creds volume e410d4c (controller) - deps: bump django from 3.2.12 to 3.2.13 in /rootfs c6ef777 (controller) - controller: simplified passport config 0fd3233 (controller) - controller: remove settings hardcode a64e99c (controller) - controller: change passport config 62aba25 (controller) - controller: set cronjob timezone to utc 760b70b (controller) - controller: change default ratio 8dffc3a (controller) - controller: fine management affinity 26043c4 (controller) - controller: change default app storage 608bd8d (controller) - deps: bump django from 3.2.13 to 3.2.14 in /rootfs 18ed0c2 (controller) - controller: remove conjob affinity add6712 (controller) - controller: add volume expand support use patch cc1ad13 (controller) - controller: add startupProbe 0e9a603 (controller) - controller: add clearsocial cronjob eb6f05d (controller) - controller: change initContainers 762c676 (controller) - controller: change replicas abd7e8c (controller) - deps: bump django from 3.2.14 to 3.2.15 in /rootfs 07fdf1b (controller) - controller: remove database conn_max_age ef8e41f (controller) - controller: add database replica check 79143f2 (controller) - controller: upgrade new require a624048 (controller) - controller: add app.refresh func annotation b22d367 (controller) - controller: optimize app refresh timing fe98f0c (database) - database: use exec runner replace docker runner 5e00c11 (database) - database: canonical charts naming d2cb860 (database) - database: disable huge_pages 197d80d (database) - database: add persistence 1c3e645 (database) - database: provide any additional service annotations 37730ab (database) - dockerfile: use drycc/base image 5014112 (database) - dockerfile: change entrypoint 29b538e (database) - database: change nodes to pod affinity c2bb074 (database) - database: bump python 3.10.4 and mc 2022.04.01.23.44.48 077a4e9 (database) - database: use registry.drycc.cc replace docker.io 560bdb9 (database) - database: change python-dev registry 1e54b55 (database) - database: https://github.com/minio/minio/issues/14331 d646672 (database) - database: https://github.com/minio/minio/issues/13799 a6ac4e3 (database) - database: use env replace creds volume 9618d87 (database) - database: fine management affinity b823273 (database) - database: change minio to storage 7bd5a90 (database) - database: add check storage health 20c6d96 (database) - database: fix storage run error 8bde830 (database) - database: upgrade to pg 14.5 a33b5e5 (fluentd) - fluentd: update plugins eed7a78 (fluentd) - fluentd: update filter kubernetes setting cc83dd8 (fluentd) - fluentd: update elasticsearch store setting and support exclude specific container logs ba2feb2 (fluentd) - fluentd: use exec runner replace docker runner d528676 (fluentd) - fluentd: simplify drone configuration dece82d (fluentd) - fluentd: canonical charts naming 4e0a802 (fluentd) - fluend: replace nsqd with redis 15ceca0 (fluentd) - dockerfile: use drycc/base image a7f619f (fluentd) - dockerfile: change workdir 9adf5ed (fluentd) - database: bump fluentd 1.14.6 50c14c2 (fluentd) - fluentd: use registry.drycc.cc replace docker.io 83171b1 (fluentd) - fluentd: change python-dev registry ec83581 (fluentd) - fluentd: unified reids declaration 07c63e2 (fluentd) - fluentd: upgrade fluentd 1.15.2 65df9be (imagebuilder) - imagebuilder: update pack version 66cab35 (imagebuilder) - imagebuilder: use dind replace go-dev 0c82060 (imagebuilder) - imagebuilder: use exec runner replace docker runner 8146da9 (imagebuilder) - imagebuilder: canonical charts naming 7d97241 (imagebuilder) - dockerfile: use drycc/base image 07e805c (imagebuilder) - imagebuilder: change default buildpack 8d1038d (imagebuilder) - imagebuilder: upgrade podman to 4.0.1 62d3687 (imagebuilder) - imagebuilder: change workdir to /workspace da8bfb0 (imagebuilder) - imagebuilder: change uid gid to 1001 d44e3bc (imagebuilder) - imagebuilder: upgrade stack 5b0c7e6 (imagebuilder) - imagebuilder: use registry.drycc.cc replace docker.io f74cbf6 (imagebuilder) - imagebuilder: add defaultBuildpacksURL 941d493 (imagebuilder) - imagebuilder: https://github.com/minio/minio/issues/14331 449be91 (imagebuilder) - imagebuilder: https://github.com/minio/minio/issues/13799 63b0523 (imagebuilder) - imagebuilder: use env replace creds volume 4e8a6e5 (imagebuilder) - imagebuilder: add imagebuilder config 2d891f5 (imagebuilder) - imagebuilder: change minio to storage addceda (imagebuilder) - imagebuilder: upgrade new require a6e569f (imagebuilder) - imagebuilder: pack_build add --env-file parameter 6191ff5 (influxdb) - influxdb: use exec runner replace docker runner dc3f8c7 (influxdb) - influxdb: canonical charts naming 6b5c819 (influxdb) - influxdb: new ingress style 68b381d (influxdb) - influxdb: provide any additional service annotations ea20eb8 (influxdb) - dockerfile: use drycc/base image 64c0a71 (influxdb) - influxdb: set gid uid to 1001 a709ca1 (influxdb) - influxdb: use DRYCC_UID DRYCC_GID env 740dff0 (influxdb) - influxdb: use common affinity template e035673 (influxdb) - influxdb: change nodes to pod affinity f1cefbd (influxdb) - influxdb: use registry.drycc.cc replace docker.io a00100e (influxdb) - influxdb: fine management affinity 9d165ef (influxdb) - influxdb: add probe bee7fff (influxdb) - influxdb: upgrade to influxdb 2.4.0 254914c (logger) - logger: use exec runner replace docker runner 8d91c68 (logger) - logger: canonical charts naming b6d2182 (logger) - logger: provide any additional service annotations c35e59a (logger) - dockerfile: use drycc/base image a63c070 (logger) - logger: change workdir to /workspace a594b28 (logger) - logger: set gid uid to 1001 9a90e22 (logger) - dockerfile: use uid gid 36493b4 (logger) - logger: use common affinity template 897a3a5 (logger) - logger: change nodes to pod affinity 03b32ab (logger) - logger: use registry.drycc.cc replace docker.io a50ba5f (logger) - logger: change python-dev registry 23187a3 (logger) - logger: unified reids declaration aaa129a (logger) - logger: fine management affinity be4f656 (logger) - logger: add replicas 7c25459 (logger) - charts: add NetworkPolicy 6810149 (logger) - logger: remove memory storage a918c50 (logger) - logger: add .vscode to .gitignore a415210 (logger) - logger: add log follow support 59b1da3 (logger) - logger: upgrade new require 27cc151 (monitor) - monitor: use exec runner replace docker runner 07d6a9d (monitor) - monitor: canonical charts naming 1054357 (monitor) - monitor: use redis default port e3673df (monitor) - monitor: remove nsqd fc9dd3e (monitor) - monitor: new ingress style 856a898 (monitor) - monitor: add default user env 9857535 (monitor) - monitor: add random user 38b5a04 (monitor) - grafana: oauth auto login 5dfc579 (monitor) - monitor: upgrade version e121b5a (monitor) - monitor: provide any additional service annotations 84462a0 (monitor) - dockerfile: use drycc/base image b9e8ce8 (monitor) - monitor: chore(imagebuilder): change uid gid to 1001 05ee8ab (monitor) - dockerfile: use uid gid e1fa68e (monitor) - monitor: use common affinity template b8f302b (monitor) - monitor: change nodes to pod affinity 4fc991f (monitor) - database: bump telegraf 1.22.0 and grafana 8.4.5 21a2f6a (monitor) - monitor: use registry.drycc.cc replace docker.io acc976f (monitor) - monitor: change python-dev registry 62d76c1 (monitor) - monitor: unified reids declaration b3c57ad (monitor) - monitor: optimize oauth2 configuration 70af6b0 (monitor) - monitor: change passport config 69f9a88 (monitor) - monitor: fine management affinity 2fb278f (monitor) - monitor: rename influxdb port 17548ff (monitor) - grafana: update dashborad 69d7bbd (monitor) - grafana: influx dashborad disk size 75db1b0 (monitor) - monitor: upgrade new grafana/telegraf 80504a1 (monitor) - grafana: update influx and redis dashboard f7078cb (monitor) - monitor:chown use env 91ae0dd (passport) - passport: optimize login display 2d3bbbc (passport) - passport: change drycc logo 59790a7 (passport) - passport: make user email unique faea034 (passport) - passport: use strtobool 1fbf2bc (passport) - passport: use yarn replace npm 119cac8 (passport) - passport: use exec runner replace docker runner cff5062 (passport) - passport: set default CSRF_COOKIE_SECURE false 9cc0210 (passport) - passport: canonical charts naming 9ab3896 (passport) - passport: new ingress style 259ccc9 (passport) - passport: provide any additional service annotations af1bbcd (passport) - dockerfile: use drycc/base image 9ae5373 (passport) - passport: set venv profile 8f61090 (passport) - dockerfile: use uid gid fcaf72d (passport) - passport: upgrade npm package 546dcd5 (passport) - passport: add license 4bda2d6 (passport) - passport: use minify 73b0fd1 (passport) - passport: use common affinity template 278fe7a (passport) - passport: change nodes to pod affinity 3cd93d3 (passport) - passport: add reactive 370b493 (passport) - passport: add footer 483cbd6 (passport) - passport: use h_captcha replace re_captcha 3d1675e (passport) - database: bump python 3.10.4 and node 16.14.2 86a7835 (passport) - passport: use registry.drycc.cc replace docker.io 2d65355 (passport) - passport: change python-dev registry 90c1444 (passport) - passport: unified reids declaration 2e0e417 (passport) - passport: fix firefox footer ad274be (passport) - passport: use bulecss f986d8b (passport) - passport: add main footer 3e52867 (passport) - passport: dynamic settings for vue 38adabc (passport) - passport: change passport config f8d6b60 (passport) - passport: fine management affinity 2cbd79d (passport) - passport: remove database conn_max_age 7122797 (passport) - passport: change drycc.cc to www.drycc.cc 8cc84cd (rabbitmq) - rabbitmq: use exec runner replace docker runner f35930f (rabbitmq) - rabbitmq: add rabbitmq cluster support fbfa3ba (rabbitmq) - rabbitmq: canonical charts naming ca60701 (rabbitmq) - rabbitmq: use volumeClaimTemplates fe5d1b4 (rabbitmq) - rabbitmq: add sharding support 9c4ab97 (rabbitmq) - rabbitmq: provide any additional service annotations 348a88a (rabbitmq) - dockerfile: use drycc/base image 2388be1 (rabbitmq) - rabbitmq: upgrade erlang to 24.2.2 db2eaa5 (rabbitmq) - dockerfile: use uid gid 772afd1 (rabbitmq) - rabbitmq: change to wait pid file 2bfc25e (rabbitmq) - rabbitmq: use common affinity template 11d505e (rabbitmq) - rabbitmq: change nodes to pod affinity 69d63f1 (rabbitmq) - database: bump erlang 24.3.3 and rabbitmq 3.9.14 8380299 (rabbitmq) - rabbitmq: use registry.drycc.cc replace docker.io b3f69f1 (rabbitmq) - rabbitmq: add check rabbitmqLocaltion 5327c76 (rabbitmq) - rabbitmq: fine management affinity 5c66b5a (rabbitmq) - rabbitmq: change probe 27bebf9 (rabbitmq) - rabbitmq: add start-rabbitmq script 86ee6a7 (rabbitmq) - rabbitmq: upgrade to rabbitmq 3.10.7 1f29683 (redis) - redis: use exec runner replace docker runner a5041fc (redis) - redis: canonical charts naming 64468c2 (redis) - redis: add redis persistence de5d753 (redis) - redis: provide any additional service annotations f644639 (redis) - dockerfile: use drycc/base image 98051d2 (redis) - redis: premission denied bcb548e (redis) - dockerfile: use uid gid 524aa41 (redis) - redis: use common affinity template 26c9466 (redis) - redis: change nodes to pod affinity b67d7a2 (redis) - redis: use registry.drycc.cc replace docker.io 839ec50 (redis) - redis: use env replace creds volume 237ca86 (redis) - redis: fine management affinity bdd968d (redis) - redis: upgrade neew require 8b2910f (registry) - registry: use exec runner replace docker runner eedbe78 (registry) - registry: canonical charts naming 0241615 (registry) - registry: provide any additional service annotations 9b58da4 (registry) - dockerfile: use drycc/base image ab6acb7 (registry) - registry: change workdir to /workspace f368bf7 (registry) - registry: use DRYCC_UID DRYCC_GID env f4b9041 (registry) - registry: use common affinity template c2e87ca (registry) - registry: change nodes to pod affinity feb6aba (registry) - database: bump mc 2022.04.01.23.44.48 956932b (registry) - rregistry: use registry.drycc.cc replace docker.io deda8d8 (registry) - registry: move registry-secret.yaml from workflow to registry f52c7bf (registry) - registry: change python-dev registry 007fe03 (registry) - registry: https://github.com/minio/minio/issues/14331 d620c6d (registry) - registry: https://github.com/minio/minio/issues/13799 85e6b73 (registry) - registry: use env replace creds volume 6a1155d (registry) - registry: fine management affinity 7b8ebae (registry) - registry: change minio to storage 1338951 (registry) - registry: add check storage health 2fa769d (registry) - registry: change probe f187cbf (registry) - registry: add replicas 09d8a7b (registry) - registry: upgrade to mc 2022.08.28.20.08.11 4b187b8 (registry-proxy) - registry-proxy: use exec runner replace docker runner 29ffbbe (registry-proxy) - registry-proxy: canonical charts naming 6d783ba (registry-proxy) - registry-proxy: remove use_cni 8cf05cf (registry-proxy) - dockerfile: use drycc/base image 090e286 (registry-proxy) - registry-proxy: chore(imagebuilder): change uid gid to 1001 7cf6120 (registry-proxy) - registry-proxy: use DRYCC_UID DRYCC_GID env 3a00697 (registry-proxy) - registry-proxy: use registry.drycc.cc replace docker.io 30e69e8 (registry-proxy) - registry-proxy: add registry basic auth proxy 942abce (registry-proxy) - registry-proxy: upgrade to nginx 1.23.1 5ea3297 (storage) - minio: use exec runner replace docker runner 8306add (storage) - minio: canonical charts naming c917e9f (storage) - minio: provide any additional service annotations 042c732 (storage) - dockerfile: use drycc/base image 7b47b82 (storage) - minio: change workdir to /workspace 6f3531e (storage) - minio: use DRYCC_UID DRYCC_GID env 9795fb1 (storage) - minio: use common affinity template a7b09c5 (storage) - minio: change nodes to pod affinity 7607342 (storage) - database: bump mc 2022.04.01.23.44.48 and minio 2022.04.01.03.41.39 ea2b2f1 (storage) - minio: use registry.drycc.cc replace docker.io 445b501 (storage) - minio: https://github.com/minio/minio/issues/14331 f19fbc7 (storage) - minio: use env replace creds volume 8982e2e (storage) - minio: use minio to distributed 06bec73 (storage) - minio: fine management affinity 9b8f006 (storage) - storage: remove assert 59d64b9 (storage) - storage: change listen to POD_IP 60044ee (storage) - storage: add juicefs mount options 189f944 (storage) - storage: remove volumeName 302fe89 (storage) - storage: mv to minio dir 6ec586d (storage) - storage: change readinessProbee andlivenessProbe 0e028df (storage) - storage: add minio pdb cf9bd2d (storage) - storage: add check storage health svc 2dd5c9f (storage) - storage: add volumeBindingMode fa2effc (storage) - storage: remove databaseBucket d166cc7 (storage) - charts: format network-policy name d06bcce (storage) - storage: upgrade to golang 1.19 c2ca05c (storage) - storage: upgrade new require","title":"V1.6.0"},{"location":"changelogs/v1.6.0/#workflow-v150-v160","text":"","title":"Workflow ## v1.5.0 -> v1.6.0"},{"location":"changelogs/v1.6.0/#releases","text":"builder v1.3.0 -> v1.4.0 controller v1.4.0 -> v1.5.0 passport v1.0.0 -> v1.1.0 database v1.1.0 -> v1.2.0 imagebuilder v1.0.1 -> v1.1.0 fluentd v1.2.0 -> v1.3.0 logger v1.2.0 -> v1.3.0 storage v1.2.0 -> v1.3.0 monitor v1.2.0 -> v1.3.0 redis v1.2.0 -> v1.3.0 influxdb v1.1.0 -> v1.2.0 rabbitmq v1.0.0 -> v1.1.0 registry v1.1.0 -> v1.2.0 registry-proxy v1.1.0 -> v1.2.0","title":"Releases"},{"location":"changelogs/v1.6.0/#features","text":"52517d9 (builder) - builder: update controller-sdk-go 1d78ca0 (builder) - builder: add affinity 26b6980 (builder) - builder: switch charts to oci bfd4385 (controller) - controller: add get manager user status 874208d (controller) - controller: unified measurement model cadf98f (controller) - controller: add admission webhook e0050c2 (controller) - controller: new measurement model a11ba58 (controller) - controller: multi pod restart uses async fb3c15d (controller) - controller: add check app owner status 3d78b76 (controller) - controller: add resource services api 3d6a201 (controller) - controller: add search apps api 01c443a (controller) - controller: add KUBERNETES_CPU_MEMORY_RATIO parameter 7c26232 (controller) - controller: add volume size limit 3bee749 (controller) - controller: add annotations support 23cd97c (controller) - controller: traefik v2 support e37b7db (controller) - controller: add affinity b3b367b (controller) - controller: add volume expand support a4e154a (controller) - controller: add database replica support 2f37216 (controller) - controller: switch wsgi to asgi b3314a5 (controller) - controller: add pod exec api 75df2dc (controller) - controller: add stream support for app logs 4229bad (controller) - ccontroller: switch charts to oci 89bb19b (database) - database: upgrade to pg14 9f45a5d (database) - database: add hugepages support c4008c9 (database) - database: add affinity 411a7b2 (database) - postgres: use patroni 64e5cb0 (database) - database: switch charts to oci 2bab823 (fluentd) - fluentd: switch charts to oci 337ba62 (imagebuilder) - imagebuilder: run podman as rootless 4396ffa (imagebuilder) - imagebuilder: switch to oci charts f37ae09 (influxdb) - influxdb: add affinity 04503b2 (influxdb) - influxdb: add influxdb ha 41ddad5 (influxdb) - influxdb: switch charts to oci 2006480 (logger) - logger: use redis stream replace nsqd ab23d17 (logger) - logger: add affinity 81d4e9d (logger) - logger: switch charts to oci c3d9796 (monitor) - monitor: add affinity cd9de3c (monitor) - monitor: switch to oci charts 318a73f (passport) - passport: add change user confirm 79ef100 (passport) - passport: add re login at authorize 6927bb5 (passport) - passport: add affinity 3146a09 (passport) - passport: add google reCAPTCHA 802abcd (passport) - passport: add replica database support a0dcd1b (passport) - passport: switch wsgi to asgi 4c9dbba (passport) - passport: switch charts to oci 74825f7 (rabbitmq) - rabbitmq: add rabbitmq managentment ingress 12cf7d6 (rabbitmq) - rabbitmq: add affinity 103417d (rabbitmq) - rabbitmq: switch charts to oci 5d428bb (redis) - redis: add affinity a88c1a9 (redis) - redis: switch charts to oci 541585d (registry) - registry: add affinity e9ca9d4 (registry) - registry: add garbage-collect cronjob ec62a59 (registry) - registry: switch charts to oci fde0b07 (registry-proxy) - registry-proxy: switch charts to oci be14eb4 (storage) - minio: add affinity 51af696 (storage) - storage: add k8s csi support 76a75d9 (storage) - storage: add cluster health checker a17dc8c (storage) - storage: switch charts to oci","title":"Features"},{"location":"changelogs/v1.6.0/#fixes","text":"e4f44fb (builder) - builder: no error return e38dfc7 (builder) - builderControllerHost/ControllerPort init error ff9069f (controller) - controller: influxdb query error f7f5069 (controller) - controller: authentication 500 7e297a8 (controller) - controller: add check remote user status 9db28e1 (controller) - controller: celery MaxRetriesExceededError 4bcff08 (controller) - controller: wrong name d69fde2 (controller) - controller: traefik ingress create error a3ad743 (controller) - fixup(controller: user login error 662c8dd (controller) - controller: change influxdb port 957bdf6 (controller) - controller: validate rsa key pairing before storage 419ec4c (controller) - controller: kubernetes pod/exec cluster role a67edaa (controller) - controller: Cannot routing:disable e09e214 (controller) - controller: allowlist cannot remove 318b126 (controller) - controller: domains update error 92855eb (database) - database: premission denied bde945a (database) - fixup(postgres: support arm, fix Failed to build psutil 7854d45 (database) - fixup(postgres: user name converted to lowercase letters 57b2a07 (fluentd) - fluentd: ifconfig_path not found 20e72b9 (imagebuilder) - imagebuilder: upgrade pack version 651db8a (imagebuilder) - imagebuilder: chown uid gid order d2e9164 (influxdb) - influxdb: proxy not running 3a1d361 (monitor) - monitor: charts naming d754ae0 (monitor) - monitor: telegraf init error 63f9e34 (monitor) - monitor: affinity error 95ae1e5 (passport) - passport: yarn build fail 3f5365e (passport) - passport: wrong name 907f17b (passport) - passport: change uid gid to 1001 e3911e0 (passport) - passport: 'registration_done' not found 2ace5f0 (passport) - passport: ui style b3ba1e1 (passport) - passport privacy policy link 172e9c8 (passport) - passport: check databaseReplicaUrl error a3aeb70 (rabbitmq) - passport: change uid gid to 1001 5c73dcf (redis) - reids: DRYCC_REGISTY misspelling d7e3baf (redis) - redis: env miss cadaa91 (registry) - registry: set gid uid to 1001 d524217 (registry) - registry: storage run error 854f912 (registry) - registry: chown uid gid order e642bb7 (registry-proxy) - registry-proxy: containerPort error 8dfd029 (registry-proxy) - registry-proxy: chown uid gid order bbea364 (storage) - minio: premission denied 97deba1 (storage) - storage: node unimplemented error b9bdeff (storage) - storage: pd can not connect each other","title":"Fixes"},{"location":"changelogs/v1.6.0/#style","text":"1edb10c (controller) - controller: database convention over configuration 1960cc3 (database) - database: database name convention over configuration 06d1f5d (imagebuilder) - imagebuilder: URL to Url b8a8941 (passport) - passport: database convention over configuration","title":"Style"},{"location":"changelogs/v1.6.0/#maintenance","text":"8e9a199 (builder) - builder: upgrade controller-sdk-go 4840151 (builder) - builder: use exec runner replace docker runner 68ccfb1 (builder) - builder: canonical charts naming 8f971cb (builder) - builder: provide any additional service annotations fe2c55d (builder) - dockerfile: use drycc/base image 2b5e706 (builder) - dockerfile: change user and workdir 7a6c8d3 (builder) - builder: set gid uid to 1001 fe494f7 (builder) - dockerfile: use uid gid a7c8752 (builder) - builder: change nodes to pod affinity eb2e94c (builder) - database: bump mc 2022.04.01.23.44.48 cfaae66 (builder) - builder: use registry.drycc.cc replace docker.io d7d2890 (builder) - builder: change default imagebuilder registry ecfdb19 (builder) - imagebuilder: change python-dev registry 6da17f4 (builder) - builder: https://github.com/minio/minio/issues/14331 1a57e5b (builder) - builder: https://github.com/minio/minio/issues/14331 f1464fa (builder) - builder: https://github.com/minio/minio/issues/13799 b1e1c4f (builder) - builder: use env replace creds volume 71a4145 (builder) - builder: bump go.mod 3567688 (builder) - builder: fine management affinity 73ea38b (builder) - builder: change storage to minio 1f91321 (builder) - builder: use testify replace assert d148b9c (builder) - builder: add check storage health b768101 (builder) - builder: change initContainers 1b3bec3 (builder) - builder: add replicas 5cb0d61 (builder) - builder: upgrade to latest controller-sdk-go 98b9d58 (builder) - builder: upgrade new require 65817c3 (builder) - builder: change drycc.cc to www.drycc.cc 4e3f9d0 (controller) - controller: add celery retry mechanism f6716fe (controller) - controller: change cronjob name eb60693 (controller) - controller: refine celery task priority 66905e9 (controller) - controller: change manager auth ea20c41 (controller) - controller: remove start/stop api 4c8fc80 (controller) - controller: improve tasks error handling cf7402e (controller) - controller: add blocklist api 80f14dd (controller) - controller: use get_user_model replace auth.User ffc7bb7 (controller) - controller: use JSONField replace ArrayField 370df8c (controller) - controller: add validate metric 29084ce (controller) - controller: use user id request manager api 718fe12 (controller) - controller change urlpatterns order 71f4042 (controller) - controller: measurements uses lowercase letters e5123ea (controller) - controller: change resource unit to number 18fee9a (controller) - deps: bump celery from 5.1.2 to 5.2.2 in /rootfs ffca6c1 (controller) - controller: use exec runner replace docker runner 9ec12e1 (controller) - controller: simplify drone configuration 4b4749e (controller) - controller: set default CSRF_COOKIE_SECURE false 2ef6338 (controller) - deps: bump django from 3.2.5 to 3.2.10 in /rootfs c7570d0 (controller) - deps: bump django from 3.2.10 to 3.2.11 in /rootfs 8b17bc1 (controller) - controller: canonical charts naming c928fb0 (controller) - controller: use rabbitmq cluster f917185 (controller) - controller: provide any additional service annotations 22a8f63 (controller) - deps: bump django from 3.2.11 to 3.2.12 in /rootfs 3cc3b00 (controller) - dockerfile: use drycc/base image ee274f6 (controller) - controller: set venv profile ce6b069 (controller) - controller: set gid uid to 1001 3a105d3 (controller) - dockerfile: use uid gid 15f9b0e (controller) - controller: code review 01e6fd9 (controller) - controller: use passport user id 893ee31 (controller) - oauth2: update user info pipline 3028fb4 (controller) - user: set AnonymousUser username 5daf82d (controller) - controller: set worker_cancel_long_running_tasks_on_connection_loss 61f2c53 (controller) - controller: change nodes to pod affinity 88feb1d (controller) - imagebuilder: python=3.10.4 rabbitmq=3.9.14 914e03f (controller) - controller: use registry.drycc.cc replace docker.io a5bb548 (controller) - controller: change python-dev registry 3ecdd7c (controller) - controller: add a separate rabbitmqUrl configuration 967cb11 (controller) - controller: remove APP_STORAGE 473d2b5 (controller) - controller: use env replace creds volume e410d4c (controller) - deps: bump django from 3.2.12 to 3.2.13 in /rootfs c6ef777 (controller) - controller: simplified passport config 0fd3233 (controller) - controller: remove settings hardcode a64e99c (controller) - controller: change passport config 62aba25 (controller) - controller: set cronjob timezone to utc 760b70b (controller) - controller: change default ratio 8dffc3a (controller) - controller: fine management affinity 26043c4 (controller) - controller: change default app storage 608bd8d (controller) - deps: bump django from 3.2.13 to 3.2.14 in /rootfs 18ed0c2 (controller) - controller: remove conjob affinity add6712 (controller) - controller: add volume expand support use patch cc1ad13 (controller) - controller: add startupProbe 0e9a603 (controller) - controller: add clearsocial cronjob eb6f05d (controller) - controller: change initContainers 762c676 (controller) - controller: change replicas abd7e8c (controller) - deps: bump django from 3.2.14 to 3.2.15 in /rootfs 07fdf1b (controller) - controller: remove database conn_max_age ef8e41f (controller) - controller: add database replica check 79143f2 (controller) - controller: upgrade new require a624048 (controller) - controller: add app.refresh func annotation b22d367 (controller) - controller: optimize app refresh timing fe98f0c (database) - database: use exec runner replace docker runner 5e00c11 (database) - database: canonical charts naming d2cb860 (database) - database: disable huge_pages 197d80d (database) - database: add persistence 1c3e645 (database) - database: provide any additional service annotations 37730ab (database) - dockerfile: use drycc/base image 5014112 (database) - dockerfile: change entrypoint 29b538e (database) - database: change nodes to pod affinity c2bb074 (database) - database: bump python 3.10.4 and mc 2022.04.01.23.44.48 077a4e9 (database) - database: use registry.drycc.cc replace docker.io 560bdb9 (database) - database: change python-dev registry 1e54b55 (database) - database: https://github.com/minio/minio/issues/14331 d646672 (database) - database: https://github.com/minio/minio/issues/13799 a6ac4e3 (database) - database: use env replace creds volume 9618d87 (database) - database: fine management affinity b823273 (database) - database: change minio to storage 7bd5a90 (database) - database: add check storage health 20c6d96 (database) - database: fix storage run error 8bde830 (database) - database: upgrade to pg 14.5 a33b5e5 (fluentd) - fluentd: update plugins eed7a78 (fluentd) - fluentd: update filter kubernetes setting cc83dd8 (fluentd) - fluentd: update elasticsearch store setting and support exclude specific container logs ba2feb2 (fluentd) - fluentd: use exec runner replace docker runner d528676 (fluentd) - fluentd: simplify drone configuration dece82d (fluentd) - fluentd: canonical charts naming 4e0a802 (fluentd) - fluend: replace nsqd with redis 15ceca0 (fluentd) - dockerfile: use drycc/base image a7f619f (fluentd) - dockerfile: change workdir 9adf5ed (fluentd) - database: bump fluentd 1.14.6 50c14c2 (fluentd) - fluentd: use registry.drycc.cc replace docker.io 83171b1 (fluentd) - fluentd: change python-dev registry ec83581 (fluentd) - fluentd: unified reids declaration 07c63e2 (fluentd) - fluentd: upgrade fluentd 1.15.2 65df9be (imagebuilder) - imagebuilder: update pack version 66cab35 (imagebuilder) - imagebuilder: use dind replace go-dev 0c82060 (imagebuilder) - imagebuilder: use exec runner replace docker runner 8146da9 (imagebuilder) - imagebuilder: canonical charts naming 7d97241 (imagebuilder) - dockerfile: use drycc/base image 07e805c (imagebuilder) - imagebuilder: change default buildpack 8d1038d (imagebuilder) - imagebuilder: upgrade podman to 4.0.1 62d3687 (imagebuilder) - imagebuilder: change workdir to /workspace da8bfb0 (imagebuilder) - imagebuilder: change uid gid to 1001 d44e3bc (imagebuilder) - imagebuilder: upgrade stack 5b0c7e6 (imagebuilder) - imagebuilder: use registry.drycc.cc replace docker.io f74cbf6 (imagebuilder) - imagebuilder: add defaultBuildpacksURL 941d493 (imagebuilder) - imagebuilder: https://github.com/minio/minio/issues/14331 449be91 (imagebuilder) - imagebuilder: https://github.com/minio/minio/issues/13799 63b0523 (imagebuilder) - imagebuilder: use env replace creds volume 4e8a6e5 (imagebuilder) - imagebuilder: add imagebuilder config 2d891f5 (imagebuilder) - imagebuilder: change minio to storage addceda (imagebuilder) - imagebuilder: upgrade new require a6e569f (imagebuilder) - imagebuilder: pack_build add --env-file parameter 6191ff5 (influxdb) - influxdb: use exec runner replace docker runner dc3f8c7 (influxdb) - influxdb: canonical charts naming 6b5c819 (influxdb) - influxdb: new ingress style 68b381d (influxdb) - influxdb: provide any additional service annotations ea20eb8 (influxdb) - dockerfile: use drycc/base image 64c0a71 (influxdb) - influxdb: set gid uid to 1001 a709ca1 (influxdb) - influxdb: use DRYCC_UID DRYCC_GID env 740dff0 (influxdb) - influxdb: use common affinity template e035673 (influxdb) - influxdb: change nodes to pod affinity f1cefbd (influxdb) - influxdb: use registry.drycc.cc replace docker.io a00100e (influxdb) - influxdb: fine management affinity 9d165ef (influxdb) - influxdb: add probe bee7fff (influxdb) - influxdb: upgrade to influxdb 2.4.0 254914c (logger) - logger: use exec runner replace docker runner 8d91c68 (logger) - logger: canonical charts naming b6d2182 (logger) - logger: provide any additional service annotations c35e59a (logger) - dockerfile: use drycc/base image a63c070 (logger) - logger: change workdir to /workspace a594b28 (logger) - logger: set gid uid to 1001 9a90e22 (logger) - dockerfile: use uid gid 36493b4 (logger) - logger: use common affinity template 897a3a5 (logger) - logger: change nodes to pod affinity 03b32ab (logger) - logger: use registry.drycc.cc replace docker.io a50ba5f (logger) - logger: change python-dev registry 23187a3 (logger) - logger: unified reids declaration aaa129a (logger) - logger: fine management affinity be4f656 (logger) - logger: add replicas 7c25459 (logger) - charts: add NetworkPolicy 6810149 (logger) - logger: remove memory storage a918c50 (logger) - logger: add .vscode to .gitignore a415210 (logger) - logger: add log follow support 59b1da3 (logger) - logger: upgrade new require 27cc151 (monitor) - monitor: use exec runner replace docker runner 07d6a9d (monitor) - monitor: canonical charts naming 1054357 (monitor) - monitor: use redis default port e3673df (monitor) - monitor: remove nsqd fc9dd3e (monitor) - monitor: new ingress style 856a898 (monitor) - monitor: add default user env 9857535 (monitor) - monitor: add random user 38b5a04 (monitor) - grafana: oauth auto login 5dfc579 (monitor) - monitor: upgrade version e121b5a (monitor) - monitor: provide any additional service annotations 84462a0 (monitor) - dockerfile: use drycc/base image b9e8ce8 (monitor) - monitor: chore(imagebuilder): change uid gid to 1001 05ee8ab (monitor) - dockerfile: use uid gid e1fa68e (monitor) - monitor: use common affinity template b8f302b (monitor) - monitor: change nodes to pod affinity 4fc991f (monitor) - database: bump telegraf 1.22.0 and grafana 8.4.5 21a2f6a (monitor) - monitor: use registry.drycc.cc replace docker.io acc976f (monitor) - monitor: change python-dev registry 62d76c1 (monitor) - monitor: unified reids declaration b3c57ad (monitor) - monitor: optimize oauth2 configuration 70af6b0 (monitor) - monitor: change passport config 69f9a88 (monitor) - monitor: fine management affinity 2fb278f (monitor) - monitor: rename influxdb port 17548ff (monitor) - grafana: update dashborad 69d7bbd (monitor) - grafana: influx dashborad disk size 75db1b0 (monitor) - monitor: upgrade new grafana/telegraf 80504a1 (monitor) - grafana: update influx and redis dashboard f7078cb (monitor) - monitor:chown use env 91ae0dd (passport) - passport: optimize login display 2d3bbbc (passport) - passport: change drycc logo 59790a7 (passport) - passport: make user email unique faea034 (passport) - passport: use strtobool 1fbf2bc (passport) - passport: use yarn replace npm 119cac8 (passport) - passport: use exec runner replace docker runner cff5062 (passport) - passport: set default CSRF_COOKIE_SECURE false 9cc0210 (passport) - passport: canonical charts naming 9ab3896 (passport) - passport: new ingress style 259ccc9 (passport) - passport: provide any additional service annotations af1bbcd (passport) - dockerfile: use drycc/base image 9ae5373 (passport) - passport: set venv profile 8f61090 (passport) - dockerfile: use uid gid fcaf72d (passport) - passport: upgrade npm package 546dcd5 (passport) - passport: add license 4bda2d6 (passport) - passport: use minify 73b0fd1 (passport) - passport: use common affinity template 278fe7a (passport) - passport: change nodes to pod affinity 3cd93d3 (passport) - passport: add reactive 370b493 (passport) - passport: add footer 483cbd6 (passport) - passport: use h_captcha replace re_captcha 3d1675e (passport) - database: bump python 3.10.4 and node 16.14.2 86a7835 (passport) - passport: use registry.drycc.cc replace docker.io 2d65355 (passport) - passport: change python-dev registry 90c1444 (passport) - passport: unified reids declaration 2e0e417 (passport) - passport: fix firefox footer ad274be (passport) - passport: use bulecss f986d8b (passport) - passport: add main footer 3e52867 (passport) - passport: dynamic settings for vue 38adabc (passport) - passport: change passport config f8d6b60 (passport) - passport: fine management affinity 2cbd79d (passport) - passport: remove database conn_max_age 7122797 (passport) - passport: change drycc.cc to www.drycc.cc 8cc84cd (rabbitmq) - rabbitmq: use exec runner replace docker runner f35930f (rabbitmq) - rabbitmq: add rabbitmq cluster support fbfa3ba (rabbitmq) - rabbitmq: canonical charts naming ca60701 (rabbitmq) - rabbitmq: use volumeClaimTemplates fe5d1b4 (rabbitmq) - rabbitmq: add sharding support 9c4ab97 (rabbitmq) - rabbitmq: provide any additional service annotations 348a88a (rabbitmq) - dockerfile: use drycc/base image 2388be1 (rabbitmq) - rabbitmq: upgrade erlang to 24.2.2 db2eaa5 (rabbitmq) - dockerfile: use uid gid 772afd1 (rabbitmq) - rabbitmq: change to wait pid file 2bfc25e (rabbitmq) - rabbitmq: use common affinity template 11d505e (rabbitmq) - rabbitmq: change nodes to pod affinity 69d63f1 (rabbitmq) - database: bump erlang 24.3.3 and rabbitmq 3.9.14 8380299 (rabbitmq) - rabbitmq: use registry.drycc.cc replace docker.io b3f69f1 (rabbitmq) - rabbitmq: add check rabbitmqLocaltion 5327c76 (rabbitmq) - rabbitmq: fine management affinity 5c66b5a (rabbitmq) - rabbitmq: change probe 27bebf9 (rabbitmq) - rabbitmq: add start-rabbitmq script 86ee6a7 (rabbitmq) - rabbitmq: upgrade to rabbitmq 3.10.7 1f29683 (redis) - redis: use exec runner replace docker runner a5041fc (redis) - redis: canonical charts naming 64468c2 (redis) - redis: add redis persistence de5d753 (redis) - redis: provide any additional service annotations f644639 (redis) - dockerfile: use drycc/base image 98051d2 (redis) - redis: premission denied bcb548e (redis) - dockerfile: use uid gid 524aa41 (redis) - redis: use common affinity template 26c9466 (redis) - redis: change nodes to pod affinity b67d7a2 (redis) - redis: use registry.drycc.cc replace docker.io 839ec50 (redis) - redis: use env replace creds volume 237ca86 (redis) - redis: fine management affinity bdd968d (redis) - redis: upgrade neew require 8b2910f (registry) - registry: use exec runner replace docker runner eedbe78 (registry) - registry: canonical charts naming 0241615 (registry) - registry: provide any additional service annotations 9b58da4 (registry) - dockerfile: use drycc/base image ab6acb7 (registry) - registry: change workdir to /workspace f368bf7 (registry) - registry: use DRYCC_UID DRYCC_GID env f4b9041 (registry) - registry: use common affinity template c2e87ca (registry) - registry: change nodes to pod affinity feb6aba (registry) - database: bump mc 2022.04.01.23.44.48 956932b (registry) - rregistry: use registry.drycc.cc replace docker.io deda8d8 (registry) - registry: move registry-secret.yaml from workflow to registry f52c7bf (registry) - registry: change python-dev registry 007fe03 (registry) - registry: https://github.com/minio/minio/issues/14331 d620c6d (registry) - registry: https://github.com/minio/minio/issues/13799 85e6b73 (registry) - registry: use env replace creds volume 6a1155d (registry) - registry: fine management affinity 7b8ebae (registry) - registry: change minio to storage 1338951 (registry) - registry: add check storage health 2fa769d (registry) - registry: change probe f187cbf (registry) - registry: add replicas 09d8a7b (registry) - registry: upgrade to mc 2022.08.28.20.08.11 4b187b8 (registry-proxy) - registry-proxy: use exec runner replace docker runner 29ffbbe (registry-proxy) - registry-proxy: canonical charts naming 6d783ba (registry-proxy) - registry-proxy: remove use_cni 8cf05cf (registry-proxy) - dockerfile: use drycc/base image 090e286 (registry-proxy) - registry-proxy: chore(imagebuilder): change uid gid to 1001 7cf6120 (registry-proxy) - registry-proxy: use DRYCC_UID DRYCC_GID env 3a00697 (registry-proxy) - registry-proxy: use registry.drycc.cc replace docker.io 30e69e8 (registry-proxy) - registry-proxy: add registry basic auth proxy 942abce (registry-proxy) - registry-proxy: upgrade to nginx 1.23.1 5ea3297 (storage) - minio: use exec runner replace docker runner 8306add (storage) - minio: canonical charts naming c917e9f (storage) - minio: provide any additional service annotations 042c732 (storage) - dockerfile: use drycc/base image 7b47b82 (storage) - minio: change workdir to /workspace 6f3531e (storage) - minio: use DRYCC_UID DRYCC_GID env 9795fb1 (storage) - minio: use common affinity template a7b09c5 (storage) - minio: change nodes to pod affinity 7607342 (storage) - database: bump mc 2022.04.01.23.44.48 and minio 2022.04.01.03.41.39 ea2b2f1 (storage) - minio: use registry.drycc.cc replace docker.io 445b501 (storage) - minio: https://github.com/minio/minio/issues/14331 f19fbc7 (storage) - minio: use env replace creds volume 8982e2e (storage) - minio: use minio to distributed 06bec73 (storage) - minio: fine management affinity 9b8f006 (storage) - storage: remove assert 59d64b9 (storage) - storage: change listen to POD_IP 60044ee (storage) - storage: add juicefs mount options 189f944 (storage) - storage: remove volumeName 302fe89 (storage) - storage: mv to minio dir 6ec586d (storage) - storage: change readinessProbee andlivenessProbe 0e028df (storage) - storage: add minio pdb cf9bd2d (storage) - storage: add check storage health svc 2dd5c9f (storage) - storage: add volumeBindingMode fa2effc (storage) - storage: remove databaseBucket d166cc7 (storage) - charts: format network-policy name d06bcce (storage) - storage: upgrade to golang 1.19 c2ca05c (storage) - storage: upgrade new require","title":"Maintenance"},{"location":"contributing/community/","text":"Community \u00b6 Drycc software is fully open source. As such, the \"Drycc community\" consists of anyone who uses the Drycc software and participates in its evolution, whether by answering questions, finding bugs, suggesting enhancements, or writing documentation or code. Drycc development is coordinated through numerous project repositories on GitHub . Anyone can check out the source code for any Drycc component, fork it, make improvements, and create a pull request to offer those changes back to the Drycc community. Engine Yard maintains the numerous Drycc projects, and as such, decides what ends up in the official GitHub repositories. Drycc depends on the contributions of the community; the maintainers will not ignore pull requests or issues. Drycc uses the timeless, highly efficient, and totally unfair system known as \"Benevolent Dictator for Life\" ( BDFL ). Gabriel Monroy , the creator of Drycc, is our BDFL and has final say over all decisions related to Drycc. Open Source Bounties \u00b6 Drycc projects are bounty-friendly. We believe open source bounty sites can be constructive tools in the development of open source software. Community members are encouraged to a) offer bounties and b) receive bounties for open source contributions that benefit everyone. The Drycc maintainers, however, will not accept bounties on this project but are more than happy to help community members attempting bounties.","title":"Community"},{"location":"contributing/community/#community","text":"Drycc software is fully open source. As such, the \"Drycc community\" consists of anyone who uses the Drycc software and participates in its evolution, whether by answering questions, finding bugs, suggesting enhancements, or writing documentation or code. Drycc development is coordinated through numerous project repositories on GitHub . Anyone can check out the source code for any Drycc component, fork it, make improvements, and create a pull request to offer those changes back to the Drycc community. Engine Yard maintains the numerous Drycc projects, and as such, decides what ends up in the official GitHub repositories. Drycc depends on the contributions of the community; the maintainers will not ignore pull requests or issues. Drycc uses the timeless, highly efficient, and totally unfair system known as \"Benevolent Dictator for Life\" ( BDFL ). Gabriel Monroy , the creator of Drycc, is our BDFL and has final say over all decisions related to Drycc.","title":"Community"},{"location":"contributing/community/#open-source-bounties","text":"Drycc projects are bounty-friendly. We believe open source bounty sites can be constructive tools in the development of open source software. Community members are encouraged to a) offer bounties and b) receive bounties for open source contributions that benefit everyone. The Drycc maintainers, however, will not accept bounties on this project but are more than happy to help community members attempting bounties.","title":"Open Source Bounties"},{"location":"contributing/conduct/","text":"Conduct \u00b6 The Drycc community welcomes and encourages participation by everyone . No matter how you identify yourself or how others perceive you: we welcome you. We welcome contributions from everyone as long as they interact constructively with our community. The Drycc developer community continues to grow, and it is inevitable that disagreements and conflict will arise. We ask that participants conduct themselves according to these principles: Be welcoming, friendly, and patient. Be considerate. Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language. Be respectful. Not all of us will agree all the time, but disagreement is no excuse for poor behavior and bad manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It\u2019s important to remember that a community where people feel uncomfortable or threatened is not a productive one. Be careful in the words that you choose. Be kind to others. Do not insult or put down other participants. Behave professionally. Remember that harassment and sexist, racist, or exclusionary jokes are never appropriate for the community. (Thanks to the Debian and Django communities for their text and their inspiration.)","title":"Conduct"},{"location":"contributing/conduct/#conduct","text":"The Drycc community welcomes and encourages participation by everyone . No matter how you identify yourself or how others perceive you: we welcome you. We welcome contributions from everyone as long as they interact constructively with our community. The Drycc developer community continues to grow, and it is inevitable that disagreements and conflict will arise. We ask that participants conduct themselves according to these principles: Be welcoming, friendly, and patient. Be considerate. Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language. Be respectful. Not all of us will agree all the time, but disagreement is no excuse for poor behavior and bad manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It\u2019s important to remember that a community where people feel uncomfortable or threatened is not a productive one. Be careful in the words that you choose. Be kind to others. Do not insult or put down other participants. Behave professionally. Remember that harassment and sexist, racist, or exclusionary jokes are never appropriate for the community. (Thanks to the Debian and Django communities for their text and their inspiration.)","title":"Conduct"},{"location":"contributing/design-documents/","text":"Design Documents \u00b6 Before submitting a pull request which will significantly alter the behavior of any Drycc component, such as a new feature or major refactoring, contributors should first open an issue representing a design document. Goals \u00b6 Design documents help ensure project contributors: Involve stakeholders as early as possible in a feature's development Ensure code changes accomplish the original motivations and design goals Establish clear acceptance criteria for a feature or change Enforce test-driven design methodology and automated test coverage Contents \u00b6 Design document issues should be named Design Doc: and contain the following sections: Goal \u00b6 This section should briefly describe the proposed change and the motivations behind it. Tests will be written to ensure this design goal is met by the change. This section should also reference a separate GitHub issue tracking the feature or change, which will typically be assigned to a release milestone. Code Changes \u00b6 This section should detail the code changes necessary to accomplish the change, as well as the proposed implementation. This should be as detailed as necessary to help reviewers understand the change. Tests \u00b6 All changes should be covered by automated tests, either unit or integration tests (ideally both). This section should detail how tests will be written to validate that the change accomplishes the design goals and doesn't introduce any regressions. If a change cannot be sufficiently covered by automated testing, the design should be reconsidered. If there is no test coverage whatsoever for an affected section of code, a separate issue should be filed to integrate automated testing with that section of the codebase. The tests described here also form the acceptance criteria for the change, so that when it's completed maintainers can merge the pull request after confirming the tests pass CI. Approval \u00b6 A design document follows the same merge approval review process as final pull requests do, and maintainers will take extra care to ensure that any stakeholders for the change are included in the discussion and review of the design document. Once the design is accepted, the author can complete the change and submit a pull request for review. The pull request should close both the design document for the change as well as any issues that either track the issue or are closed as a result of the change. See Submitting a Pull Request for more information on pull request and commit message formatting.","title":"Design Documents"},{"location":"contributing/design-documents/#design-documents","text":"Before submitting a pull request which will significantly alter the behavior of any Drycc component, such as a new feature or major refactoring, contributors should first open an issue representing a design document.","title":"Design Documents"},{"location":"contributing/design-documents/#goals","text":"Design documents help ensure project contributors: Involve stakeholders as early as possible in a feature's development Ensure code changes accomplish the original motivations and design goals Establish clear acceptance criteria for a feature or change Enforce test-driven design methodology and automated test coverage","title":"Goals"},{"location":"contributing/design-documents/#contents","text":"Design document issues should be named Design Doc: and contain the following sections:","title":"Contents"},{"location":"contributing/design-documents/#goal","text":"This section should briefly describe the proposed change and the motivations behind it. Tests will be written to ensure this design goal is met by the change. This section should also reference a separate GitHub issue tracking the feature or change, which will typically be assigned to a release milestone.","title":"Goal"},{"location":"contributing/design-documents/#code-changes","text":"This section should detail the code changes necessary to accomplish the change, as well as the proposed implementation. This should be as detailed as necessary to help reviewers understand the change.","title":"Code Changes"},{"location":"contributing/design-documents/#tests","text":"All changes should be covered by automated tests, either unit or integration tests (ideally both). This section should detail how tests will be written to validate that the change accomplishes the design goals and doesn't introduce any regressions. If a change cannot be sufficiently covered by automated testing, the design should be reconsidered. If there is no test coverage whatsoever for an affected section of code, a separate issue should be filed to integrate automated testing with that section of the codebase. The tests described here also form the acceptance criteria for the change, so that when it's completed maintainers can merge the pull request after confirming the tests pass CI.","title":"Tests"},{"location":"contributing/design-documents/#approval","text":"A design document follows the same merge approval review process as final pull requests do, and maintainers will take extra care to ensure that any stakeholders for the change are included in the discussion and review of the design document. Once the design is accepted, the author can complete the change and submit a pull request for review. The pull request should close both the design document for the change as well as any issues that either track the issue or are closed as a result of the change. See Submitting a Pull Request for more information on pull request and commit message formatting.","title":"Approval"},{"location":"contributing/development-environment/","text":"Development Environment \u00b6 This document is for developers who are interested in working directly on the Drycc codebase. In this guide, we walk you through the process of setting up a development environment that is suitable for hacking on most Drycc components. We try to make it simple to hack on Drycc components. However, there are necessarily several moving pieces and some setup required. We welcome any suggestions for automating or simplifying this process. Note The Drycc team is actively engaged in containerizing Go and Python based development environments tailored specifically for Drycc development in order to minimize the setup required. This work is ongoing. Refer to the drycc/router project for a working example of a fully containerized development environment. If you're just getting into the Drycc codebase, look for GitHub issues with the label easy-fix . These are more straightforward or low-risk issues and are a great way to become more familiar with Drycc. Prerequisites \u00b6 In order to successfully compile and test Drycc binaries and build Container images of Drycc components, the following are required: git Go 1.5 or later, with support for compiling to linux/amd64 glide golint shellcheck Podman (in a non-Linux environment, you will additionally want [Podman Machine][machine]) For drycc/controller , in particular, you will also need: Python 2.7 or later (with pip ) virtualenv ( sudo pip install virtualenv ) In most cases, you should simply install according to the instructions. There are a few special cases, though. We cover these below. Configuring Go \u00b6 If your local workstation does not support the linux/amd64 target environment, you will have to install Go from source with cross-compile support for that environment. This is because some of the components are built on your local machine and then injected into a container. Homebrew users can just install with cross compiling support: $ brew install go --with-cc-common It is also straightforward to build Go from source: $ sudo su $ curl -sSL https://golang.org/dl/go1.5.src.tar.gz | tar -v -C /usr/local -xz $ cd /usr/local/go/src $ # compile Go for our default platform first, then add cross-compile support $ ./make.bash --no-clean $ GOOS=linux GOARCH=amd64 ./make.bash --no-clean Once you can compile to linux/amd64 , you should be able to compile Drycc components as normal. Fork the Repository \u00b6 Once the prerequisites have been met, we can begin to work with Drycc components. Begin at Github by forking whichever Drycc project you would like to contribute to, then clone that fork locally. Since Drycc is predominantly written in Go, the best place to put it is under $GOPATH/src/github.com/drycc/ . $ mkdir -p $GOPATH/src/github.com/drycc $ cd $GOPATH/src/github.com/drycc $ git clone git@github.com:/.git $ cd Note By checking out the forked copy into the namespace github.com/drycc/ , we are tricking the Go toolchain into seeing our fork as the \"official\" source tree. If you are going to be issuing pull requests to the upstream repository from which you forked, we suggest configuring Git such that you can easily rebase your code to the upstream repository's main branch. There are various strategies for doing this, but the most common is to add an upstream remote: $ git remote add upstream https://github.com/drycc/.git For the sake of simplicity, you may want to point an environment variable to your Drycc code - the directory containing one or more Drycc components: $ export DRYCC=$GOPATH/src/github.com/drycc Throughout the rest of this document, $DRYCC refers to that location. Alternative: Forking with a Pushurl \u00b6 A number of Drycc contributors prefer to pull directly from drycc/ , but push to / . If that workflow suits you better, you can set it up this way: $ git clone git@github.com:drycc/.git $ cd drycc $ git config remote.origin.pushurl git@github.com:/.git In this setup, fetching and pulling code will work directly with the upstream repository, while pushing code will send changes to your fork. This makes it easy to stay up to date, but also make changes and then issue pull requests. Make Your Changes \u00b6 With your development environment set up and the code you wish to work on forked and cloned, you can begin making your changes. Test Your Changes \u00b6 Drycc components each include a comprehensive suite of automated tests, mostly written in Go. See testing for instructions on running the tests. Deploying Your Changes \u00b6 Although writing and executing tests are critical to ensuring code quality, most contributors will also want to deploy their changes to a live environment, whether to make use of those changes or to test them further. The remainder of this section documents the procedure for running officially released Drycc components in a development cluster and replacing any one of those with your customizations. Running a Kubernetes Cluster for Development \u00b6 To run a Kubernetes cluster locally or elsewhere to support your development activities, refer to Drycc installation instructions here . Using a Development Registry \u00b6 To facilitate deploying Container images containing your changes to your Kubernetes cluster, you will need to make use of a Container registry. This is a location to where you can push your custom-built images and from where your Kubernetes cluster can retrieve those same images. If your development cluster runs locally (in Minikube, for instance), the most efficient and economical means of achieving this is to run a Container registry locally as a Container container. To facilitate this, most Drycc components provide a make target to create such a registry: $ make dev-registry In a Linux environment, to begin using the registry: export DRYCC_REGISTRY=:5000 In non-Linux environments: export DRYCC_REGISTRY=:5000 If your development cluster runs on a cloud provider such as Google Container Engine, a local registry such as the one above will not be accessible to your Kubernetes nodes. In such cases, a public registry such as [DockerHub][dh] or quay.io will suffice. To use DockerHub for this purpose, for instance: $ export DRYCC_REGISTRY=\"registry.drycc.cc\" $ export IMAGE_PREFIX= To use quay.io: $ export DRYCC_REGISTRY=quay.io $ export IMAGE_PREFIX= Note the importance of the trailing slash. Dev / Deployment Workflow \u00b6 With a functioning Kubernetes cluster and the officially released Drycc components installed onto it, deployment and further testing of any Drycc component you have made changes to is facilitated by replacing the officially released component with a custom built image that contains your changes. Most Drycc components include Makefiles with targets specifically intended to facilitate this workflow with minimal friction. In the general case, this workflow looks like this: Update source code and commit your changes using git Use make build to build a new Container image Use make dev-release to generate Kubernetes manifest(s) Use make deploy to restart the component using the updated manifest This can be shortened to a one-liner using just the deploy target: $ make deploy Useful Commands \u00b6 Once your customized Drycc component has been deployed, here are some helpful commands that will allow you to inspect your cluster and to troubleshoot, if necessary: See All Drycc Pods \u00b6 $ kubectl --namespace=drycc get pods Describe a Pod \u00b6 This is often useful for troubleshooting pods that are in pending or crashed states: $ kubectl --namespace=drycc describe -f Tail Logs \u00b6 $ kubectl --namespace=drycc logs -f Django Shell \u00b6 Specific to drycc/controller $ kubectl --namespace=drycc exec -it -- python manage.py shell Have commands other Drycc contributors might find useful? Send us a PR! Pull Requests \u00b6 Satisfied with your changes? Share them! Please read Submitting a Pull Request . It contains a checklist of things you should do when proposing a change to any Drycc component.","title":"Development Environment"},{"location":"contributing/development-environment/#development-environment","text":"This document is for developers who are interested in working directly on the Drycc codebase. In this guide, we walk you through the process of setting up a development environment that is suitable for hacking on most Drycc components. We try to make it simple to hack on Drycc components. However, there are necessarily several moving pieces and some setup required. We welcome any suggestions for automating or simplifying this process. Note The Drycc team is actively engaged in containerizing Go and Python based development environments tailored specifically for Drycc development in order to minimize the setup required. This work is ongoing. Refer to the drycc/router project for a working example of a fully containerized development environment. If you're just getting into the Drycc codebase, look for GitHub issues with the label easy-fix . These are more straightforward or low-risk issues and are a great way to become more familiar with Drycc.","title":"Development Environment"},{"location":"contributing/development-environment/#prerequisites","text":"In order to successfully compile and test Drycc binaries and build Container images of Drycc components, the following are required: git Go 1.5 or later, with support for compiling to linux/amd64 glide golint shellcheck Podman (in a non-Linux environment, you will additionally want [Podman Machine][machine]) For drycc/controller , in particular, you will also need: Python 2.7 or later (with pip ) virtualenv ( sudo pip install virtualenv ) In most cases, you should simply install according to the instructions. There are a few special cases, though. We cover these below.","title":"Prerequisites"},{"location":"contributing/development-environment/#configuring-go","text":"If your local workstation does not support the linux/amd64 target environment, you will have to install Go from source with cross-compile support for that environment. This is because some of the components are built on your local machine and then injected into a container. Homebrew users can just install with cross compiling support: $ brew install go --with-cc-common It is also straightforward to build Go from source: $ sudo su $ curl -sSL https://golang.org/dl/go1.5.src.tar.gz | tar -v -C /usr/local -xz $ cd /usr/local/go/src $ # compile Go for our default platform first, then add cross-compile support $ ./make.bash --no-clean $ GOOS=linux GOARCH=amd64 ./make.bash --no-clean Once you can compile to linux/amd64 , you should be able to compile Drycc components as normal.","title":"Configuring Go"},{"location":"contributing/development-environment/#fork-the-repository","text":"Once the prerequisites have been met, we can begin to work with Drycc components. Begin at Github by forking whichever Drycc project you would like to contribute to, then clone that fork locally. Since Drycc is predominantly written in Go, the best place to put it is under $GOPATH/src/github.com/drycc/ . $ mkdir -p $GOPATH/src/github.com/drycc $ cd $GOPATH/src/github.com/drycc $ git clone git@github.com:/.git $ cd Note By checking out the forked copy into the namespace github.com/drycc/ , we are tricking the Go toolchain into seeing our fork as the \"official\" source tree. If you are going to be issuing pull requests to the upstream repository from which you forked, we suggest configuring Git such that you can easily rebase your code to the upstream repository's main branch. There are various strategies for doing this, but the most common is to add an upstream remote: $ git remote add upstream https://github.com/drycc/.git For the sake of simplicity, you may want to point an environment variable to your Drycc code - the directory containing one or more Drycc components: $ export DRYCC=$GOPATH/src/github.com/drycc Throughout the rest of this document, $DRYCC refers to that location.","title":"Fork the Repository"},{"location":"contributing/development-environment/#alternative-forking-with-a-pushurl","text":"A number of Drycc contributors prefer to pull directly from drycc/ , but push to / . If that workflow suits you better, you can set it up this way: $ git clone git@github.com:drycc/.git $ cd drycc $ git config remote.origin.pushurl git@github.com:/.git In this setup, fetching and pulling code will work directly with the upstream repository, while pushing code will send changes to your fork. This makes it easy to stay up to date, but also make changes and then issue pull requests.","title":"Alternative: Forking with a Pushurl"},{"location":"contributing/development-environment/#make-your-changes","text":"With your development environment set up and the code you wish to work on forked and cloned, you can begin making your changes.","title":"Make Your Changes"},{"location":"contributing/development-environment/#test-your-changes","text":"Drycc components each include a comprehensive suite of automated tests, mostly written in Go. See testing for instructions on running the tests.","title":"Test Your Changes"},{"location":"contributing/development-environment/#deploying-your-changes","text":"Although writing and executing tests are critical to ensuring code quality, most contributors will also want to deploy their changes to a live environment, whether to make use of those changes or to test them further. The remainder of this section documents the procedure for running officially released Drycc components in a development cluster and replacing any one of those with your customizations.","title":"Deploying Your Changes"},{"location":"contributing/development-environment/#running-a-kubernetes-cluster-for-development","text":"To run a Kubernetes cluster locally or elsewhere to support your development activities, refer to Drycc installation instructions here .","title":"Running a Kubernetes Cluster for Development"},{"location":"contributing/development-environment/#using-a-development-registry","text":"To facilitate deploying Container images containing your changes to your Kubernetes cluster, you will need to make use of a Container registry. This is a location to where you can push your custom-built images and from where your Kubernetes cluster can retrieve those same images. If your development cluster runs locally (in Minikube, for instance), the most efficient and economical means of achieving this is to run a Container registry locally as a Container container. To facilitate this, most Drycc components provide a make target to create such a registry: $ make dev-registry In a Linux environment, to begin using the registry: export DRYCC_REGISTRY=:5000 In non-Linux environments: export DRYCC_REGISTRY=:5000 If your development cluster runs on a cloud provider such as Google Container Engine, a local registry such as the one above will not be accessible to your Kubernetes nodes. In such cases, a public registry such as [DockerHub][dh] or quay.io will suffice. To use DockerHub for this purpose, for instance: $ export DRYCC_REGISTRY=\"registry.drycc.cc\" $ export IMAGE_PREFIX= To use quay.io: $ export DRYCC_REGISTRY=quay.io $ export IMAGE_PREFIX= Note the importance of the trailing slash.","title":"Using a Development Registry"},{"location":"contributing/development-environment/#dev-deployment-workflow","text":"With a functioning Kubernetes cluster and the officially released Drycc components installed onto it, deployment and further testing of any Drycc component you have made changes to is facilitated by replacing the officially released component with a custom built image that contains your changes. Most Drycc components include Makefiles with targets specifically intended to facilitate this workflow with minimal friction. In the general case, this workflow looks like this: Update source code and commit your changes using git Use make build to build a new Container image Use make dev-release to generate Kubernetes manifest(s) Use make deploy to restart the component using the updated manifest This can be shortened to a one-liner using just the deploy target: $ make deploy","title":"Dev / Deployment Workflow"},{"location":"contributing/development-environment/#useful-commands","text":"Once your customized Drycc component has been deployed, here are some helpful commands that will allow you to inspect your cluster and to troubleshoot, if necessary:","title":"Useful Commands"},{"location":"contributing/development-environment/#see-all-drycc-pods","text":"$ kubectl --namespace=drycc get pods","title":"See All Drycc Pods"},{"location":"contributing/development-environment/#describe-a-pod","text":"This is often useful for troubleshooting pods that are in pending or crashed states: $ kubectl --namespace=drycc describe -f ","title":"Describe a Pod"},{"location":"contributing/development-environment/#tail-logs","text":"$ kubectl --namespace=drycc logs -f ","title":"Tail Logs"},{"location":"contributing/development-environment/#django-shell","text":"Specific to drycc/controller $ kubectl --namespace=drycc exec -it -- python manage.py shell Have commands other Drycc contributors might find useful? Send us a PR!","title":"Django Shell"},{"location":"contributing/development-environment/#pull-requests","text":"Satisfied with your changes? Share them! Please read Submitting a Pull Request . It contains a checklist of things you should do when proposing a change to any Drycc component.","title":"Pull Requests"},{"location":"contributing/maintainers/","text":"Drycc Maintainers \u00b6 This document serves to describe the leadership structure of the Drycc project, and list the current project maintainers. What is a maintainer? \u00b6 (Unabashedly stolen from the Podman project) There are different types of maintainers, with different responsibilities, but all maintainers have 3 things in common: They share responsibility in the project's success. They have made a long-term, recurring time investment to improve the project. They spend that time doing whatever needs to be done, not necessarily what is the most interesting or fun. Maintainers are often under-appreciated, because their work is harder to appreciate. It's easy to appreciate a really cool and technically advanced feature. It's harder to appreciate the absence of bugs, the slow but steady improvement in stability, or the reliability of a release process. But those things distinguish a good project from a great one. Drycc maintainers \u00b6 Drycc has two groups of maintainers in addition to our beloved Benevolent Dictator for Life. BDFL \u00b6 Drycc follows the timeless, highly efficient and totally unfair system known as Benevolent dictator for life . Gabriel Monroy ( @gabrtv ), as creator of the Drycc project, serves as our project's BDFL. While the day-to-day project management is carried out by the maintainers, Gabriel serves as the final arbiter of any disputes and has the final say on project direction. Core maintainers \u00b6 Core maintainers are exceptionally knowledgeable about all areas of Drycc. Some maintainers work on Drycc full-time, although this is not a requirement. The duties of a core maintainer include: Classify and respond to GitHub issues and review pull requests Help to shape the Drycc roadmap and lead efforts to accomplish roadmap milestones Participate actively in feature development and bug fixing Answer questions and help users in the Drycc #community Slack channel The current list of core maintainers can be seen here . No pull requests can be merged until at least one core maintainer signs off with an LGTM . The other LGTM can come from either a core maintainer or contributing maintainer. Contributing maintainers \u00b6 Contributing maintainers are exceptionally knowledgeable about some but not necessarily all areas of Drycc, and are often selected due to specific domain knowledge that complements the project (but a willingness to continually contribute to the project is most important!). Often, core maintainers will ask a contributing maintainer to weigh in on issues, pull requests, or conversations where the contributing maintainer is knowledgeable. The duties of a contributing maintainer are very similar to those of a core maintainer, but they are limited to areas of the Drycc project where the contributing maintainer is knowledgeable. Contributing maintainers are defined in practice as those who have write access to the Drycc repository. All maintainers can review pull requests and add LGTM labels as appropriate. Becoming a maintainer \u00b6 The Drycc project wouldn't be where it is today without its community. Many of the project's community members embody the spirit of maintainership, and have contributed substantially to the project. The contributing maintainers group was created in part so that exceptional members of the community who have an interest in the continued success of the project have the opportunity to join the core maintainers in guiding the future of Drycc. Generally, potential contributing maintainers are selected by the Drycc core maintainers based in part on the following criteria: Sustained contributions to the project over a period of time (usually months) A willingness to help Drycc users on GitHub and in the Drycc #community Slack channel A friendly attitude :) The Drycc core maintainers must unanimously agree before inviting a community member to join as a contributing maintainer, although in many cases the candidate has already been acting in the capacity of a contributing maintainer for some time, and has been consulted on issues, pull requests, etc.","title":"Maintainers"},{"location":"contributing/maintainers/#drycc-maintainers","text":"This document serves to describe the leadership structure of the Drycc project, and list the current project maintainers.","title":"Drycc Maintainers"},{"location":"contributing/maintainers/#what-is-a-maintainer","text":"(Unabashedly stolen from the Podman project) There are different types of maintainers, with different responsibilities, but all maintainers have 3 things in common: They share responsibility in the project's success. They have made a long-term, recurring time investment to improve the project. They spend that time doing whatever needs to be done, not necessarily what is the most interesting or fun. Maintainers are often under-appreciated, because their work is harder to appreciate. It's easy to appreciate a really cool and technically advanced feature. It's harder to appreciate the absence of bugs, the slow but steady improvement in stability, or the reliability of a release process. But those things distinguish a good project from a great one.","title":"What is a maintainer?"},{"location":"contributing/maintainers/#drycc-maintainers_1","text":"Drycc has two groups of maintainers in addition to our beloved Benevolent Dictator for Life.","title":"Drycc maintainers"},{"location":"contributing/maintainers/#bdfl","text":"Drycc follows the timeless, highly efficient and totally unfair system known as Benevolent dictator for life . Gabriel Monroy ( @gabrtv ), as creator of the Drycc project, serves as our project's BDFL. While the day-to-day project management is carried out by the maintainers, Gabriel serves as the final arbiter of any disputes and has the final say on project direction.","title":"BDFL"},{"location":"contributing/maintainers/#core-maintainers","text":"Core maintainers are exceptionally knowledgeable about all areas of Drycc. Some maintainers work on Drycc full-time, although this is not a requirement. The duties of a core maintainer include: Classify and respond to GitHub issues and review pull requests Help to shape the Drycc roadmap and lead efforts to accomplish roadmap milestones Participate actively in feature development and bug fixing Answer questions and help users in the Drycc #community Slack channel The current list of core maintainers can be seen here . No pull requests can be merged until at least one core maintainer signs off with an LGTM . The other LGTM can come from either a core maintainer or contributing maintainer.","title":"Core maintainers"},{"location":"contributing/maintainers/#contributing-maintainers","text":"Contributing maintainers are exceptionally knowledgeable about some but not necessarily all areas of Drycc, and are often selected due to specific domain knowledge that complements the project (but a willingness to continually contribute to the project is most important!). Often, core maintainers will ask a contributing maintainer to weigh in on issues, pull requests, or conversations where the contributing maintainer is knowledgeable. The duties of a contributing maintainer are very similar to those of a core maintainer, but they are limited to areas of the Drycc project where the contributing maintainer is knowledgeable. Contributing maintainers are defined in practice as those who have write access to the Drycc repository. All maintainers can review pull requests and add LGTM labels as appropriate.","title":"Contributing maintainers"},{"location":"contributing/maintainers/#becoming-a-maintainer","text":"The Drycc project wouldn't be where it is today without its community. Many of the project's community members embody the spirit of maintainership, and have contributed substantially to the project. The contributing maintainers group was created in part so that exceptional members of the community who have an interest in the continued success of the project have the opportunity to join the core maintainers in guiding the future of Drycc. Generally, potential contributing maintainers are selected by the Drycc core maintainers based in part on the following criteria: Sustained contributions to the project over a period of time (usually months) A willingness to help Drycc users on GitHub and in the Drycc #community Slack channel A friendly attitude :) The Drycc core maintainers must unanimously agree before inviting a community member to join as a contributing maintainer, although in many cases the candidate has already been acting in the capacity of a contributing maintainer for some time, and has been consulted on issues, pull requests, etc.","title":"Becoming a maintainer"},{"location":"contributing/overview/","text":"Contributor Overview \u00b6 Interested in contributing to a Drycc project? There are lots of ways to help. File Bugs & Enhancements \u00b6 Find a bug? Want to see a new feature? Have a request for the maintainers? Open a Github issue in the applicable repository and we\u2019ll get the conversation started. Our official support channel is the Drycc #community Slack channel . Don't know what the applicable repository for an issue is? Open up in issue in workflow or chat with a maintainer in the Drycc #community Slack channel and we'll make sure it gets to the right place. Additionally, take a look at the troubleshooting documentation for common issues. Before opening a new issue, it's helpful to search and see if anyone else has already reported the problem. You can search through a list of issues for all Drycc projects here . Write Documentation \u00b6 We are always looking to improve and expand our documentation. Most docs reside in the drycc/workflow repository. Simply fork the project, update docs and send us a pull request. Contribute Code \u00b6 We are always looking for help improving the core platform, other workloads, tooling, and test coverage. Interested in contributing code? Let\u2019s chat in the Drycc #community Slack channel . Make sure to check out issues tagged easy fix or help wanted . When you're ready to begin writing code, review Design Documents and get your Development Environment set up. By contributing to any Drycc project you agree to its Developer Certificate of Origin (DCO) . This document was created by the Linux Kernel community and is a simple statement that you, as a contributor, have the legal right to make the contribution. Triage Issues \u00b6 If you don't have time to code, consider helping with triage. The community will thank you for saving them time by spending some of yours. See Triaging Issues for more info. Share your Experience \u00b6 Interact with the community on our user mailing list or live in our Drycc #community Slack channel , where you can chat with other Drycc Workflow users any time of day.","title":"Overview"},{"location":"contributing/overview/#contributor-overview","text":"Interested in contributing to a Drycc project? There are lots of ways to help.","title":"Contributor Overview"},{"location":"contributing/overview/#file-bugs-enhancements","text":"Find a bug? Want to see a new feature? Have a request for the maintainers? Open a Github issue in the applicable repository and we\u2019ll get the conversation started. Our official support channel is the Drycc #community Slack channel . Don't know what the applicable repository for an issue is? Open up in issue in workflow or chat with a maintainer in the Drycc #community Slack channel and we'll make sure it gets to the right place. Additionally, take a look at the troubleshooting documentation for common issues. Before opening a new issue, it's helpful to search and see if anyone else has already reported the problem. You can search through a list of issues for all Drycc projects here .","title":"File Bugs & Enhancements"},{"location":"contributing/overview/#write-documentation","text":"We are always looking to improve and expand our documentation. Most docs reside in the drycc/workflow repository. Simply fork the project, update docs and send us a pull request.","title":"Write Documentation"},{"location":"contributing/overview/#contribute-code","text":"We are always looking for help improving the core platform, other workloads, tooling, and test coverage. Interested in contributing code? Let\u2019s chat in the Drycc #community Slack channel . Make sure to check out issues tagged easy fix or help wanted . When you're ready to begin writing code, review Design Documents and get your Development Environment set up. By contributing to any Drycc project you agree to its Developer Certificate of Origin (DCO) . This document was created by the Linux Kernel community and is a simple statement that you, as a contributor, have the legal right to make the contribution.","title":"Contribute Code"},{"location":"contributing/overview/#triage-issues","text":"If you don't have time to code, consider helping with triage. The community will thank you for saving them time by spending some of yours. See Triaging Issues for more info.","title":"Triage Issues"},{"location":"contributing/overview/#share-your-experience","text":"Interact with the community on our user mailing list or live in our Drycc #community Slack channel , where you can chat with other Drycc Workflow users any time of day.","title":"Share your Experience"},{"location":"contributing/submitting-a-pull-request/","text":"Submitting a Pull Request \u00b6 Proposed changes to Drycc projects are made as GitHub pull requests. Design Document \u00b6 Before opening a pull request, ensure your change also references a design document if the contribution is substantial. For more information, see Design Documents . Single Issue \u00b6 It's hard to reach agreement on the merit of a PR when it isn't focused. When fixing an issue or implementing a new feature, resist the temptation to refactor nearby code or to fix that potential bug you noticed. Instead, open a separate issue or pull request. Keeping concerns separated allows pull requests to be tested, reviewed, and merged more quickly. Squash and rebase the commit or commits in your pull request into logical units of work with git . Include tests and documentation changes in the same commit, so that a revert would remove all traces of the feature or fix. Most pull requests will reference a GitHub issue. In the PR description - not in the commit itself - include a line such as \"closes #1234\". The issue referenced will automatically be closed when your PR is merged. Include Tests \u00b6 If you significantly alter or add functionality to a component that impacts the broader Drycc Workflow PaaS, you should submit a complementary PR to modify or amend end-to-end integration tests. These integration tests can be found in the drycc/workflow-e2e repository. See testing for more information. Include Docs \u00b6 Changes to any Drycc Workflow component that could affect a user's experience also require a change or addition to the relevant documentation. For most Drycc components, this involves updating the component's own documentation. In some cases where a component is tightly integrated into drycc/workflow , its documentation must also be updated. Cross-repo commits \u00b6 If a pull request is part of a larger piece of work involving one or more additional commits in other Workflow repositories, these commits can be referenced in the last PR to be submitted. The downstream e2e test job will then supply every referenced commit (derived from PR issue number supplied) to the test runner so it can source the necessary Container images for inclusion in the generated Workflow chart to be tested. For example, consider paired commits in drycc/controller and drycc/workflow-e2e . The commit body for the first PR in drycc/workflow-e2e would look like: feat(foo_test): add e2e test for feature foo [skip e2e] test for controller#42 Adding [skip e2e] forgoes the e2e tests on this commit. This and any other required PRs aside from the final PR should be submitted first, so that their respective build and image push jobs run. Lastly, the final PR in drycc/controller should be created with the required PR number(s) listed, in the form of [Rr]equires # , for use by the downstream e2e run. feat(foo): add feature foo Requires workflow-e2e#42 Code Standards \u00b6 Drycc components are implemented in Go and Python . For both languages, we agree with The Zen of Python , which emphasizes simple over clever. Readability counts. Go code should always be run through gofmt on the default settings. Lines of code may be up to 99 characters long. Documentation strings and tests are required for all exported functions. Use of third-party go packages should be minimal, but when doing so, such dependencies should be managed via the glide tool. Python code should always adhere to PEP8 , the python code style guide, with the exception that lines of code may be up to 99 characters long. Docstrings and tests are required for all public methods, although the flake8 tool used by Drycc does not enforce this. Commit Style \u00b6 We follow a convention for commit messages borrowed from CoreOS, who borrowed theirs from AngularJS. This is an example of a commit: feat(scripts/test-cluster): add a cluster test command this uses tmux to setup a test cluster that you can easily kill and start for debugging. To make it more formal, it looks something like this: {type}({scope}): {subject} {body} {footer} The allowed {types} are as follows: feat -> feature fix -> bug fix docs -> documentation style -> formatting ref -> refactoring code test -> adding missing tests chore -> maintenance The {scope} can be anything specifying the location(s) of the commit change(s). The {subject} needs to be an imperative, present tense verb: \u201cchange\u201d, not \u201cchanged\u201d nor \u201cchanges\u201d. The first letter should not be capitalized, and there is no dot (.) at the end. Just like the {subject} , the message {body} needs to be in the present tense, and includes the motivation for the change, as well as a contrast with the previous behavior. The first letter in a paragraph must be capitalized. All breaking changes need to be mentioned in the {footer} with the description of the change, the justification behind the change and any migration notes required. Any line of the commit message cannot be longer than 72 characters, with the subject line limited to 50 characters. This allows the message to be easier to read on GitHub as well as in various git tools. Merge Approval \u00b6 Any code change - other than a simple typo fix or one-line documentation change - requires at least two Drycc maintainers to accept it. Maintainers tag pull requests with \" LGTM1 \" and \" LGTM2 \" (Looks Good To Me) labels to indicate acceptance. No pull requests can be merged until at least one core maintainer signs off with an LGTM. The other LGTM can come from either a core maintainer or contributing maintainer. If the PR is from a Drycc maintainer, then he or she should be the one to close it. This keeps the commit stream clean and gives the maintainer the benefit of revisiting the PR before deciding whether or not to merge the changes. An exception to this is when an errant commit needs to be reverted urgently. If necessary, a PR that only reverts a previous commit can be merged without waiting for LGTM approval.","title":"Submitting a Pull Request"},{"location":"contributing/submitting-a-pull-request/#submitting-a-pull-request","text":"Proposed changes to Drycc projects are made as GitHub pull requests.","title":"Submitting a Pull Request"},{"location":"contributing/submitting-a-pull-request/#design-document","text":"Before opening a pull request, ensure your change also references a design document if the contribution is substantial. For more information, see Design Documents .","title":"Design Document"},{"location":"contributing/submitting-a-pull-request/#single-issue","text":"It's hard to reach agreement on the merit of a PR when it isn't focused. When fixing an issue or implementing a new feature, resist the temptation to refactor nearby code or to fix that potential bug you noticed. Instead, open a separate issue or pull request. Keeping concerns separated allows pull requests to be tested, reviewed, and merged more quickly. Squash and rebase the commit or commits in your pull request into logical units of work with git . Include tests and documentation changes in the same commit, so that a revert would remove all traces of the feature or fix. Most pull requests will reference a GitHub issue. In the PR description - not in the commit itself - include a line such as \"closes #1234\". The issue referenced will automatically be closed when your PR is merged.","title":"Single Issue"},{"location":"contributing/submitting-a-pull-request/#include-tests","text":"If you significantly alter or add functionality to a component that impacts the broader Drycc Workflow PaaS, you should submit a complementary PR to modify or amend end-to-end integration tests. These integration tests can be found in the drycc/workflow-e2e repository. See testing for more information.","title":"Include Tests"},{"location":"contributing/submitting-a-pull-request/#include-docs","text":"Changes to any Drycc Workflow component that could affect a user's experience also require a change or addition to the relevant documentation. For most Drycc components, this involves updating the component's own documentation. In some cases where a component is tightly integrated into drycc/workflow , its documentation must also be updated.","title":"Include Docs"},{"location":"contributing/submitting-a-pull-request/#cross-repo-commits","text":"If a pull request is part of a larger piece of work involving one or more additional commits in other Workflow repositories, these commits can be referenced in the last PR to be submitted. The downstream e2e test job will then supply every referenced commit (derived from PR issue number supplied) to the test runner so it can source the necessary Container images for inclusion in the generated Workflow chart to be tested. For example, consider paired commits in drycc/controller and drycc/workflow-e2e . The commit body for the first PR in drycc/workflow-e2e would look like: feat(foo_test): add e2e test for feature foo [skip e2e] test for controller#42 Adding [skip e2e] forgoes the e2e tests on this commit. This and any other required PRs aside from the final PR should be submitted first, so that their respective build and image push jobs run. Lastly, the final PR in drycc/controller should be created with the required PR number(s) listed, in the form of [Rr]equires # , for use by the downstream e2e run. feat(foo): add feature foo Requires workflow-e2e#42","title":"Cross-repo commits"},{"location":"contributing/submitting-a-pull-request/#code-standards","text":"Drycc components are implemented in Go and Python . For both languages, we agree with The Zen of Python , which emphasizes simple over clever. Readability counts. Go code should always be run through gofmt on the default settings. Lines of code may be up to 99 characters long. Documentation strings and tests are required for all exported functions. Use of third-party go packages should be minimal, but when doing so, such dependencies should be managed via the glide tool. Python code should always adhere to PEP8 , the python code style guide, with the exception that lines of code may be up to 99 characters long. Docstrings and tests are required for all public methods, although the flake8 tool used by Drycc does not enforce this.","title":"Code Standards"},{"location":"contributing/submitting-a-pull-request/#commit-style","text":"We follow a convention for commit messages borrowed from CoreOS, who borrowed theirs from AngularJS. This is an example of a commit: feat(scripts/test-cluster): add a cluster test command this uses tmux to setup a test cluster that you can easily kill and start for debugging. To make it more formal, it looks something like this: {type}({scope}): {subject} {body} {footer} The allowed {types} are as follows: feat -> feature fix -> bug fix docs -> documentation style -> formatting ref -> refactoring code test -> adding missing tests chore -> maintenance The {scope} can be anything specifying the location(s) of the commit change(s). The {subject} needs to be an imperative, present tense verb: \u201cchange\u201d, not \u201cchanged\u201d nor \u201cchanges\u201d. The first letter should not be capitalized, and there is no dot (.) at the end. Just like the {subject} , the message {body} needs to be in the present tense, and includes the motivation for the change, as well as a contrast with the previous behavior. The first letter in a paragraph must be capitalized. All breaking changes need to be mentioned in the {footer} with the description of the change, the justification behind the change and any migration notes required. Any line of the commit message cannot be longer than 72 characters, with the subject line limited to 50 characters. This allows the message to be easier to read on GitHub as well as in various git tools.","title":"Commit Style"},{"location":"contributing/submitting-a-pull-request/#merge-approval","text":"Any code change - other than a simple typo fix or one-line documentation change - requires at least two Drycc maintainers to accept it. Maintainers tag pull requests with \" LGTM1 \" and \" LGTM2 \" (Looks Good To Me) labels to indicate acceptance. No pull requests can be merged until at least one core maintainer signs off with an LGTM. The other LGTM can come from either a core maintainer or contributing maintainer. If the PR is from a Drycc maintainer, then he or she should be the one to close it. This keeps the commit stream clean and gives the maintainer the benefit of revisiting the PR before deciding whether or not to merge the changes. An exception to this is when an errant commit needs to be reverted urgently. If necessary, a PR that only reverts a previous commit can be merged without waiting for LGTM approval.","title":"Merge Approval"},{"location":"contributing/testing/","text":"Testing Drycc \u00b6 Each Drycc component is one among an ecosystem of such components - many of which integrate with one another - which makes testing each component thoroughly a matter of paramount importance. Each Drycc component includes its own suite of style checks, unit tests , and black-box type functional tests . Integration tests verify the behavior of the Drycc components together as a system and are provided separately by the drycc/workflow-e2e project. GitHub pull requests for all Drycc components are tested automatically by the Travis CI continuous integration system. Contributors should run the same tests locally before proposing any changes to the Drycc codebase. Set Up the Environment \u00b6 Successfully executing the unit and functional tests for any Drycc component requires that the Development Environment is set up first. Run the Tests \u00b6 The style checks, unit tests, and functional tests for each component can all be executed via make targets: To execute style checks: $ make test-style To execute unit tests: $ make test-unit To execute functional tests: $ make test-functional To execute style checks, unit tests, and functional tests all in one shot: $ make test To execute integration tests, refer to drycc/workflow-e2e documentation.","title":"Testing"},{"location":"contributing/testing/#testing-drycc","text":"Each Drycc component is one among an ecosystem of such components - many of which integrate with one another - which makes testing each component thoroughly a matter of paramount importance. Each Drycc component includes its own suite of style checks, unit tests , and black-box type functional tests . Integration tests verify the behavior of the Drycc components together as a system and are provided separately by the drycc/workflow-e2e project. GitHub pull requests for all Drycc components are tested automatically by the Travis CI continuous integration system. Contributors should run the same tests locally before proposing any changes to the Drycc codebase.","title":"Testing Drycc"},{"location":"contributing/testing/#set-up-the-environment","text":"Successfully executing the unit and functional tests for any Drycc component requires that the Development Environment is set up first.","title":"Set Up the Environment"},{"location":"contributing/testing/#run-the-tests","text":"The style checks, unit tests, and functional tests for each component can all be executed via make targets: To execute style checks: $ make test-style To execute unit tests: $ make test-unit To execute functional tests: $ make test-functional To execute style checks, unit tests, and functional tests all in one shot: $ make test To execute integration tests, refer to drycc/workflow-e2e documentation.","title":"Run the Tests"},{"location":"contributing/triaging-issues/","text":"Triaging Issues \u00b6 Issue triage provides an important way to contribute to an open source project. Triage helps ensure issues resolve quickly by: Describing the issue's intent and purpose is conveyed precisely. This is necessary because it can be difficult for an issue to explain how an end user experiences an problem and what actions they took. Giving a contributor the information they need before they commit to resolving an issue. Lowering the issue count by preventing duplicate issues. Streamlining the development process by preventing duplicate discussions. If you don't have time to code, consider helping with triage. The community will thank you for saving them time by spending some of yours. Ensure the Issue Contains Basic Information \u00b6 Before triaging an issue very far, make sure that the issue's author provided the standard issue information. This will help you make an educated recommendation on how this to categorize the issue. Standard information that should be included in most issues are things such as: the version(s) of Drycc this issue affects a reproducible case if this is a bug page URL if this is a docs issue or the name of a man page Depending on the issue, you might not feel all this information is needed. Use your best judgment. If you cannot triage an issue using what its author provided, explain kindly to the author that they must provide the above information to clarify the problem. If the author provides the recommended information but you are still unable to triage the issue, request additional information. Do this kindly and politely because you are asking for more of the author's time. If the author does not respond requested information within the timespan of a week, close the issue with a kind note stating that the author can request for the issue to be reopened when the necessary information is provided. Classifying the Issue \u00b6 An issue can have multiple of the following labels: Issue Kind \u00b6 Kind Description bug Bugs are bugs. The cause may or may not be known at triage time so debugging should be taken account into the time estimate. docs Writing documentation, man pages, articles, blogs, or other significant word-driven task. enhancement Enhancements can drastically improve usability or performance of a component. question Contains a user or contributor question requiring a response. security Security-related issues such as TLS encryption, network segregation, authn/authz features, etc. Functional Area \u00b6 builder cache contrib and provisioning client controller database docs kubernetes registry router store (Ceph) tests Easy Fix \u00b6 \"Easy Fix\" issues are a way for a new contributor to find issues that are fit for their experience level. These issues are typically for users who are new to Drycc, and possibly Go, and is looking to help while learning the basics. Prioritizing issues \u00b6 When attached to a specific milestone, an issue can be attributed one of the following labels to indicate their degree of priority. Priority Description priority 0 Urgent: Security, critical bugs, blocking issues. Drop everything and fix this today, then consider creating a patch release. priority 1 Serious: Impedes user actions or is a regression. Fix this before the next planned release. And that's it. That should be all the information required for a new or existing contributor to come in an resolve an issue.","title":"Triaging Issues"},{"location":"contributing/triaging-issues/#triaging-issues","text":"Issue triage provides an important way to contribute to an open source project. Triage helps ensure issues resolve quickly by: Describing the issue's intent and purpose is conveyed precisely. This is necessary because it can be difficult for an issue to explain how an end user experiences an problem and what actions they took. Giving a contributor the information they need before they commit to resolving an issue. Lowering the issue count by preventing duplicate issues. Streamlining the development process by preventing duplicate discussions. If you don't have time to code, consider helping with triage. The community will thank you for saving them time by spending some of yours.","title":"Triaging Issues"},{"location":"contributing/triaging-issues/#ensure-the-issue-contains-basic-information","text":"Before triaging an issue very far, make sure that the issue's author provided the standard issue information. This will help you make an educated recommendation on how this to categorize the issue. Standard information that should be included in most issues are things such as: the version(s) of Drycc this issue affects a reproducible case if this is a bug page URL if this is a docs issue or the name of a man page Depending on the issue, you might not feel all this information is needed. Use your best judgment. If you cannot triage an issue using what its author provided, explain kindly to the author that they must provide the above information to clarify the problem. If the author provides the recommended information but you are still unable to triage the issue, request additional information. Do this kindly and politely because you are asking for more of the author's time. If the author does not respond requested information within the timespan of a week, close the issue with a kind note stating that the author can request for the issue to be reopened when the necessary information is provided.","title":"Ensure the Issue Contains Basic Information"},{"location":"contributing/triaging-issues/#classifying-the-issue","text":"An issue can have multiple of the following labels:","title":"Classifying the Issue"},{"location":"contributing/triaging-issues/#issue-kind","text":"Kind Description bug Bugs are bugs. The cause may or may not be known at triage time so debugging should be taken account into the time estimate. docs Writing documentation, man pages, articles, blogs, or other significant word-driven task. enhancement Enhancements can drastically improve usability or performance of a component. question Contains a user or contributor question requiring a response. security Security-related issues such as TLS encryption, network segregation, authn/authz features, etc.","title":"Issue Kind"},{"location":"contributing/triaging-issues/#functional-area","text":"builder cache contrib and provisioning client controller database docs kubernetes registry router store (Ceph) tests","title":"Functional Area"},{"location":"contributing/triaging-issues/#easy-fix","text":"\"Easy Fix\" issues are a way for a new contributor to find issues that are fit for their experience level. These issues are typically for users who are new to Drycc, and possibly Go, and is looking to help while learning the basics.","title":"Easy Fix"},{"location":"contributing/triaging-issues/#prioritizing-issues","text":"When attached to a specific milestone, an issue can be attributed one of the following labels to indicate their degree of priority. Priority Description priority 0 Urgent: Security, critical bugs, blocking issues. Drop everything and fix this today, then consider creating a patch release. priority 1 Serious: Impedes user actions or is a regression. Fix this before the next planned release. And that's it. That should be all the information required for a new or existing contributor to come in an resolve an issue.","title":"Prioritizing issues"},{"location":"diagrams/","text":"Architecture Diagrams \u00b6 This is an OmniGraffle file which holds the source materials for the following images. To update a chart: Make your modification! Select \"File > Export\" Select \"Entire Document Choose: Scale: 100% Set Bitmap Resolution to 72 dpi (for web) Uncheck \"Transparent Background\" Select \"images\" directory Click \"Export\" This should update all of the graphics in one go! Commit and pull-request.","title":"Architecture Diagrams"},{"location":"diagrams/#architecture-diagrams","text":"This is an OmniGraffle file which holds the source materials for the following images. To update a chart: Make your modification! Select \"File > Export\" Select \"Entire Document Choose: Scale: 100% Set Bitmap Resolution to 72 dpi (for web) Uncheck \"Transparent Background\" Select \"images\" directory Click \"Export\" This should update all of the graphics in one go! Commit and pull-request.","title":"Architecture Diagrams"},{"location":"installing-workflow/","text":"Installing Drycc Workflow \u00b6 This document is aimed at those who have already provisioned a Kubernetes v1.16.15+ cluster and want to install Drycc Workflow. If help is required getting started with Kubernetes and Drycc Workflow, follow the quickstart guide for assistance. Prerequisites \u00b6 Verify the Kubernetes system requirements Install Helm and Drycc Workflow CLI tools Check Your Setup \u00b6 Check that the helm command is available and the version is v2.5.0 or newer. $ helm version Client: &version.Version{SemVer:\"v2.5.0\", GitCommit:\"012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6\", GitTreeState:\"clean\"} Server: &version.Version{SemVer:\"v2.5.0\", GitCommit:\"012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6\", GitTreeState:\"clean\"} Choose Your Deployment Strategy \u00b6 Drycc Workflow includes everything it needs to run out of the box. However, these defaults are aimed at simplicity rather than production readiness. Production and staging deployments of Workflow should, at a minimum, use off-cluster storage which is used by Workflow components to store and backup critical data. Should an operator need to completely re-install Workflow, the required components can recover from off-cluster storage. See the documentation for configuring object storage for more details. More rigorous installations would benefit from using outside sources for the following things: * Postgres - For example AWS RDS. * Registry - This includes quay.io , dockerhub , Amazon ECR , and Google GCR . * Redis - Such as AWS Elasticache * Grafana Gateway \u00b6 Now, workflow requires that gateway and cert-manager must be installed. Any compatible Kubernetes entry controller can be used. Install Drycc Workflow \u00b6 If the version of helm is 3.0 +; you need to create the namespace in advance: kubectl create ns drycc If you want to change it, set the variable when using helm. $ helm install drycc oci://registry.drycc.cc/charts/workflow \\ --namespace drycc \\ --set builder.imageRegistry=quay.io \\ --set imagebuilder.imageRegistry=quay.io \\ --set controller.imageRegistry=quay.io \\ --set database.imageRegistry=quay.io \\ --set fluentbit.imageRegistry=quay.io \\ --set redis.imageRegistry=quay.io \\ --set rabbitmq.imageRegistry=quay.io \\ --set logger.imageRegistry=quay.io \\ --set storage.imageRegistry=quay.io \\ --set monitor.imageRegistry=quay.io \\ --set registry.imageRegistry=quay.io \\ --set registry-proxy.imageRegistry=quay.io \\ --set global.platformDomain=drycc.cc Helm will install a variety of Kubernetes resources in the drycc namespace. Wait for the pods that Helm launched to be ready. Monitor their status by running: $ kubectl --namespace=drycc get pods If it's preferred to have kubectl automatically update as the pod states change, run (type Ctrl-C to stop the watch): $ kubectl --namespace=drycc get pods -w Depending on the order in which the Workflow components initialize, some pods may restart. This is common during the installation: if a component's dependencies are not yet available, that component will exit and Kubernetes will automatically restart it. Here, it can be seen that the controller, builder and registry all took a few loops before they were able to start: $ kubectl --namespace=drycc get pods NAME READY STATUS RESTARTS AGE drycc-builder-574483744-l15zj 1/1 Running 0 4m drycc-controller-3953262871-pncgq 1/1 Running 2 4m drycc-controller-celery-cmxxn 3/3 Running 0 4m drycc-database-83844344-47ld6 1/1 Running 0 4m drycc-logger-176328999-wjckx 1/1 Running 4 4m drycc-logger-fluentbit-zxnqb 1/1 Running 0 4m drycc-redis-304849759-1f35p 1/1 Running 0 4m drycc-storage-676004970-nxqgt 1/1 Running 0 4m drycc-monitor-grafana-432627134-lnl2h 1/1 Running 0 4m drycc-monitor-telegraf-wmcmn 1/1 Running 1 4m drycc-registry-756475849-lwc6b 1/1 Running 1 4m drycc-registry-proxy-96c4p 1/1 Running 0 4m drycc-rabbitmq-0 1/1 Running 0 4m Once all of the pods are in the READY state, Drycc Workflow is up and running! For more installation parameters, please check the values.yaml file of workflow. After installing Workflow, register a user and deploy an application . Configure DNS \u00b6 User must to set up a hostname, and assumes the drycc-builder.$host convention. We need to point the drycc-builder.$host record to the public IP address of your builder. You can get the public IP using the following command. A wildcard entry is necessary here as apps will use the same rule after they are deployed. $ kubectl get svc drycc-builder --namespace drycc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE drycc-builder 10.0.25.3 138.91.243.152 2222:31625/TCP 33m If we were using drycc.cc as a hostname, we would need to create the following A DNS records. Name Type Value drycc-builder.drycc.cc A 138.91.243.152 Once all of the pods are in the READY state, and drycc-builder.$host resolves to the external IP found above, Workflow is up and running! After installing Workflow, register a user and deploy an application . If your k8s does not provide public network loadblance, you need to install TCP proxy services such as haproxy on machines that can access both internal and external networks, and then expose 80 and 443 .","title":"Installing Workflow"},{"location":"installing-workflow/#installing-drycc-workflow","text":"This document is aimed at those who have already provisioned a Kubernetes v1.16.15+ cluster and want to install Drycc Workflow. If help is required getting started with Kubernetes and Drycc Workflow, follow the quickstart guide for assistance.","title":"Installing Drycc Workflow"},{"location":"installing-workflow/#prerequisites","text":"Verify the Kubernetes system requirements Install Helm and Drycc Workflow CLI tools","title":"Prerequisites"},{"location":"installing-workflow/#check-your-setup","text":"Check that the helm command is available and the version is v2.5.0 or newer. $ helm version Client: &version.Version{SemVer:\"v2.5.0\", GitCommit:\"012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6\", GitTreeState:\"clean\"} Server: &version.Version{SemVer:\"v2.5.0\", GitCommit:\"012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6\", GitTreeState:\"clean\"}","title":"Check Your Setup"},{"location":"installing-workflow/#choose-your-deployment-strategy","text":"Drycc Workflow includes everything it needs to run out of the box. However, these defaults are aimed at simplicity rather than production readiness. Production and staging deployments of Workflow should, at a minimum, use off-cluster storage which is used by Workflow components to store and backup critical data. Should an operator need to completely re-install Workflow, the required components can recover from off-cluster storage. See the documentation for configuring object storage for more details. More rigorous installations would benefit from using outside sources for the following things: * Postgres - For example AWS RDS. * Registry - This includes quay.io , dockerhub , Amazon ECR , and Google GCR . * Redis - Such as AWS Elasticache * Grafana","title":"Choose Your Deployment Strategy"},{"location":"installing-workflow/#gateway","text":"Now, workflow requires that gateway and cert-manager must be installed. Any compatible Kubernetes entry controller can be used.","title":"Gateway"},{"location":"installing-workflow/#install-drycc-workflow","text":"If the version of helm is 3.0 +; you need to create the namespace in advance: kubectl create ns drycc If you want to change it, set the variable when using helm. $ helm install drycc oci://registry.drycc.cc/charts/workflow \\ --namespace drycc \\ --set builder.imageRegistry=quay.io \\ --set imagebuilder.imageRegistry=quay.io \\ --set controller.imageRegistry=quay.io \\ --set database.imageRegistry=quay.io \\ --set fluentbit.imageRegistry=quay.io \\ --set redis.imageRegistry=quay.io \\ --set rabbitmq.imageRegistry=quay.io \\ --set logger.imageRegistry=quay.io \\ --set storage.imageRegistry=quay.io \\ --set monitor.imageRegistry=quay.io \\ --set registry.imageRegistry=quay.io \\ --set registry-proxy.imageRegistry=quay.io \\ --set global.platformDomain=drycc.cc Helm will install a variety of Kubernetes resources in the drycc namespace. Wait for the pods that Helm launched to be ready. Monitor their status by running: $ kubectl --namespace=drycc get pods If it's preferred to have kubectl automatically update as the pod states change, run (type Ctrl-C to stop the watch): $ kubectl --namespace=drycc get pods -w Depending on the order in which the Workflow components initialize, some pods may restart. This is common during the installation: if a component's dependencies are not yet available, that component will exit and Kubernetes will automatically restart it. Here, it can be seen that the controller, builder and registry all took a few loops before they were able to start: $ kubectl --namespace=drycc get pods NAME READY STATUS RESTARTS AGE drycc-builder-574483744-l15zj 1/1 Running 0 4m drycc-controller-3953262871-pncgq 1/1 Running 2 4m drycc-controller-celery-cmxxn 3/3 Running 0 4m drycc-database-83844344-47ld6 1/1 Running 0 4m drycc-logger-176328999-wjckx 1/1 Running 4 4m drycc-logger-fluentbit-zxnqb 1/1 Running 0 4m drycc-redis-304849759-1f35p 1/1 Running 0 4m drycc-storage-676004970-nxqgt 1/1 Running 0 4m drycc-monitor-grafana-432627134-lnl2h 1/1 Running 0 4m drycc-monitor-telegraf-wmcmn 1/1 Running 1 4m drycc-registry-756475849-lwc6b 1/1 Running 1 4m drycc-registry-proxy-96c4p 1/1 Running 0 4m drycc-rabbitmq-0 1/1 Running 0 4m Once all of the pods are in the READY state, Drycc Workflow is up and running! For more installation parameters, please check the values.yaml file of workflow. After installing Workflow, register a user and deploy an application .","title":"Install Drycc Workflow"},{"location":"installing-workflow/#configure-dns","text":"User must to set up a hostname, and assumes the drycc-builder.$host convention. We need to point the drycc-builder.$host record to the public IP address of your builder. You can get the public IP using the following command. A wildcard entry is necessary here as apps will use the same rule after they are deployed. $ kubectl get svc drycc-builder --namespace drycc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE drycc-builder 10.0.25.3 138.91.243.152 2222:31625/TCP 33m If we were using drycc.cc as a hostname, we would need to create the following A DNS records. Name Type Value drycc-builder.drycc.cc A 138.91.243.152 Once all of the pods are in the READY state, and drycc-builder.$host resolves to the external IP found above, Workflow is up and running! After installing Workflow, register a user and deploy an application . If your k8s does not provide public network loadblance, you need to install TCP proxy services such as haproxy on machines that can access both internal and external networks, and then expose 80 and 443 .","title":"Configure DNS"},{"location":"installing-workflow/configuring-object-storage/","text":"Configuring Object Storage \u00b6 A variety of Drycc Workflow components rely on an object storage system to do their work including storing application slugs, Container images and database logs. Drycc Workflow ships with Storage by default, which provides in-cluster. Configuring off-cluster Object Storage \u00b6 Every component that relies on object storage uses two inputs for configuration: You must use object storage services that are compatible with S3 API Access credentials stored as a Kubernetes secret named storage-creds The helm chart for Drycc Workflow can be easily configured to connect Workflow components to off-cluster object storage. Drycc Workflow currently supports Google Compute Storage, Amazon S3, Azure Blob Storage and OpenStack Swift Storage. Step 1: Create storage buckets \u00b6 Create storage buckets for each of the Workflow subsystems: builder , registry , and database . Depending on your chosen object storage you may need to provide globally unique bucket names. If you are using S3, use hyphens instead of periods in the bucket names. Using periods in the bucket name will cause an ssl certificate validation issue with S3 . If you provide credentials with sufficient access to the underlying storage, Workflow components will create the buckets if they do not exist. Step 2: Generate storage credentials \u00b6 If applicable, generate credentials that have create and write access to the storage buckets created in Step 1. If you are using AWS S3 and your Kubernetes nodes are configured with appropriate IAM API keys via InstanceRoles, you do not need to create API credentials. Do, however, validate that the InstanceRole has appropriate permissions to the configured buckets! Step 3: Configure Workflow Chart \u00b6 Operators should configure object storage by editing the Helm values file before running helm install . To do so: Fetch the Helm values by running helm inspect values oci://registry.drycc.cc/charts/workflow > values.yaml Update the global/storage parameter to reference the platform you are using, e.g. s3 , azure , gcs , or swift Find the corresponding section for your storage type and provide appropriate values including region, bucket names, and access credentials. Save your changes. Note All values will be automatically (base64) encoded except the key_json values under gcs / gcr . These must be base64-encoded. This is to support cleanly passing said encoded text via helm --set cli functionality rather than attempting to pass the raw JSON data. For example: $ helm install drycc oci://registry.drycc.cc/charts/workflow \\ --namespace drycc \\ --set global.platformDomain=youdomain.com --set global.storage=gcs,gcs.key_json=\"$(cat /path/to/gcs_creds.json | base64 -w 0)\" You are now ready to run helm install drycc oci://registry.drycc.cc/charts/workflow --namespace drycc -f values.yaml using your desired object storage.","title":"Configuring Object Storage"},{"location":"installing-workflow/configuring-object-storage/#configuring-object-storage","text":"A variety of Drycc Workflow components rely on an object storage system to do their work including storing application slugs, Container images and database logs. Drycc Workflow ships with Storage by default, which provides in-cluster.","title":"Configuring Object Storage"},{"location":"installing-workflow/configuring-object-storage/#configuring-off-cluster-object-storage","text":"Every component that relies on object storage uses two inputs for configuration: You must use object storage services that are compatible with S3 API Access credentials stored as a Kubernetes secret named storage-creds The helm chart for Drycc Workflow can be easily configured to connect Workflow components to off-cluster object storage. Drycc Workflow currently supports Google Compute Storage, Amazon S3, Azure Blob Storage and OpenStack Swift Storage.","title":"Configuring off-cluster Object Storage"},{"location":"installing-workflow/configuring-object-storage/#step-1-create-storage-buckets","text":"Create storage buckets for each of the Workflow subsystems: builder , registry , and database . Depending on your chosen object storage you may need to provide globally unique bucket names. If you are using S3, use hyphens instead of periods in the bucket names. Using periods in the bucket name will cause an ssl certificate validation issue with S3 . If you provide credentials with sufficient access to the underlying storage, Workflow components will create the buckets if they do not exist.","title":"Step 1: Create storage buckets"},{"location":"installing-workflow/configuring-object-storage/#step-2-generate-storage-credentials","text":"If applicable, generate credentials that have create and write access to the storage buckets created in Step 1. If you are using AWS S3 and your Kubernetes nodes are configured with appropriate IAM API keys via InstanceRoles, you do not need to create API credentials. Do, however, validate that the InstanceRole has appropriate permissions to the configured buckets!","title":"Step 2: Generate storage credentials"},{"location":"installing-workflow/configuring-object-storage/#step-3-configure-workflow-chart","text":"Operators should configure object storage by editing the Helm values file before running helm install . To do so: Fetch the Helm values by running helm inspect values oci://registry.drycc.cc/charts/workflow > values.yaml Update the global/storage parameter to reference the platform you are using, e.g. s3 , azure , gcs , or swift Find the corresponding section for your storage type and provide appropriate values including region, bucket names, and access credentials. Save your changes. Note All values will be automatically (base64) encoded except the key_json values under gcs / gcr . These must be base64-encoded. This is to support cleanly passing said encoded text via helm --set cli functionality rather than attempting to pass the raw JSON data. For example: $ helm install drycc oci://registry.drycc.cc/charts/workflow \\ --namespace drycc \\ --set global.platformDomain=youdomain.com --set global.storage=gcs,gcs.key_json=\"$(cat /path/to/gcs_creds.json | base64 -w 0)\" You are now ready to run helm install drycc oci://registry.drycc.cc/charts/workflow --namespace drycc -f values.yaml using your desired object storage.","title":"Step 3: Configure Workflow Chart"},{"location":"installing-workflow/configuring-postgres/","text":"Configuring Postgres \u00b6 Drycc Workflow's controller and passport component rely on a PostgreSQL database to store platform state. By default, Drycc Workflow ships with the database component, which provides an in-cluster PostgreSQL database backed up to in-cluster or off-cluster object storage . Currently, for object storage, which is utilized by several Workflow components, only off-cluster solutions such as S3 or GCS are recommended in production environments. Experience has shown that many operators already opting for off-cluster object storage similarly prefer to host Postgres off-cluster as well, using Amazon RDS or similar. When excercising both options, a Workflow installation becomes entirely stateless, and is thus restored or rebuilt with greater ease should the need ever arise. Provisioning off-cluster Postgres \u00b6 First, provision a PostgreSQL RDBMS using the cloud provider or other infrastructure of your choice. Take care to ensure that security groups or other firewall rules will permit connectivity from your Kubernetes worker nodes, any of which may play host to the Workflow controller component. Take note of the following: The hostname or public IP of your PostgreSQL RDBMS The port on which your PostgreSQL RDBMS runs-- typically 5432 Within the off-cluster RDBMS, manually provision the following: A database user (take note of the username and password) A database owned by that user (take note of its name) If you are able to log into the RDBMS as a superuser or a user with appropriate permissions, this process will typically look like this: $ psql -h -p -d postgres -U <\"postgres\" or your own username> > create user with password ''; > create database with owner ; > \\q Configuring Workflow \u00b6 The Helm chart for Drycc Workflow can be easily configured to connect the Workflow controller component to an off-cluster PostgreSQL database. Step 1: If you haven't already fetched the values, do so with helm inspect values drycc/workflow > values.yaml Step 2: Update database connection details by modifying values.yaml : Update the databaseLocation parameter to off-cluster . Update the values in the [database] configuration section to properly reflect all connection details. Update the values in the [controller] configuration section to properly reflect platformDomain details. Save your changes. Note: you do not need to (and must not) base64 encode any values, as the Helm chart will automatically handle encoding as necessary. You are now ready to helm install drycc oci://registry.drycc.cc/charts/workflow --namespace drycc -f values.yaml as usual .","title":"Configuring Postgres"},{"location":"installing-workflow/configuring-postgres/#configuring-postgres","text":"Drycc Workflow's controller and passport component rely on a PostgreSQL database to store platform state. By default, Drycc Workflow ships with the database component, which provides an in-cluster PostgreSQL database backed up to in-cluster or off-cluster object storage . Currently, for object storage, which is utilized by several Workflow components, only off-cluster solutions such as S3 or GCS are recommended in production environments. Experience has shown that many operators already opting for off-cluster object storage similarly prefer to host Postgres off-cluster as well, using Amazon RDS or similar. When excercising both options, a Workflow installation becomes entirely stateless, and is thus restored or rebuilt with greater ease should the need ever arise.","title":"Configuring Postgres"},{"location":"installing-workflow/configuring-postgres/#provisioning-off-cluster-postgres","text":"First, provision a PostgreSQL RDBMS using the cloud provider or other infrastructure of your choice. Take care to ensure that security groups or other firewall rules will permit connectivity from your Kubernetes worker nodes, any of which may play host to the Workflow controller component. Take note of the following: The hostname or public IP of your PostgreSQL RDBMS The port on which your PostgreSQL RDBMS runs-- typically 5432 Within the off-cluster RDBMS, manually provision the following: A database user (take note of the username and password) A database owned by that user (take note of its name) If you are able to log into the RDBMS as a superuser or a user with appropriate permissions, this process will typically look like this: $ psql -h -p -d postgres -U <\"postgres\" or your own username> > create user with password ''; > create database with owner ; > \\q","title":"Provisioning off-cluster Postgres"},{"location":"installing-workflow/configuring-postgres/#configuring-workflow","text":"The Helm chart for Drycc Workflow can be easily configured to connect the Workflow controller component to an off-cluster PostgreSQL database. Step 1: If you haven't already fetched the values, do so with helm inspect values drycc/workflow > values.yaml Step 2: Update database connection details by modifying values.yaml : Update the databaseLocation parameter to off-cluster . Update the values in the [database] configuration section to properly reflect all connection details. Update the values in the [controller] configuration section to properly reflect platformDomain details. Save your changes. Note: you do not need to (and must not) base64 encode any values, as the Helm chart will automatically handle encoding as necessary. You are now ready to helm install drycc oci://registry.drycc.cc/charts/workflow --namespace drycc -f values.yaml as usual .","title":"Configuring Workflow"},{"location":"installing-workflow/configuring-registry/","text":"Configuring Registry \u00b6 Drycc Workflow's builder component relies on a registry for storing application container images. Drycc Workflow ships with a registry component by default, which provides an in-cluster Container registry backed by the platform-configured object storage . Operators might want to use an off-cluster registry for performance or security reasons. Configuring Off-Cluster Private Registry \u00b6 Every component that relies on a registry uses two inputs for configuration: Registry Location environment variable named DRYCC_REGISTRY_LOCATION Access credentials stored as a Kubernetes secret named registry-secret The Helm chart for Drycc Workflow can be easily configured to connect Workflow components to off-cluster registry. Drycc Workflow supports external registries which provide either short-lived tokens that are valid only for a specified amount of time or long-lived tokens (basic username/password) which are valid forever for authenticating to them. For those registries which provide short lived tokens for authentication, Drycc Workflow will generate and refresh them such that the deployed apps will only have access to the short-lived tokens and not to the actual credentials for the registries. When using a private registry the container images are no longer pulled by Drycc Workflow Controller but rather are managed by Kubernetes . This will increase security and overall speed, however the port information can no longer be discovered. Instead the port information can be set via drycc config:set PORT= prior to deploying the application. Drycc Workflow currently supports: off-cluster: Any provider which supports long-lived username/password authentication, such as Azure Container Registry , Docker Hub , quay.io , or a self-hosted Container registry. Configuration \u00b6 If you haven't already fetched the values file, do so with helm inspect values drycc/workflow > values.yaml Update registry location details by modifying the values file: Update the registryLocation parameter to reference the registry location you are using: off-cluster , ecr , gcr Update the values in the section which corresponds to your registry location type. You are now ready to helm install drycc oci://registry.drycc.cc/charts/workflow --namespace drycc -f values.yaml using your desired registry. Examples \u00b6 Here we show how the relevant parts of the fetched values.yaml file might look like after configuring for a particular off-cluster registry: Azure Container Registry (ACR) \u00b6 After following the docs and creating a registry, e.g. myregistry , with its corresponding login server of myregistry.azurecr.io , the following values should be supplied: global: ... registryLocation: \"off-cluster\" ... registry-token-refresher: ... registry: hostname: \"myregistry.azurecr.io\" organization: \"myorg\" username: \"myusername\" password: \"mypassword\" ... Note: The mandatory organization field (here myorg ) will be created as an ACR repository if it does not already exist. Quay.io \u00b6 global: ... registryLocation: \"off-cluster\" ... registry-token-refresher: ... registry: hostname: \"quay.io\" organization: \"myorg\" username: \"myusername\" password: \"mypassword\" ...","title":"Configuring the Registry"},{"location":"installing-workflow/configuring-registry/#configuring-registry","text":"Drycc Workflow's builder component relies on a registry for storing application container images. Drycc Workflow ships with a registry component by default, which provides an in-cluster Container registry backed by the platform-configured object storage . Operators might want to use an off-cluster registry for performance or security reasons.","title":"Configuring Registry"},{"location":"installing-workflow/configuring-registry/#configuring-off-cluster-private-registry","text":"Every component that relies on a registry uses two inputs for configuration: Registry Location environment variable named DRYCC_REGISTRY_LOCATION Access credentials stored as a Kubernetes secret named registry-secret The Helm chart for Drycc Workflow can be easily configured to connect Workflow components to off-cluster registry. Drycc Workflow supports external registries which provide either short-lived tokens that are valid only for a specified amount of time or long-lived tokens (basic username/password) which are valid forever for authenticating to them. For those registries which provide short lived tokens for authentication, Drycc Workflow will generate and refresh them such that the deployed apps will only have access to the short-lived tokens and not to the actual credentials for the registries. When using a private registry the container images are no longer pulled by Drycc Workflow Controller but rather are managed by Kubernetes . This will increase security and overall speed, however the port information can no longer be discovered. Instead the port information can be set via drycc config:set PORT= prior to deploying the application. Drycc Workflow currently supports: off-cluster: Any provider which supports long-lived username/password authentication, such as Azure Container Registry , Docker Hub , quay.io , or a self-hosted Container registry.","title":"Configuring Off-Cluster Private Registry"},{"location":"installing-workflow/configuring-registry/#configuration","text":"If you haven't already fetched the values file, do so with helm inspect values drycc/workflow > values.yaml Update registry location details by modifying the values file: Update the registryLocation parameter to reference the registry location you are using: off-cluster , ecr , gcr Update the values in the section which corresponds to your registry location type. You are now ready to helm install drycc oci://registry.drycc.cc/charts/workflow --namespace drycc -f values.yaml using your desired registry.","title":"Configuration"},{"location":"installing-workflow/configuring-registry/#examples","text":"Here we show how the relevant parts of the fetched values.yaml file might look like after configuring for a particular off-cluster registry:","title":"Examples"},{"location":"installing-workflow/configuring-registry/#azure-container-registry-acr","text":"After following the docs and creating a registry, e.g. myregistry , with its corresponding login server of myregistry.azurecr.io , the following values should be supplied: global: ... registryLocation: \"off-cluster\" ... registry-token-refresher: ... registry: hostname: \"myregistry.azurecr.io\" organization: \"myorg\" username: \"myusername\" password: \"mypassword\" ... Note: The mandatory organization field (here myorg ) will be created as an ACR repository if it does not already exist.","title":"Azure Container Registry (ACR)"},{"location":"installing-workflow/configuring-registry/#quayio","text":"global: ... registryLocation: \"off-cluster\" ... registry-token-refresher: ... registry: hostname: \"quay.io\" organization: \"myorg\" username: \"myusername\" password: \"mypassword\" ...","title":"Quay.io"},{"location":"installing-workflow/gateway/","text":"Specify Gateway \u00b6 Install Drycc Workflow (Specify gateway) \u00b6 Now that Helm is installed and the repository has been added, install Workflow with a native gateway by running: $ helm install drycc oci://registry.drycc.cc/charts/workflow \\ --namespace drycc \\ --set global.gatewayClass=istio \\ --set global.platformDomain=drycc.cc \\ --set builder.service.type=LoadBalancer Of course, if you deploy it on a bare machine, you probably do not have Load Balancer. You need to use NodePort: $ helm install drycc oci://registry.drycc.cc/charts/workflow \\ --namespace drycc \\ --set global.gatewayClass=istio \\ --set global.platformDomain=drycc.cc \\ --set builder.service.type=NodePort \\ --set builder.service.nodePort=32222 If you want to use Load Balancer on a bare machine, you can look at metallb Where global.platformDomain is a required parameter that is traditionally not required for Workflow that is explained in the next section. In this example we are using drycc.cc for $hostname . Helm will install a variety of Kubernetes resources in the drycc namespace. Wait for the pods that Helm launched to be ready. Monitor their status by running: $ kubectl --namespace=drycc get pods You should also notice that several Kubernetes gatewayclass has been installed on your cluster. You can view it by running: $ kubectl get gatewayclass --namespace drycc Depending on the order in which the Workflow components initialize, some pods may restart. This is common during the installation: if a component's dependencies are not yet available, that component will exit and Kubernetes will automatically restart it. Here, it can be seen that the controller, builder and registry all took a few loops waiting for storage before they were able to start: $ kubectl --namespace=drycc get pods NAME READY STATUS RESTARTS AGE drycc-builder-hy3xv 1/1 Running 5 5m drycc-controller-g3cu8 1/1 Running 5 5m drycc-controller-celery-cmxxn 3/3 Running 0 5m drycc-database-rad1o 1/1 Running 0 5m drycc-logger-fluentbit-1v8uk 1/1 Running 0 5m drycc-logger-fluentbit-esm60 1/1 Running 0 5m drycc-logger-sm8b3 1/1 Running 0 5m drycc-storage-4ww3t 1/1 Running 0 5m drycc-registry-asozo 1/1 Running 1 5m drycc-rabbitmq-0 1/1 Running 0 5m Install a Kubernetes Gateway \u00b6 Now that Workflow has been deployed with the global.gatewayClass , we will need a Kubernetes gateway in place to begin routing traffic. Here is an example of how to use istio as an gateway for Workflow. Of course, you are welcome to use any controller you wish. $ helm repo add istio https://istio-release.storage.googleapis.com/charts $ helm repo update $ kubectl create namespace istio-system $ helm install istio-base istio/base -n istio-system $ helm install istiod istio/istiod -n istio-system --wait $ kubectl create namespace istio-ingress $ helm install istio-ingress istio/gateway -n istio-ingress --wait Configure DNS \u00b6 User must install drycc and then set up a hostname, and assumes the *.$host convention. We need to point the *.$host record to the public IP address of your gateway. You can get the public IP using the following command. A wildcard entry is necessary here as apps will use the same rule after they are deployed. $ kubectl get gateway --namespace drycc NAME CLASS ADDRESS PROGRAMMED AGE gateway istio 138.91.243.152 True 36d If we were using drycc.cc as a hostname, we would need to create the following A DNS records. Name Type Value *.drycc.cc A 138.91.243.152 Once all of the pods are in the READY state, and *.$host resolves to the external IP found above, the preparation of gateway has been completed! After installing Workflow, register a user and deploy an application . If your k8s does not provide public network loadblance, you need to install TCP proxy services such as haproxy on machines that can access both internal and external networks, and then expose 80 and 443 .","title":"Installing Gateway"},{"location":"installing-workflow/gateway/#specify-gateway","text":"","title":"Specify Gateway"},{"location":"installing-workflow/gateway/#install-drycc-workflow-specify-gateway","text":"Now that Helm is installed and the repository has been added, install Workflow with a native gateway by running: $ helm install drycc oci://registry.drycc.cc/charts/workflow \\ --namespace drycc \\ --set global.gatewayClass=istio \\ --set global.platformDomain=drycc.cc \\ --set builder.service.type=LoadBalancer Of course, if you deploy it on a bare machine, you probably do not have Load Balancer. You need to use NodePort: $ helm install drycc oci://registry.drycc.cc/charts/workflow \\ --namespace drycc \\ --set global.gatewayClass=istio \\ --set global.platformDomain=drycc.cc \\ --set builder.service.type=NodePort \\ --set builder.service.nodePort=32222 If you want to use Load Balancer on a bare machine, you can look at metallb Where global.platformDomain is a required parameter that is traditionally not required for Workflow that is explained in the next section. In this example we are using drycc.cc for $hostname . Helm will install a variety of Kubernetes resources in the drycc namespace. Wait for the pods that Helm launched to be ready. Monitor their status by running: $ kubectl --namespace=drycc get pods You should also notice that several Kubernetes gatewayclass has been installed on your cluster. You can view it by running: $ kubectl get gatewayclass --namespace drycc Depending on the order in which the Workflow components initialize, some pods may restart. This is common during the installation: if a component's dependencies are not yet available, that component will exit and Kubernetes will automatically restart it. Here, it can be seen that the controller, builder and registry all took a few loops waiting for storage before they were able to start: $ kubectl --namespace=drycc get pods NAME READY STATUS RESTARTS AGE drycc-builder-hy3xv 1/1 Running 5 5m drycc-controller-g3cu8 1/1 Running 5 5m drycc-controller-celery-cmxxn 3/3 Running 0 5m drycc-database-rad1o 1/1 Running 0 5m drycc-logger-fluentbit-1v8uk 1/1 Running 0 5m drycc-logger-fluentbit-esm60 1/1 Running 0 5m drycc-logger-sm8b3 1/1 Running 0 5m drycc-storage-4ww3t 1/1 Running 0 5m drycc-registry-asozo 1/1 Running 1 5m drycc-rabbitmq-0 1/1 Running 0 5m","title":"Install Drycc Workflow (Specify gateway)"},{"location":"installing-workflow/gateway/#install-a-kubernetes-gateway","text":"Now that Workflow has been deployed with the global.gatewayClass , we will need a Kubernetes gateway in place to begin routing traffic. Here is an example of how to use istio as an gateway for Workflow. Of course, you are welcome to use any controller you wish. $ helm repo add istio https://istio-release.storage.googleapis.com/charts $ helm repo update $ kubectl create namespace istio-system $ helm install istio-base istio/base -n istio-system $ helm install istiod istio/istiod -n istio-system --wait $ kubectl create namespace istio-ingress $ helm install istio-ingress istio/gateway -n istio-ingress --wait","title":"Install a Kubernetes Gateway"},{"location":"installing-workflow/gateway/#configure-dns","text":"User must install drycc and then set up a hostname, and assumes the *.$host convention. We need to point the *.$host record to the public IP address of your gateway. You can get the public IP using the following command. A wildcard entry is necessary here as apps will use the same rule after they are deployed. $ kubectl get gateway --namespace drycc NAME CLASS ADDRESS PROGRAMMED AGE gateway istio 138.91.243.152 True 36d If we were using drycc.cc as a hostname, we would need to create the following A DNS records. Name Type Value *.drycc.cc A 138.91.243.152 Once all of the pods are in the READY state, and *.$host resolves to the external IP found above, the preparation of gateway has been completed! After installing Workflow, register a user and deploy an application . If your k8s does not provide public network loadblance, you need to install TCP proxy services such as haproxy on machines that can access both internal and external networks, and then expose 80 and 443 .","title":"Configure DNS"},{"location":"installing-workflow/system-requirements/","text":"Requirements \u00b6 To run Drycc Workflow on a Kubernetes cluster, there are a few requirements to keep in mind. Kubernetes Versions \u00b6 Drycc Workflow requires Kubernetes v1.16.15 or later. Components Requirements \u00b6 Drycc uses gateway as a routing implementation, so you have to choose an gateway. We recommend using istio or kong . Workflow supports the use of ACME to manage automatic certificates, cert-manager is also one of the necessary components, if you use cert-manager EAB, you need to set the clusterResourceNamespace to the namespace of drycc. Workflow supports stateful apps. You can create and use them through the 'drycc volumes' command. If you want to use this feature, you must have a StorageClass that supports ReadWriteMany . Workflow also supports the OSB API through the 'drycc resources' command. If you want to use this function, you need to install service-catalog . Storage Requirements \u00b6 A variety of Drycc Workflow components rely on an object storage system to do their work, including storing application slugs, Container images and database logs. Drycc Workflow ships with drycc storage by default, which provides in-cluster. Workflow supports Amazon Simple Storage Service (S3), Google Cloud Storage (GCS), OpenShift Swift, and Azure Blob Storage. See configuring object storage for setup instructions. Resource Requirements \u00b6 When deploying Drycc Workflow, it's important to provision machines with adequate resources. Drycc is a highly-available distributed system, which means that Drycc components and your deployed applications will move around the cluster onto healthy hosts as hosts leave the cluster for various reasons (failures, reboots, autoscalers, etc.). Because of this, you should have ample spare resources on any machine in your cluster to withstand the additional load of running services for failed machines. Drycc Workflow components use about 2.5GB of memory across the cluster, and require approximately 30GB of hard disk space. Because it may need to handle additional load if another one fails, each machine has minimum requirements of: At least 4GB of RAM (more is better) At least 40GB of hard disk space Note that these estimates are for Drycc Workflow and Kubernetes only. Be sure to leave enough spare capacity for your application footprint as well. Running smaller machines will likely result in increased system load and has been known to result in component failures and instability.","title":"System Requirements"},{"location":"installing-workflow/system-requirements/#requirements","text":"To run Drycc Workflow on a Kubernetes cluster, there are a few requirements to keep in mind.","title":"Requirements"},{"location":"installing-workflow/system-requirements/#kubernetes-versions","text":"Drycc Workflow requires Kubernetes v1.16.15 or later.","title":"Kubernetes Versions"},{"location":"installing-workflow/system-requirements/#components-requirements","text":"Drycc uses gateway as a routing implementation, so you have to choose an gateway. We recommend using istio or kong . Workflow supports the use of ACME to manage automatic certificates, cert-manager is also one of the necessary components, if you use cert-manager EAB, you need to set the clusterResourceNamespace to the namespace of drycc. Workflow supports stateful apps. You can create and use them through the 'drycc volumes' command. If you want to use this feature, you must have a StorageClass that supports ReadWriteMany . Workflow also supports the OSB API through the 'drycc resources' command. If you want to use this function, you need to install service-catalog .","title":"Components Requirements"},{"location":"installing-workflow/system-requirements/#storage-requirements","text":"A variety of Drycc Workflow components rely on an object storage system to do their work, including storing application slugs, Container images and database logs. Drycc Workflow ships with drycc storage by default, which provides in-cluster. Workflow supports Amazon Simple Storage Service (S3), Google Cloud Storage (GCS), OpenShift Swift, and Azure Blob Storage. See configuring object storage for setup instructions.","title":"Storage Requirements"},{"location":"installing-workflow/system-requirements/#resource-requirements","text":"When deploying Drycc Workflow, it's important to provision machines with adequate resources. Drycc is a highly-available distributed system, which means that Drycc components and your deployed applications will move around the cluster onto healthy hosts as hosts leave the cluster for various reasons (failures, reboots, autoscalers, etc.). Because of this, you should have ample spare resources on any machine in your cluster to withstand the additional load of running services for failed machines. Drycc Workflow components use about 2.5GB of memory across the cluster, and require approximately 30GB of hard disk space. Because it may need to handle additional load if another one fails, each machine has minimum requirements of: At least 4GB of RAM (more is better) At least 40GB of hard disk space Note that these estimates are for Drycc Workflow and Kubernetes only. Be sure to leave enough spare capacity for your application footprint as well. Running smaller machines will likely result in increased system load and has been known to result in component failures and instability.","title":"Resource Requirements"},{"location":"managing-workflow/configuring-dns/","text":"Configure DNS \u00b6 The Drycc Workflow controller and all applications deployed via Workflow are intended (by default) to be accessible as subdomains of the Workflow cluster's domain. For example, assuming example.com were a cluster's domain: The controller should be accessible at drycc.example.com Applications should be accessible (by default) at .example.com Given that this is the case, the primary objective in configuring DNS is that traffic for all subdomains of a cluster's domain be directed to the cluster node(s) hosting the platform's router component, which is capable of directing traffic within the cluster to the correct endpoints. With a Load Balancer \u00b6 Generally, it is recommended that a [load balancer][] be used to direct inbound traffic to one or more routers. In such a case, configuring DNS is as simple as defining a wildcard record in DNS that points to the load balancer. For example, assuming a domain of example.com : An A record enumerating each of your load balancer(s) IPs (i.e. DNS round-robining) A CNAME record referencing an existing fully-qualified domain name for the load balancer Per AWS' own documentation , this is the recommended strategy when using AWS Elastic Load Balancers, as ELB IPs may change over time. DNS for any applications using a \"custom domain\" (a fully-qualified domain name that is not a subdomain of the cluster's own domain) can be configured by creating a CNAME record that references the wildcard record described above. Although it is dependent upon your distribution of Kubernetes and your underlying infrastructure, in many cases, the IP(s) or existing fully-qualified domain name of a load balancer can be determined directly using the kubectl tool: $ kubectl --namespace=istio-nginx describe service | grep \"LoadBalancer\" LoadBalancer Ingress: a493e4e58ea0511e5bb390686bc85da3-1558404688.us-west-2.elb.amazonaws.com The LoadBalancer Ingress field typically describes an existing domain name or public IP(s). Note that if Kubernetes is able to automatically provision a load balancer for you, it does so asynchronously. If the command shown above is issued very soon after Workflow installation, the load balancer may not exist yet. Without a Load Balancer \u00b6 On some platforms (Minikube, for instance), a load balancer is not an easy or practical thing to provision. In these cases, one can directly identify the public IP of a Kubernetes node that is hosting a router pod and use that information to configure the local /etc/hosts file. Because wildcard entries do not work in a local /etc/hosts file, using this strategy may result in frequent editing of that file to add fully-qualified subdomains of a cluster for each application added to that cluster. Because of this a more viable option may be to utilize the xip.io service. In general, for any IP, a.b.c.d , the fully-qualified domain name any-subdomain.a.b.c.d.xip.io will resolve to the IP a.b.c.d . This can be enormously useful. To begin, find the node(s) hosting router instances using kubectl : $ kubectl --namespace=istio-ingress describe pod | grep Node: Node: ip-10-0-0-199.us-west-2.compute.internal/10.0.0.199 Node: ip-10-0-0-198.us-west-2.compute.internal/10.0.0.198 The command will display information for every router pod. For each, a node name and IP are displayed in the Node field. If the IPs appearing in these fields are public, any of these may be used to configure your local /etc/hosts file or may be used with xip.io . If the IPs shown are not public, further investigation may be needed. You can list the IP addresses of a node using kubectl : $ kubectl describe node ip-10-0-0-199.us-west-2.compute.internal # ... Addresses: 10.0.0.199,10.0.0.199,54.218.85.175 # ... Here, the Addresses field lists all the node's IPs. If any of them are public, again, they may be used to configure your local /etc/hosts file or may be used with xip.io . Tutorial: Configuring DNS with Google Cloud DNS \u00b6 In this section, we'll describe how to configure Google Cloud DNS for routing your domain name to your Drycc cluster. We'll assume the following in this section: Your Ingress service has a load balancer in front of it. The load balancer need not be cloud based, it just needs to provide a stable IP address or a stable domain name You have the mystuff.com domain name registered with a registrar Replace your domain name with mystuff.com in the instructions to follow Your registrar lets you alter the nameservers for your domain name (most registrars do) Here are the steps for configuring cloud DNS to route to your drycc cluster: Get the load balancer IP or domain name If you are on Google Container Engine, you can run kubectl get svc -n istio-ingress and look for the LoadBalancer Ingress column to get the IP address Create a new Cloud DNS Zone (on the console: Networking => Cloud DNS , then click on Create Zone ) Name your zone, and set the DNS name to mystuff.com. (note the . at the end Click on the Create button Click on the Add Record Set button on the resulting page If your load balancer provides a stable IP address, enter the following fields in the resulting form: DNS Name : * Resource Record Type : A TTL : the DNS TTL of your choosing. If you're testing or you anticipate that you'll tear down and rebuild many drycc clusters over time, we recommend a low TTL IPv4 Address : The IP that you got in the very first step Click the Create button If your load balancer provides the stable domain name lbdomain.com , enter the following fields in the resulting form: DNS Name : * Resource Record Type : CNAME TTL : the DNS TTL of your choosing. If you're testing or you anticipate that you'll tear down and rebuild many drycc clusters over time, we recommend a low TTL Canonical name : lbdomain.com. (note the . a the end) Click on the Create button In your domain registrar, set the nameservers for your mystuff.com domain to the ones under the data column in the NS record on the same page. They'll often be something like the below (note the trailing . characters). ns-cloud-b1.googledomains.com. ns-cloud-b2.googledomains.com. ns-cloud-b3.googledomains.com. ns-cloud-b4.googledomains.com. Note: If you ever have to re-create your drycc cluster, simply go back to step 6.4 or 7.4 (depending on your load balancer) and change the IP address or domain name to the new value. You may have to wait for the TTL you set to expire. Testing \u00b6 To test that traffic reaches its intended destination, a request can be sent to the Drycc controller like so (do not forget the trailing slash!): curl http://drycc.example.com/v2/ Or: curl http://drycc.54.218.85.175.xip.io/v2/ Since such requests require authentication, a response such as the following should be considered an indicator of success: {\"detail\":\"Authentication credentials were not provided.\"}","title":"Configuring DNS"},{"location":"managing-workflow/configuring-dns/#configure-dns","text":"The Drycc Workflow controller and all applications deployed via Workflow are intended (by default) to be accessible as subdomains of the Workflow cluster's domain. For example, assuming example.com were a cluster's domain: The controller should be accessible at drycc.example.com Applications should be accessible (by default) at .example.com Given that this is the case, the primary objective in configuring DNS is that traffic for all subdomains of a cluster's domain be directed to the cluster node(s) hosting the platform's router component, which is capable of directing traffic within the cluster to the correct endpoints.","title":"Configure DNS"},{"location":"managing-workflow/configuring-dns/#with-a-load-balancer","text":"Generally, it is recommended that a [load balancer][] be used to direct inbound traffic to one or more routers. In such a case, configuring DNS is as simple as defining a wildcard record in DNS that points to the load balancer. For example, assuming a domain of example.com : An A record enumerating each of your load balancer(s) IPs (i.e. DNS round-robining) A CNAME record referencing an existing fully-qualified domain name for the load balancer Per AWS' own documentation , this is the recommended strategy when using AWS Elastic Load Balancers, as ELB IPs may change over time. DNS for any applications using a \"custom domain\" (a fully-qualified domain name that is not a subdomain of the cluster's own domain) can be configured by creating a CNAME record that references the wildcard record described above. Although it is dependent upon your distribution of Kubernetes and your underlying infrastructure, in many cases, the IP(s) or existing fully-qualified domain name of a load balancer can be determined directly using the kubectl tool: $ kubectl --namespace=istio-nginx describe service | grep \"LoadBalancer\" LoadBalancer Ingress: a493e4e58ea0511e5bb390686bc85da3-1558404688.us-west-2.elb.amazonaws.com The LoadBalancer Ingress field typically describes an existing domain name or public IP(s). Note that if Kubernetes is able to automatically provision a load balancer for you, it does so asynchronously. If the command shown above is issued very soon after Workflow installation, the load balancer may not exist yet.","title":"With a Load Balancer"},{"location":"managing-workflow/configuring-dns/#without-a-load-balancer","text":"On some platforms (Minikube, for instance), a load balancer is not an easy or practical thing to provision. In these cases, one can directly identify the public IP of a Kubernetes node that is hosting a router pod and use that information to configure the local /etc/hosts file. Because wildcard entries do not work in a local /etc/hosts file, using this strategy may result in frequent editing of that file to add fully-qualified subdomains of a cluster for each application added to that cluster. Because of this a more viable option may be to utilize the xip.io service. In general, for any IP, a.b.c.d , the fully-qualified domain name any-subdomain.a.b.c.d.xip.io will resolve to the IP a.b.c.d . This can be enormously useful. To begin, find the node(s) hosting router instances using kubectl : $ kubectl --namespace=istio-ingress describe pod | grep Node: Node: ip-10-0-0-199.us-west-2.compute.internal/10.0.0.199 Node: ip-10-0-0-198.us-west-2.compute.internal/10.0.0.198 The command will display information for every router pod. For each, a node name and IP are displayed in the Node field. If the IPs appearing in these fields are public, any of these may be used to configure your local /etc/hosts file or may be used with xip.io . If the IPs shown are not public, further investigation may be needed. You can list the IP addresses of a node using kubectl : $ kubectl describe node ip-10-0-0-199.us-west-2.compute.internal # ... Addresses: 10.0.0.199,10.0.0.199,54.218.85.175 # ... Here, the Addresses field lists all the node's IPs. If any of them are public, again, they may be used to configure your local /etc/hosts file or may be used with xip.io .","title":"Without a Load Balancer"},{"location":"managing-workflow/configuring-dns/#tutorial-configuring-dns-with-google-cloud-dns","text":"In this section, we'll describe how to configure Google Cloud DNS for routing your domain name to your Drycc cluster. We'll assume the following in this section: Your Ingress service has a load balancer in front of it. The load balancer need not be cloud based, it just needs to provide a stable IP address or a stable domain name You have the mystuff.com domain name registered with a registrar Replace your domain name with mystuff.com in the instructions to follow Your registrar lets you alter the nameservers for your domain name (most registrars do) Here are the steps for configuring cloud DNS to route to your drycc cluster: Get the load balancer IP or domain name If you are on Google Container Engine, you can run kubectl get svc -n istio-ingress and look for the LoadBalancer Ingress column to get the IP address Create a new Cloud DNS Zone (on the console: Networking => Cloud DNS , then click on Create Zone ) Name your zone, and set the DNS name to mystuff.com. (note the . at the end Click on the Create button Click on the Add Record Set button on the resulting page If your load balancer provides a stable IP address, enter the following fields in the resulting form: DNS Name : * Resource Record Type : A TTL : the DNS TTL of your choosing. If you're testing or you anticipate that you'll tear down and rebuild many drycc clusters over time, we recommend a low TTL IPv4 Address : The IP that you got in the very first step Click the Create button If your load balancer provides the stable domain name lbdomain.com , enter the following fields in the resulting form: DNS Name : * Resource Record Type : CNAME TTL : the DNS TTL of your choosing. If you're testing or you anticipate that you'll tear down and rebuild many drycc clusters over time, we recommend a low TTL Canonical name : lbdomain.com. (note the . a the end) Click on the Create button In your domain registrar, set the nameservers for your mystuff.com domain to the ones under the data column in the NS record on the same page. They'll often be something like the below (note the trailing . characters). ns-cloud-b1.googledomains.com. ns-cloud-b2.googledomains.com. ns-cloud-b3.googledomains.com. ns-cloud-b4.googledomains.com. Note: If you ever have to re-create your drycc cluster, simply go back to step 6.4 or 7.4 (depending on your load balancer) and change the IP address or domain name to the new value. You may have to wait for the TTL you set to expire.","title":"Tutorial: Configuring DNS with Google Cloud DNS"},{"location":"managing-workflow/configuring-dns/#testing","text":"To test that traffic reaches its intended destination, a request can be sent to the Drycc controller like so (do not forget the trailing slash!): curl http://drycc.example.com/v2/ Or: curl http://drycc.54.218.85.175.xip.io/v2/ Since such requests require authentication, a response such as the following should be considered an indicator of success: {\"detail\":\"Authentication credentials were not provided.\"}","title":"Testing"},{"location":"managing-workflow/deploy-hooks/","text":"Deploy Hooks \u00b6 Deploy hooks allow an external service to receive a notification whenever a new version of your app is pushed to Workflow. It\u2019s useful to help keep the development team informed about deploys, while it can also be used to integrate different systems together. After one or more hooks are setup, hook output and errors appear in your application\u2019s logs: $ drycc logs ... 2011-03-15T15:07:29-07:00 drycc[api]: Deploy hook sent to http://drycc.rocks Deploy hooks are a generic HTTP hook. An administrator can create and configure multiple deploy hooks by tuning the controller settings via the Helm chart. HTTP POST Hook \u00b6 The HTTP deploy hook performs an HTTP POST to a URL. The parameters included in the request are the same as the variables available in the hook message: app , release , release_summary , sha and user . See below for their descriptions: app=secure-woodland&release=v4&release_summary=gabrtv%20deployed%35b3726&sha=35b3726&user=gabrtv Optionally, if a deploy hook secret key is added to the controller through tuning the controller settings , a new Authorization header will be present in the POST request. The value of this header is computed as the HMAC hex digest of the request URL, using the secret as the key. In order to authenticate that this request came from Workflow, use the secret key, the full URL and the HMAC-SHA1 hashing algorithm to compute the signature. In Python, that would look something like this: import hashlib import hmac hmac.new(\"my_secret_key\", \"http://drycc.rocks?app=secure-woodland&release=v4&release_summary=gabrtv%20deployed%35b3726&sha=35b3726&user=gabrtv\", digestmod=hashlib.sha1).hexdigest() If the value of the computed HMAC hex digest and the value in the Authorization header are identical, then the request came from Workflow. Important When computing the signature, ensure that the URL parameters are in alphabetic order. This is critical when computing the cryptographic signature as most web applications don't care about the order of the HTTP parameters, but the cryptographic signature will not be the same.","title":"Deploy Hooks"},{"location":"managing-workflow/deploy-hooks/#deploy-hooks","text":"Deploy hooks allow an external service to receive a notification whenever a new version of your app is pushed to Workflow. It\u2019s useful to help keep the development team informed about deploys, while it can also be used to integrate different systems together. After one or more hooks are setup, hook output and errors appear in your application\u2019s logs: $ drycc logs ... 2011-03-15T15:07:29-07:00 drycc[api]: Deploy hook sent to http://drycc.rocks Deploy hooks are a generic HTTP hook. An administrator can create and configure multiple deploy hooks by tuning the controller settings via the Helm chart.","title":"Deploy Hooks"},{"location":"managing-workflow/deploy-hooks/#http-post-hook","text":"The HTTP deploy hook performs an HTTP POST to a URL. The parameters included in the request are the same as the variables available in the hook message: app , release , release_summary , sha and user . See below for their descriptions: app=secure-woodland&release=v4&release_summary=gabrtv%20deployed%35b3726&sha=35b3726&user=gabrtv Optionally, if a deploy hook secret key is added to the controller through tuning the controller settings , a new Authorization header will be present in the POST request. The value of this header is computed as the HMAC hex digest of the request URL, using the secret as the key. In order to authenticate that this request came from Workflow, use the secret key, the full URL and the HMAC-SHA1 hashing algorithm to compute the signature. In Python, that would look something like this: import hashlib import hmac hmac.new(\"my_secret_key\", \"http://drycc.rocks?app=secure-woodland&release=v4&release_summary=gabrtv%20deployed%35b3726&sha=35b3726&user=gabrtv\", digestmod=hashlib.sha1).hexdigest() If the value of the computed HMAC hex digest and the value in the Authorization header are identical, then the request came from Workflow. Important When computing the signature, ensure that the URL parameters are in alphabetic order. This is critical when computing the cryptographic signature as most web applications don't care about the order of the HTTP parameters, but the cryptographic signature will not be the same.","title":"HTTP POST Hook"},{"location":"managing-workflow/platform-logging/","text":"Platform Logging \u00b6 The logging platform is made up of 2 components - Fluentbit and Logger . Fluentbit runs on every worker node of the cluster and is deployed as a Daemon Set . The Fluentbit pods capture all of the stderr and stdout streams of every container running on the host (even those not hosted directly by kubernetes). Once the log message arrives in our custom fluentbit plugin we determine where the message originated. If the message was from the Workflow Controller or from an application deployed via workflow we send it to the logs topic on the local Redis Stream instance. Logger then acts as a consumer reading messages off of the Redis Stream logs topic storing those messages in a local Redis instance. When a user wants to retrieve log entries using the drycc logs command we make an HTTP request from Controller to Logger which then fetches the appropriate data from Redis. Configuring Off Cluster Redis \u00b6 Even though we provide a redis instance with the default Workflow install, it is recommended that operators use a third-party source like Elasticache or similar offering. This way your data is durable across upgrades or outages. If you have a third-party Redis installation you would like to use all you need to do is set the following values in your helm chart: db = \"0\" host = \"my.host.redis\" port = \"6379\" password = \"\" These can be changed by running helm inspect values drycc/workflow > values.yaml before using helm install to complete the installation. To customize the redis credentials, edit values.yaml and modify the redis section of the file to tune these settings. Debugging Logger \u00b6 If the drycc logs command encounters an error it will return the following message: Error: There are currently no log messages. Please check the following things: 1) Logger and fluentbit pods are running. 2) The application is writing logs to the logger component by checking that an entry in the ring buffer was created: kubectl --namespace=drycc logs 3) Making sure that the container logs were mounted properly into the fluentbit pod: kubectl --namespace=drycc exec ls /var/log/containers Architecture Diagram \u00b6 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 Router \u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2510 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 Logger \u2502\u25c0\u2500\u2500\u2500\u25b6\u2502Redis\u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2518 Log file \u25b2 \u2502 \u2502 \u25bc \u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 logs/metrics \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502App Logs\u2502\u2500\u2500Log File\u2500\u2500\u25b6\u2502Fluentbit\u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500topics\u2500\u2500\u2500\u2500\u2500\u25b6\u2502 Redis Stream \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 Default Configuration \u00b6 Fluent Bit is based in a pluggable architecture where different plugins plays a major role in the data pipeline, more than 70 built-in plugins available. Please refer to charts values.yaml for specific configurations.","title":"Platform Logging"},{"location":"managing-workflow/platform-logging/#platform-logging","text":"The logging platform is made up of 2 components - Fluentbit and Logger . Fluentbit runs on every worker node of the cluster and is deployed as a Daemon Set . The Fluentbit pods capture all of the stderr and stdout streams of every container running on the host (even those not hosted directly by kubernetes). Once the log message arrives in our custom fluentbit plugin we determine where the message originated. If the message was from the Workflow Controller or from an application deployed via workflow we send it to the logs topic on the local Redis Stream instance. Logger then acts as a consumer reading messages off of the Redis Stream logs topic storing those messages in a local Redis instance. When a user wants to retrieve log entries using the drycc logs command we make an HTTP request from Controller to Logger which then fetches the appropriate data from Redis.","title":"Platform Logging"},{"location":"managing-workflow/platform-logging/#configuring-off-cluster-redis","text":"Even though we provide a redis instance with the default Workflow install, it is recommended that operators use a third-party source like Elasticache or similar offering. This way your data is durable across upgrades or outages. If you have a third-party Redis installation you would like to use all you need to do is set the following values in your helm chart: db = \"0\" host = \"my.host.redis\" port = \"6379\" password = \"\" These can be changed by running helm inspect values drycc/workflow > values.yaml before using helm install to complete the installation. To customize the redis credentials, edit values.yaml and modify the redis section of the file to tune these settings.","title":"Configuring Off Cluster Redis"},{"location":"managing-workflow/platform-logging/#debugging-logger","text":"If the drycc logs command encounters an error it will return the following message: Error: There are currently no log messages. Please check the following things: 1) Logger and fluentbit pods are running. 2) The application is writing logs to the logger component by checking that an entry in the ring buffer was created: kubectl --namespace=drycc logs 3) Making sure that the container logs were mounted properly into the fluentbit pod: kubectl --namespace=drycc exec ls /var/log/containers","title":"Debugging Logger"},{"location":"managing-workflow/platform-logging/#architecture-diagram","text":"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 Router \u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2510 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 Logger \u2502\u25c0\u2500\u2500\u2500\u25b6\u2502Redis\u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2518 Log file \u25b2 \u2502 \u2502 \u25bc \u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 logs/metrics \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502App Logs\u2502\u2500\u2500Log File\u2500\u2500\u25b6\u2502Fluentbit\u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500topics\u2500\u2500\u2500\u2500\u2500\u25b6\u2502 Redis Stream \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518","title":"Architecture Diagram"},{"location":"managing-workflow/platform-logging/#default-configuration","text":"Fluent Bit is based in a pluggable architecture where different plugins plays a major role in the data pipeline, more than 70 built-in plugins available. Please refer to charts values.yaml for specific configurations.","title":"Default Configuration"},{"location":"managing-workflow/platform-monitoring/","text":"Platform Monitoring \u00b6 Description \u00b6 We now include a monitoring stack for introspection on a running Kubernetes cluster. The stack includes 4 components: kube-state-metrics , kube-state-metrics (KSM) is a simple service that listens to the Kubernetes API server and generates metrics about the state of the objects. Node Exporter , Prometheus exporter for hardware and OS metrics exposed by *NIX kernels. Prometheus , a Cloud Native Computing Foundation project, is a systems and service monitoring system. Grafana , Graphing tool for time series data Architecture Diagram \u00b6 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 HOST \u2502 \u2502 node-exporter \u2502\u25c0\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502kube-state-metrics\u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u25b2 \u2502 HOST \u2502 \u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 node-exporter \u2502\u25c0\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2502 Prometheus \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u25b2 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 \u2502 HOST \u2502 \u2502 \u25bc \u2502 node-exporter\u2502\u25c0\u2500\u2500\u2500\u2518 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 Grafana \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 Grafana \u00b6 Grafana allows users to create custom dashboards that visualize the data captured to the running Prometheus component. By default Grafana is exposed using a service annotation through the router at the following URL: http://grafana.mydomain.com . The default login is admin/admin . If you are interested in changing these values please see [Tuning Component Settings][]. Grafana will preload several dashboards to help operators get started with monitoring Kubernetes and Drycc Workflow. These dashboards are meant as starting points and don't include every item that might be desirable to monitor in a production installation. Drycc Workflow monitoring by default does not write data to the host filesystem or to long-term storage. If the Grafana instance fails, modified dashboards are lost. Production Configuration \u00b6 A production install of Grafana should have the following configuration values changed if possible: Change the default username and password from admin/admin . The value for the password is passed in plain text so it is best to set this value on the command line instead of checking it into version control. Enable persistence Use a supported external database such as mysql or postgres. You can find more information here On Cluster Persistence \u00b6 Enabling persistence will allow your custom configuration to persist across pod restarts. This means that the default sqllite database (which stores things like sessions and user data) will not disappear if you upgrade the Workflow installation. If you wish to have persistence for Grafana you can set enabled to true in the values.yaml file before running helm install . grafana: # Configure the following ONLY if you want persistence for on-cluster grafana # GCP PDs and EBS volumes are supported only persistence: enabled: true # Set to true to enable persistence size: 5Gi # PVC size Off Cluster Grafana \u00b6 If you wish to provide your own Grafana instance you can set grafanaLocation in the values.yaml file before running helm install . Prometheus \u00b6 Prometheus writes data to the host disk; however, if the prometheus pod dies and comes back on another host, the data will not be recovered. The prometheus graph UI is also exposed through the router allowing users to access the query engine by going to prometheus.mydomain.com . On Cluster Persistence \u00b6 You can set node-exporter and kube-state-metrics to true or false in the values.yaml . If you wish to have persistence for Prometheus you can set enabled to true in the values.yaml file before running helm install . prometheus: prometheus-server: persistence: enabled: true # Set to true to enable persistence size: 10Gi # PVC size node-exporter: enabled: true kube-state-metrics: enabled: true Off Cluster Prometheus \u00b6 To use off-cluster Prometheus, please provide the following values in the values.yaml file before running helm install . global.prometheusLocation=off-cluster url = \"http://my.prometheus.url:9090\"","title":"Platform Monitoring"},{"location":"managing-workflow/platform-monitoring/#platform-monitoring","text":"","title":"Platform Monitoring"},{"location":"managing-workflow/platform-monitoring/#description","text":"We now include a monitoring stack for introspection on a running Kubernetes cluster. The stack includes 4 components: kube-state-metrics , kube-state-metrics (KSM) is a simple service that listens to the Kubernetes API server and generates metrics about the state of the objects. Node Exporter , Prometheus exporter for hardware and OS metrics exposed by *NIX kernels. Prometheus , a Cloud Native Computing Foundation project, is a systems and service monitoring system. Grafana , Graphing tool for time series data","title":"Description"},{"location":"managing-workflow/platform-monitoring/#architecture-diagram","text":"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 HOST \u2502 \u2502 node-exporter \u2502\u25c0\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502kube-state-metrics\u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u25b2 \u2502 HOST \u2502 \u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 node-exporter \u2502\u25c0\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2502 Prometheus \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u25b2 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 \u2502 HOST \u2502 \u2502 \u25bc \u2502 node-exporter\u2502\u25c0\u2500\u2500\u2500\u2518 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 Grafana \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518","title":"Architecture Diagram"},{"location":"managing-workflow/platform-monitoring/#grafana","text":"Grafana allows users to create custom dashboards that visualize the data captured to the running Prometheus component. By default Grafana is exposed using a service annotation through the router at the following URL: http://grafana.mydomain.com . The default login is admin/admin . If you are interested in changing these values please see [Tuning Component Settings][]. Grafana will preload several dashboards to help operators get started with monitoring Kubernetes and Drycc Workflow. These dashboards are meant as starting points and don't include every item that might be desirable to monitor in a production installation. Drycc Workflow monitoring by default does not write data to the host filesystem or to long-term storage. If the Grafana instance fails, modified dashboards are lost.","title":"Grafana"},{"location":"managing-workflow/platform-monitoring/#production-configuration","text":"A production install of Grafana should have the following configuration values changed if possible: Change the default username and password from admin/admin . The value for the password is passed in plain text so it is best to set this value on the command line instead of checking it into version control. Enable persistence Use a supported external database such as mysql or postgres. You can find more information here","title":"Production Configuration"},{"location":"managing-workflow/platform-monitoring/#on-cluster-persistence","text":"Enabling persistence will allow your custom configuration to persist across pod restarts. This means that the default sqllite database (which stores things like sessions and user data) will not disappear if you upgrade the Workflow installation. If you wish to have persistence for Grafana you can set enabled to true in the values.yaml file before running helm install . grafana: # Configure the following ONLY if you want persistence for on-cluster grafana # GCP PDs and EBS volumes are supported only persistence: enabled: true # Set to true to enable persistence size: 5Gi # PVC size","title":"On Cluster Persistence"},{"location":"managing-workflow/platform-monitoring/#off-cluster-grafana","text":"If you wish to provide your own Grafana instance you can set grafanaLocation in the values.yaml file before running helm install .","title":"Off Cluster Grafana"},{"location":"managing-workflow/platform-monitoring/#prometheus","text":"Prometheus writes data to the host disk; however, if the prometheus pod dies and comes back on another host, the data will not be recovered. The prometheus graph UI is also exposed through the router allowing users to access the query engine by going to prometheus.mydomain.com .","title":"Prometheus"},{"location":"managing-workflow/platform-monitoring/#on-cluster-persistence_1","text":"You can set node-exporter and kube-state-metrics to true or false in the values.yaml . If you wish to have persistence for Prometheus you can set enabled to true in the values.yaml file before running helm install . prometheus: prometheus-server: persistence: enabled: true # Set to true to enable persistence size: 10Gi # PVC size node-exporter: enabled: true kube-state-metrics: enabled: true","title":"On Cluster Persistence"},{"location":"managing-workflow/platform-monitoring/#off-cluster-prometheus","text":"To use off-cluster Prometheus, please provide the following values in the values.yaml file before running helm install . global.prometheusLocation=off-cluster url = \"http://my.prometheus.url:9090\"","title":"Off Cluster Prometheus"},{"location":"managing-workflow/production-deployments/","text":"Production Deployments \u00b6 When readying a Workflow deployment for production workloads, there are some additional recommendations. Running Workflow without drycc storage \u00b6 In production, persistent storage can be achieved by running an external object store. For users on AWS, GCE/GKE or Azure, the convenience of Amazon S3, Google GCS or Microsoft Azure Storage makes the prospect of running a Storage-less Workflow cluster quite reasonable. For users who have restriction on using external object storage using swift object storage can be an option. Running a Workflow cluster without Storage provides several advantages: Removal of state from the worker nodes Reduced resource usage Reduced complexity and operational burden of managing Workflow See Configuring Object Storage for details on removing this operational complexity. Review Security Considerations \u00b6 There are some additional security-related considerations when running Workflow in production. See [Security Considerations][] for details. Registration is Admin-Only \u00b6 By default, registration with the Workflow controller is in \"admin_only\" mode. The first user to run a drycc register command becomes the initial \"admin\" user, and registrations after that are disallowed unless requested by an admin. Please see the following documentation to learn about changing registration mode: Customizing Controller Disable Grafana Signups \u00b6 It is also recommended to disable signups for the Grafana dashboards. Please see the following documentation to learn about disabling Grafana signups: Customizing Monitor Running Workflow with RBAC \u00b6 If your cluster has RBAC amongst your authorization modes ( $ kubectl api-versions should contains rbac.authorization.k8s.io ) it may be necessary to enable RBAC in Workflow. This can be achieved by setting use_rbac in the global section of values.yaml to true , or by adding --set=global.use_rbac=true to the $ helm install/upgrade command. RBAC support was announced in Kubernetes-1.5 and is enabled by default if: - your Kubernetes cluster is in GKE - your Kubernetes cluster built with kubeadm Note : helm may need to be given specific permissions under RBAC if not already done. Attention : Azure ACS Kubernetes clusters are not RBAC-enabled for today due to lack in authentication strategy. Feel free to watch this PR for more details.","title":"Production Deployments"},{"location":"managing-workflow/production-deployments/#production-deployments","text":"When readying a Workflow deployment for production workloads, there are some additional recommendations.","title":"Production Deployments"},{"location":"managing-workflow/production-deployments/#running-workflow-without-drycc-storage","text":"In production, persistent storage can be achieved by running an external object store. For users on AWS, GCE/GKE or Azure, the convenience of Amazon S3, Google GCS or Microsoft Azure Storage makes the prospect of running a Storage-less Workflow cluster quite reasonable. For users who have restriction on using external object storage using swift object storage can be an option. Running a Workflow cluster without Storage provides several advantages: Removal of state from the worker nodes Reduced resource usage Reduced complexity and operational burden of managing Workflow See Configuring Object Storage for details on removing this operational complexity.","title":"Running Workflow without drycc storage"},{"location":"managing-workflow/production-deployments/#review-security-considerations","text":"There are some additional security-related considerations when running Workflow in production. See [Security Considerations][] for details.","title":"Review Security Considerations"},{"location":"managing-workflow/production-deployments/#registration-is-admin-only","text":"By default, registration with the Workflow controller is in \"admin_only\" mode. The first user to run a drycc register command becomes the initial \"admin\" user, and registrations after that are disallowed unless requested by an admin. Please see the following documentation to learn about changing registration mode: Customizing Controller","title":"Registration is Admin-Only"},{"location":"managing-workflow/production-deployments/#disable-grafana-signups","text":"It is also recommended to disable signups for the Grafana dashboards. Please see the following documentation to learn about disabling Grafana signups: Customizing Monitor","title":"Disable Grafana Signups"},{"location":"managing-workflow/production-deployments/#running-workflow-with-rbac","text":"If your cluster has RBAC amongst your authorization modes ( $ kubectl api-versions should contains rbac.authorization.k8s.io ) it may be necessary to enable RBAC in Workflow. This can be achieved by setting use_rbac in the global section of values.yaml to true , or by adding --set=global.use_rbac=true to the $ helm install/upgrade command. RBAC support was announced in Kubernetes-1.5 and is enabled by default if: - your Kubernetes cluster is in GKE - your Kubernetes cluster built with kubeadm Note : helm may need to be given specific permissions under RBAC if not already done. Attention : Azure ACS Kubernetes clusters are not RBAC-enabled for today due to lack in authentication strategy. Feel free to watch this PR for more details.","title":"Running Workflow with RBAC"},{"location":"managing-workflow/tuning-component-settings/","text":"Tuning Component Settings \u00b6 Helm Charts are a set of Kubernetes manifests that reflect best practices for deploying an application or service on Kubernetes. After you add the Drycc Chart Repository, you can customize the chart using helm inspect values drycc/workflow > values.yaml before using helm install to complete the installation. There are a few ways to customize the respective component: If the value is exposed in the values.yaml file as derived above, one may modify the section of the component to tune these settings. The modified value(s) will then take effect at chart installation or release upgrade time via either of the two respective commands: $ helm install drycc oci://registry.drycc.cc/charts/workflow \\ -n drycc \\ --namespace drycc \\ -f values.yaml $ helm upgrade drycc oci://registry.drycc.cc/charts/workflow \\ -n drycc \\ --namespace drycc \\ -f values.yaml If the value hasn't yet been exposed in the values.yaml file, one may edit the component deployment with the tuned setting. Here we edit the drycc-controller deployment: $ kubectl --namespace drycc edit deployment drycc-controller Add/edit the setting via the appropriate environment variable and value under the env section and save. The updated deployment will recreate the component pod with the new/modified setting. Lastly, one may also fetch and edit the chart as served by version control/the chart repository itself: $ helm fetch oci://registry.drycc.cc/charts/workflow --untar $ $EDITOR workflow/charts/controller/templates/controller-deployment.yaml Then run helm install ./workflow --namespace drycc --name drycc to apply the changes, or helm upgrade drycc ./workflow if the cluster is already running. Setting Resource limits \u00b6 You can set resource limits to Workflow components by modifying the values.yaml file fetched earlier. This file has a section for each Workflow component. To set a limit to any Workflow component just add limitsCpu , limitsMemory in the section and set them to the appropriate values. Below is an example of how the builder section of values.yaml might look with CPU and memory limits set: builder: imageOrg: \"drycc\" imagePullPolicy: \"Always\" imageTag: \"canary\" limitsCpu: \"100m\" limitsMemory: \"50Mi\" Customizing the Builder \u00b6 The following environment variables are tunable for the Builder component: Setting Description DEBUG Enable debug log output (default: false) BUILDER_POD_NODE_SELECTOR A node selector setting for builder job. As it may sometimes consume a lot of node resources, one may want a given builder job to run in a specific node only, so it won't affect critical nodes. for example pool:testing,disk:magnetic Customizing the Controller \u00b6 The following environment variables are tunable for the Controller component: Setting Description REGISTRATION_MODE set registration to \"enabled\", \"disabled\", or \"admin_only\" (default: \"admin_only\") GUNICORN_WORKERS number of gunicorn workers spawned to process requests (default: CPU cores * 4 + 1) RESERVED_NAMES a comma-separated list of names which applications cannot reserve for routing (default: \"drycc, drycc-builder\") DRYCC_DEPLOY_HOOK_URLS a comma-separated list of URLs to send deploy hooks to. DRYCC_DEPLOY_HOOK_SECRET_KEY a private key used to compute the HMAC signature for deploy hooks. DRYCC_DEPLOY_REJECT_IF_PROCFILE_MISSING rejects a deploy if the previous build had a Procfile but the current deploy is missing it. A 409 is thrown in the API. Prevents accidental process types removal. (default: \"false\", allowed values: \"true\", \"false\") DRYCC_DEPLOY_PROCFILE_MISSING_REMOVE when turned on (default) any missing process type in a Procfile compared to the previous deploy is removed. When set to false will allow an empty Procfile to go through without removing missing process types, note that new images, configs and so on will get updated on all proc types. (default: \"true\", allowed values: \"true\", \"false\") DRYCC_DEFAULT_CONFIG_TAGS set tags for all applications by default, for example: '{\"role\": \"worker\"}'. (default: '') KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPEC set resource quota to application namespace by setting ResourceQuota spec, for example: {\"spec\":{\"hard\":{\"pods\":\"10\"}}} , restrict app owner to spawn more then 10 pods (default: \"\", no quota will be applied to namespace) LDAP authentication settings \u00b6 Configuration options for LDAP authentication are detailed here . The following environment variables are available for enabling LDAP authentication of user accounts in the Passport component: Setting Description LDAP_ENDPOINT The URI of the LDAP server. If not specified, LDAP authentication is not enabled (default: \"\", example: ldap://hostname ). LDAP_BIND_DN The distinguished name to use when binding to the LDAP server (default: \"\") LDAP_BIND_PASSWORD The password to use with LDAP_BIND_DN (default: \"\") LDAP_USER_BASEDN The distinguished name of the search base for user names (default: \"\") LDAP_USER_FILTER The name of the login field in the users search base (default: \"username\") LDAP_GROUP_BASEDN The distinguished name of the search base for user's groups names (default: \"\") LDAP_GROUP_FILTER The filter for user's groups (default: \"\", example: objectClass=person ) Global and per application settings \u00b6 Setting Description DRYCC_DEPLOY_BATCHES the number of pods to bring up and take down sequentially during a scale (default: number of available nodes) DRYCC_DEPLOY_TIMEOUT deploy timeout in seconds per deploy batch (default: 120) IMAGE_PULL_POLICY the kubernetes image pull policy for application images (default: \"IfNotPresent\") (allowed values: \"Always\", \"IfNotPresent\") KUBERNETES_DEPLOYMENTS_REVISION_HISTORY_LIMIT how many revisions Kubernetes keeps around of a given Deployment (default: all revisions) KUBERNETES_POD_TERMINATION_GRACE_PERIOD_SECONDS how many seconds kubernetes waits for a pod to finish work after a SIGTERM before sending SIGKILL (default: 30) See the Deploying Apps guide for more detailed information on those. Customizing the Database \u00b6 The following environment variables are tunable for the Database component: Setting Description BACKUP_FREQUENCY how often the database should perform a base backup (default: \"12h\") BACKUPS_TO_RETAIN number of base backups the backing store should retain (default: 5) Customizing Fluentbit \u00b6 The following values can be changed in the values.yaml file or by using the --values flag with the Helm CLI. Key Description config.service The service section defines the global properties of the service. config.inputs An input section defines a source (related to an input plugin). config.filters A filter section defines a filter (related to a filter plugin) config.outputs The outputs section specify a destination that certain records should follow after a Tag match. For more information about the various variables that can be set please see the fluentbit . Customizing the Logger \u00b6 The following environment variables are tunable for the Logger component: Setting Description STORAGE_ADAPTER How to store logs that are sent to the logger. Legal values are \"file\", \"memory\", and \"redis\". (default: \"redis\") NUMBER_OF_LINES How many lines to store in the ring buffer (default: 1000) Customizing the Monitor \u00b6 Grafana \u00b6 We have exposed some of the more useful configuration values directly in the chart. This allows them to be set using either the values.yaml file or by using the --set flag with the Helm CLI. You can see these options below: Setting | Default Value | Description ----------------- | -------------- |------------ | user | \"admin\" | The first user created in the database (this user has admin privileges) password | \"admin\" | Password for the first user. allow_sign_up | \"true\" | Allows users to sign up for an account. For a list of other options you can set by using environment variables please see the configuration file in Github. Telegraf \u00b6 For a list of configuration values that can be set by using environment variables please see the following configuration file . Prometheus \u00b6 You can find a list of values that can be set using environment variables here . Customizing the Registry \u00b6 The Registry component can be tuned by following the drycc/distribution config doc . Customizing the Router \u00b6 The majority of router settings are tunable through annotations, which allows the router to be re-configured with zero downtime post-installation. You can find the list of annotations to tune here . The following environment variables are tunable for the [Router][] component: Setting Description POD_NAMESPACE The pod namespace the router resides in. This is set by the Kubernetes downward API . Customizing Workflow Manager \u00b6 The following environment variables are tunable for [Workflow Manager][]: Setting Description CHECK_VERSIONS Enables the external version check at https://versions.drycc.info/ (default: \"true\") POLL_INTERVAL_SEC The interval when Workflow Manager performs a version check, in seconds (default: 43200, or 12 hours) VERSIONS_API_URL The versions API URL (default: \" https://versions-staging.drycc.info \") DOCTOR_API_URL The doctor API URL (default: \" https://doctor-staging.drycc.info \") API_VERSION The version number Workflow Manager sends to the versions API (default: \"v2\")","title":"Tuning Component Settings"},{"location":"managing-workflow/tuning-component-settings/#tuning-component-settings","text":"Helm Charts are a set of Kubernetes manifests that reflect best practices for deploying an application or service on Kubernetes. After you add the Drycc Chart Repository, you can customize the chart using helm inspect values drycc/workflow > values.yaml before using helm install to complete the installation. There are a few ways to customize the respective component: If the value is exposed in the values.yaml file as derived above, one may modify the section of the component to tune these settings. The modified value(s) will then take effect at chart installation or release upgrade time via either of the two respective commands: $ helm install drycc oci://registry.drycc.cc/charts/workflow \\ -n drycc \\ --namespace drycc \\ -f values.yaml $ helm upgrade drycc oci://registry.drycc.cc/charts/workflow \\ -n drycc \\ --namespace drycc \\ -f values.yaml If the value hasn't yet been exposed in the values.yaml file, one may edit the component deployment with the tuned setting. Here we edit the drycc-controller deployment: $ kubectl --namespace drycc edit deployment drycc-controller Add/edit the setting via the appropriate environment variable and value under the env section and save. The updated deployment will recreate the component pod with the new/modified setting. Lastly, one may also fetch and edit the chart as served by version control/the chart repository itself: $ helm fetch oci://registry.drycc.cc/charts/workflow --untar $ $EDITOR workflow/charts/controller/templates/controller-deployment.yaml Then run helm install ./workflow --namespace drycc --name drycc to apply the changes, or helm upgrade drycc ./workflow if the cluster is already running.","title":"Tuning Component Settings"},{"location":"managing-workflow/tuning-component-settings/#setting-resource-limits","text":"You can set resource limits to Workflow components by modifying the values.yaml file fetched earlier. This file has a section for each Workflow component. To set a limit to any Workflow component just add limitsCpu , limitsMemory in the section and set them to the appropriate values. Below is an example of how the builder section of values.yaml might look with CPU and memory limits set: builder: imageOrg: \"drycc\" imagePullPolicy: \"Always\" imageTag: \"canary\" limitsCpu: \"100m\" limitsMemory: \"50Mi\"","title":"Setting Resource limits"},{"location":"managing-workflow/tuning-component-settings/#customizing-the-builder","text":"The following environment variables are tunable for the Builder component: Setting Description DEBUG Enable debug log output (default: false) BUILDER_POD_NODE_SELECTOR A node selector setting for builder job. As it may sometimes consume a lot of node resources, one may want a given builder job to run in a specific node only, so it won't affect critical nodes. for example pool:testing,disk:magnetic","title":"Customizing the Builder"},{"location":"managing-workflow/tuning-component-settings/#customizing-the-controller","text":"The following environment variables are tunable for the Controller component: Setting Description REGISTRATION_MODE set registration to \"enabled\", \"disabled\", or \"admin_only\" (default: \"admin_only\") GUNICORN_WORKERS number of gunicorn workers spawned to process requests (default: CPU cores * 4 + 1) RESERVED_NAMES a comma-separated list of names which applications cannot reserve for routing (default: \"drycc, drycc-builder\") DRYCC_DEPLOY_HOOK_URLS a comma-separated list of URLs to send deploy hooks to. DRYCC_DEPLOY_HOOK_SECRET_KEY a private key used to compute the HMAC signature for deploy hooks. DRYCC_DEPLOY_REJECT_IF_PROCFILE_MISSING rejects a deploy if the previous build had a Procfile but the current deploy is missing it. A 409 is thrown in the API. Prevents accidental process types removal. (default: \"false\", allowed values: \"true\", \"false\") DRYCC_DEPLOY_PROCFILE_MISSING_REMOVE when turned on (default) any missing process type in a Procfile compared to the previous deploy is removed. When set to false will allow an empty Procfile to go through without removing missing process types, note that new images, configs and so on will get updated on all proc types. (default: \"true\", allowed values: \"true\", \"false\") DRYCC_DEFAULT_CONFIG_TAGS set tags for all applications by default, for example: '{\"role\": \"worker\"}'. (default: '') KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPEC set resource quota to application namespace by setting ResourceQuota spec, for example: {\"spec\":{\"hard\":{\"pods\":\"10\"}}} , restrict app owner to spawn more then 10 pods (default: \"\", no quota will be applied to namespace)","title":"Customizing the Controller"},{"location":"managing-workflow/tuning-component-settings/#ldap-authentication-settings","text":"Configuration options for LDAP authentication are detailed here . The following environment variables are available for enabling LDAP authentication of user accounts in the Passport component: Setting Description LDAP_ENDPOINT The URI of the LDAP server. If not specified, LDAP authentication is not enabled (default: \"\", example: ldap://hostname ). LDAP_BIND_DN The distinguished name to use when binding to the LDAP server (default: \"\") LDAP_BIND_PASSWORD The password to use with LDAP_BIND_DN (default: \"\") LDAP_USER_BASEDN The distinguished name of the search base for user names (default: \"\") LDAP_USER_FILTER The name of the login field in the users search base (default: \"username\") LDAP_GROUP_BASEDN The distinguished name of the search base for user's groups names (default: \"\") LDAP_GROUP_FILTER The filter for user's groups (default: \"\", example: objectClass=person )","title":"LDAP authentication settings"},{"location":"managing-workflow/tuning-component-settings/#global-and-per-application-settings","text":"Setting Description DRYCC_DEPLOY_BATCHES the number of pods to bring up and take down sequentially during a scale (default: number of available nodes) DRYCC_DEPLOY_TIMEOUT deploy timeout in seconds per deploy batch (default: 120) IMAGE_PULL_POLICY the kubernetes image pull policy for application images (default: \"IfNotPresent\") (allowed values: \"Always\", \"IfNotPresent\") KUBERNETES_DEPLOYMENTS_REVISION_HISTORY_LIMIT how many revisions Kubernetes keeps around of a given Deployment (default: all revisions) KUBERNETES_POD_TERMINATION_GRACE_PERIOD_SECONDS how many seconds kubernetes waits for a pod to finish work after a SIGTERM before sending SIGKILL (default: 30) See the Deploying Apps guide for more detailed information on those.","title":"Global and per application settings"},{"location":"managing-workflow/tuning-component-settings/#customizing-the-database","text":"The following environment variables are tunable for the Database component: Setting Description BACKUP_FREQUENCY how often the database should perform a base backup (default: \"12h\") BACKUPS_TO_RETAIN number of base backups the backing store should retain (default: 5)","title":"Customizing the Database"},{"location":"managing-workflow/tuning-component-settings/#customizing-fluentbit","text":"The following values can be changed in the values.yaml file or by using the --values flag with the Helm CLI. Key Description config.service The service section defines the global properties of the service. config.inputs An input section defines a source (related to an input plugin). config.filters A filter section defines a filter (related to a filter plugin) config.outputs The outputs section specify a destination that certain records should follow after a Tag match. For more information about the various variables that can be set please see the fluentbit .","title":"Customizing Fluentbit"},{"location":"managing-workflow/tuning-component-settings/#customizing-the-logger","text":"The following environment variables are tunable for the Logger component: Setting Description STORAGE_ADAPTER How to store logs that are sent to the logger. Legal values are \"file\", \"memory\", and \"redis\". (default: \"redis\") NUMBER_OF_LINES How many lines to store in the ring buffer (default: 1000)","title":"Customizing the Logger"},{"location":"managing-workflow/tuning-component-settings/#customizing-the-monitor","text":"","title":"Customizing the Monitor"},{"location":"managing-workflow/tuning-component-settings/#grafana","text":"We have exposed some of the more useful configuration values directly in the chart. This allows them to be set using either the values.yaml file or by using the --set flag with the Helm CLI. You can see these options below: Setting | Default Value | Description ----------------- | -------------- |------------ | user | \"admin\" | The first user created in the database (this user has admin privileges) password | \"admin\" | Password for the first user. allow_sign_up | \"true\" | Allows users to sign up for an account. For a list of other options you can set by using environment variables please see the configuration file in Github.","title":"Grafana"},{"location":"managing-workflow/tuning-component-settings/#telegraf","text":"For a list of configuration values that can be set by using environment variables please see the following configuration file .","title":"Telegraf"},{"location":"managing-workflow/tuning-component-settings/#prometheus","text":"You can find a list of values that can be set using environment variables here .","title":"Prometheus"},{"location":"managing-workflow/tuning-component-settings/#customizing-the-registry","text":"The Registry component can be tuned by following the drycc/distribution config doc .","title":"Customizing the Registry"},{"location":"managing-workflow/tuning-component-settings/#customizing-the-router","text":"The majority of router settings are tunable through annotations, which allows the router to be re-configured with zero downtime post-installation. You can find the list of annotations to tune here . The following environment variables are tunable for the [Router][] component: Setting Description POD_NAMESPACE The pod namespace the router resides in. This is set by the Kubernetes downward API .","title":"Customizing the Router"},{"location":"managing-workflow/tuning-component-settings/#customizing-workflow-manager","text":"The following environment variables are tunable for [Workflow Manager][]: Setting Description CHECK_VERSIONS Enables the external version check at https://versions.drycc.info/ (default: \"true\") POLL_INTERVAL_SEC The interval when Workflow Manager performs a version check, in seconds (default: 43200, or 12 hours) VERSIONS_API_URL The versions API URL (default: \" https://versions-staging.drycc.info \") DOCTOR_API_URL The doctor API URL (default: \" https://doctor-staging.drycc.info \") API_VERSION The version number Workflow Manager sends to the versions API (default: \"v2\")","title":"Customizing Workflow Manager"},{"location":"managing-workflow/upgrading-workflow/","text":"Upgrading Workflow \u00b6 Drycc Workflow releases may be upgraded in-place with minimal downtime. This upgrade process requires: Helm version 2.1.0 or newer Configured Off-Cluster Storage Upgrade Process \u00b6 Note If upgrading from a Helm Classic install, you'll need to 'migrate' the cluster to a Kubernetes Helm installation. See Workflow-Migration for steps. Step 1: Apply the Workflow upgrade \u00b6 Helm will remove all components from the previous release. Traffic to applications deployed through Workflow will continue to flow during the upgrade. No service interruptions should occur. If Workflow is not configured to use off-cluster Postgres, the Workflow API will experience a brief period of downtime while the database recovers from backup. First, find the name of the release helm gave to your deployment with helm ls , then run $ helm upgrade oci://registry.drycc.cc/charts/workflow Note: If using off-cluster object storage on gcs and/or off-cluster registry using gcr and intending to upgrade from a pre- v2.10.0 chart to v2.10.0 or greater, the key_json values will now need to be pre-base64-encoded. Therefore, assuming the rest of the custom/off-cluster values are defined in the existing values.yaml used for previous installs, the following may be run: $ B64_KEY_JSON=\"$(cat ~/path/to/key.json | base64 -w 0)\" $ helm upgrade drycc/workflow -f values.yaml --set gcs.key_json=\"${B64_KEY_JSON}\",registry-token-refresher.gcr.key_json=\"${B64_KEY_JSON}\" Alternatively, simply replace the appropriate values in values.yaml and do without the --set parameter. Make sure to wrap it in single quotes as double quotes will give a parser error when upgrading. Step 2: Verify Upgrade \u00b6 Verify that all components have started and passed their readiness checks: $ kubectl --namespace=drycc get pods NAME READY STATUS RESTARTS AGE drycc-builder-2448122224-3cibz 1/1 Running 0 5m drycc-controller-1410285775-ipc34 1/1 Running 3 5m drycc-controller-celery-694f75749b-cmxxn 3/3 Running 0 5m drycc-database-e7c5z 1/1 Running 0 5m drycc-logger-cgjup 1/1 Running 3 5m drycc-logger-fluentbit-45h7j 1/1 Running 0 5m drycc-logger-fluentbit-4z7lw 1/1 Running 0 5m drycc-logger-fluentbit-k2wsw 1/1 Running 0 5m drycc-logger-fluentbit-skdw4 1/1 Running 0 5m drycc-redis-8nazu 1/1 Running 0 5m drycc-monitor-grafana-tm266 1/1 Running 0 5m drycc-monitor-telegraf-51zel 1/1 Running 1 5m drycc-monitor-telegraf-cdasg 1/1 Running 0 5m drycc-monitor-telegraf-hea6x 1/1 Running 0 5m drycc-monitor-telegraf-r7lsg 1/1 Running 0 5m drycc-registry-1814324048-yomz5 1/1 Running 0 5m drycc-registry-proxy-4m3o4 1/1 Running 0 5m drycc-registry-proxy-no3r1 1/1 Running 0 5m drycc-registry-proxy-ou8is 1/1 Running 0 5m drycc-registry-proxy-zyajl 1/1 Running 0 5m drycc-rabbitmq-0 1/1 Running 0 5m Step 3: Upgrade the Drycc Client \u00b6 Users of Drycc Workflow should now upgrade their drycc client to avoid getting WARNING: Client and server API versions do not match. Please consider upgrading. warnings. curl -sfL https://www.drycc.cc/install-cli.sh | bash - && sudo mv drycc $(which drycc)","title":"Upgrading Workflow"},{"location":"managing-workflow/upgrading-workflow/#upgrading-workflow","text":"Drycc Workflow releases may be upgraded in-place with minimal downtime. This upgrade process requires: Helm version 2.1.0 or newer Configured Off-Cluster Storage","title":"Upgrading Workflow"},{"location":"managing-workflow/upgrading-workflow/#upgrade-process","text":"Note If upgrading from a Helm Classic install, you'll need to 'migrate' the cluster to a Kubernetes Helm installation. See Workflow-Migration for steps.","title":"Upgrade Process"},{"location":"managing-workflow/upgrading-workflow/#step-1-apply-the-workflow-upgrade","text":"Helm will remove all components from the previous release. Traffic to applications deployed through Workflow will continue to flow during the upgrade. No service interruptions should occur. If Workflow is not configured to use off-cluster Postgres, the Workflow API will experience a brief period of downtime while the database recovers from backup. First, find the name of the release helm gave to your deployment with helm ls , then run $ helm upgrade oci://registry.drycc.cc/charts/workflow Note: If using off-cluster object storage on gcs and/or off-cluster registry using gcr and intending to upgrade from a pre- v2.10.0 chart to v2.10.0 or greater, the key_json values will now need to be pre-base64-encoded. Therefore, assuming the rest of the custom/off-cluster values are defined in the existing values.yaml used for previous installs, the following may be run: $ B64_KEY_JSON=\"$(cat ~/path/to/key.json | base64 -w 0)\" $ helm upgrade drycc/workflow -f values.yaml --set gcs.key_json=\"${B64_KEY_JSON}\",registry-token-refresher.gcr.key_json=\"${B64_KEY_JSON}\" Alternatively, simply replace the appropriate values in values.yaml and do without the --set parameter. Make sure to wrap it in single quotes as double quotes will give a parser error when upgrading.","title":"Step 1: Apply the Workflow upgrade"},{"location":"managing-workflow/upgrading-workflow/#step-2-verify-upgrade","text":"Verify that all components have started and passed their readiness checks: $ kubectl --namespace=drycc get pods NAME READY STATUS RESTARTS AGE drycc-builder-2448122224-3cibz 1/1 Running 0 5m drycc-controller-1410285775-ipc34 1/1 Running 3 5m drycc-controller-celery-694f75749b-cmxxn 3/3 Running 0 5m drycc-database-e7c5z 1/1 Running 0 5m drycc-logger-cgjup 1/1 Running 3 5m drycc-logger-fluentbit-45h7j 1/1 Running 0 5m drycc-logger-fluentbit-4z7lw 1/1 Running 0 5m drycc-logger-fluentbit-k2wsw 1/1 Running 0 5m drycc-logger-fluentbit-skdw4 1/1 Running 0 5m drycc-redis-8nazu 1/1 Running 0 5m drycc-monitor-grafana-tm266 1/1 Running 0 5m drycc-monitor-telegraf-51zel 1/1 Running 1 5m drycc-monitor-telegraf-cdasg 1/1 Running 0 5m drycc-monitor-telegraf-hea6x 1/1 Running 0 5m drycc-monitor-telegraf-r7lsg 1/1 Running 0 5m drycc-registry-1814324048-yomz5 1/1 Running 0 5m drycc-registry-proxy-4m3o4 1/1 Running 0 5m drycc-registry-proxy-no3r1 1/1 Running 0 5m drycc-registry-proxy-ou8is 1/1 Running 0 5m drycc-registry-proxy-zyajl 1/1 Running 0 5m drycc-rabbitmq-0 1/1 Running 0 5m","title":"Step 2: Verify Upgrade"},{"location":"managing-workflow/upgrading-workflow/#step-3-upgrade-the-drycc-client","text":"Users of Drycc Workflow should now upgrade their drycc client to avoid getting WARNING: Client and server API versions do not match. Please consider upgrading. warnings. curl -sfL https://www.drycc.cc/install-cli.sh | bash - && sudo mv drycc $(which drycc)","title":"Step 3: Upgrade the Drycc Client"},{"location":"quickstart/","text":"Quick Start \u00b6 Get started with Drycc Workflow in three easy steps. Install CLI tools for Helm and Drycc Workflow Boot a Kubernetes and install Drycc Workflow Deploy your first application This guide will help you set up a cluster suitable for evaluation, development and testing. When you are ready for staging and production, view our production checklist . Step 1: Install Workflow \u00b6 For the quickstart we will install Drycc Workflow . Step 2: Install CLI tools \u00b6 For the quickstart we will install Drycc Workflow CLI . Step 3: Deploy your first app \u00b6 Last but not least, login and deploy your first application .","title":"Overview"},{"location":"quickstart/#quick-start","text":"Get started with Drycc Workflow in three easy steps. Install CLI tools for Helm and Drycc Workflow Boot a Kubernetes and install Drycc Workflow Deploy your first application This guide will help you set up a cluster suitable for evaluation, development and testing. When you are ready for staging and production, view our production checklist .","title":"Quick Start"},{"location":"quickstart/#step-1-install-workflow","text":"For the quickstart we will install Drycc Workflow .","title":"Step 1: Install Workflow"},{"location":"quickstart/#step-2-install-cli-tools","text":"For the quickstart we will install Drycc Workflow CLI .","title":"Step 2: Install CLI tools"},{"location":"quickstart/#step-3-deploy-your-first-app","text":"Last but not least, login and deploy your first application .","title":"Step 3: Deploy your first app"},{"location":"quickstart/deploy-an-app/","text":"Determine Your Host and Hostname Values \u00b6 Drycc workflow requires a wildcard DNS record to dynamically map app names to the router. User should already have DNS set up pointing to their known host. The $hostname value can be calculated by prepending drycc. to the value set in global.platformDomain . Login to Workflow \u00b6 Workflow use the passport component to create and authorize users. If you already have an account, use drycc login to authenticate against the Drycc Workflow API. $ drycc login http://drycc.example.com Opening browser to http://drycc.example.com/v2/login/drycc/?key=4ccc81ee2dce4349ad5261ceffe72c71 Waiting for login... .o.Logged in as admin Configuration file written to /root/.drycc/client.json Deploy an Application \u00b6 Drycc Workflow supports three different types of applications, Buildpacks, Dockerfiles and Container Images. Our first application will be a simple Container Image-based application, so you don't have to wrestle with checking out code. Run drycc create to create a new application on Drycc Workflow. If you do not specify a name for your application, Workflow automatically generates a friendly (and sometimes funny) name. $ drycc create --no-remote Creating Application... done, created proper-barbecue If you want to add a git remote for this app later, use `drycc git:remote -a proper-barbecue` Our application has been created and named proper-barbecue . As with the drycc hostname, any HTTP traffic to proper-barbecue will be automatically routed to your application pods by the edge router. Let's use the CLI to tell the platform to deploy an application and then use curl to send a request to the app: $ drycc pull drycc/example-go -a proper-barbecue Creating build... done $ curl http://proper-barbecue.$hostname Powered by Drycc Note If you see a 404 error, make sure you specified your application name with -a ! Workflow's edge router knows all about application names and automatically sends traffic to the right application. The router sends traffic for proper-barbecue.104.197.125.75.nip.io to your app, just like drycc.104.197.125.75.nip.io was sent to the Workflow API service. Change Application Configuration \u00b6 Next, let's change some configuration using the CLI. Our example app is built to read configuration from the environment. By using drycc config:set we can change how the application behaves: $ drycc config:set POWERED_BY=\"Container Images + Kubernetes\" -a proper-barbecue Creating config... done === proper-barbecue Config POWERED_BY Container Images + Kubernetes Behind the scenes, Workflow creates a new release for your application and uses Kubernetes to provide a zero-downtime rolling deploy to the new release! Validate that our configuration change has worked: $ curl http://proper-barbecue.104.197.125.75.nip.io Powered by Container Images + Kubernetes Scale Your Application \u00b6 Last, let's scale our application by adding more application processes. Using the CLI you can easily add and remove additional processes to service requests: $ drycc scale cmd=2 -a proper-barbecue Scaling processes... but first, coffee! done in 36s === proper-barbecue Processes --- cmd (started): 2 proper-barbecue-v18-cmd-rk644 up (v18) proper-barbecue-v18-cmd-0ag04 up (v18) Congratulations! You have deployed, configured, and scaled your first application using Drycc Workflow. Going Further \u00b6 There is a lot more you can do with Drycc Workflow, play around with the CLI: Important In order to have permission to push an app you must add a SSH key to your user on the Drycc Workflow. For more information, please check Users and SSH Keys and Troubleshooting Workflow . Roll back to a previous release with drycc rollback -a proper-barbecue See application logs with drycc logs -a proper-barbecue Try one of our other example applications like: drycc/ruby-getting-started drycc/python-getting-started drycc/php-getting-started Read about using application Buildpacks or Dockerfiles Join our #community slack channel and meet the team!","title":"Deploy Your First App"},{"location":"quickstart/deploy-an-app/#determine-your-host-and-hostname-values","text":"Drycc workflow requires a wildcard DNS record to dynamically map app names to the router. User should already have DNS set up pointing to their known host. The $hostname value can be calculated by prepending drycc. to the value set in global.platformDomain .","title":"Determine Your Host and Hostname Values"},{"location":"quickstart/deploy-an-app/#login-to-workflow","text":"Workflow use the passport component to create and authorize users. If you already have an account, use drycc login to authenticate against the Drycc Workflow API. $ drycc login http://drycc.example.com Opening browser to http://drycc.example.com/v2/login/drycc/?key=4ccc81ee2dce4349ad5261ceffe72c71 Waiting for login... .o.Logged in as admin Configuration file written to /root/.drycc/client.json","title":"Login to Workflow"},{"location":"quickstart/deploy-an-app/#deploy-an-application","text":"Drycc Workflow supports three different types of applications, Buildpacks, Dockerfiles and Container Images. Our first application will be a simple Container Image-based application, so you don't have to wrestle with checking out code. Run drycc create to create a new application on Drycc Workflow. If you do not specify a name for your application, Workflow automatically generates a friendly (and sometimes funny) name. $ drycc create --no-remote Creating Application... done, created proper-barbecue If you want to add a git remote for this app later, use `drycc git:remote -a proper-barbecue` Our application has been created and named proper-barbecue . As with the drycc hostname, any HTTP traffic to proper-barbecue will be automatically routed to your application pods by the edge router. Let's use the CLI to tell the platform to deploy an application and then use curl to send a request to the app: $ drycc pull drycc/example-go -a proper-barbecue Creating build... done $ curl http://proper-barbecue.$hostname Powered by Drycc Note If you see a 404 error, make sure you specified your application name with -a ! Workflow's edge router knows all about application names and automatically sends traffic to the right application. The router sends traffic for proper-barbecue.104.197.125.75.nip.io to your app, just like drycc.104.197.125.75.nip.io was sent to the Workflow API service.","title":"Deploy an Application"},{"location":"quickstart/deploy-an-app/#change-application-configuration","text":"Next, let's change some configuration using the CLI. Our example app is built to read configuration from the environment. By using drycc config:set we can change how the application behaves: $ drycc config:set POWERED_BY=\"Container Images + Kubernetes\" -a proper-barbecue Creating config... done === proper-barbecue Config POWERED_BY Container Images + Kubernetes Behind the scenes, Workflow creates a new release for your application and uses Kubernetes to provide a zero-downtime rolling deploy to the new release! Validate that our configuration change has worked: $ curl http://proper-barbecue.104.197.125.75.nip.io Powered by Container Images + Kubernetes","title":"Change Application Configuration"},{"location":"quickstart/deploy-an-app/#scale-your-application","text":"Last, let's scale our application by adding more application processes. Using the CLI you can easily add and remove additional processes to service requests: $ drycc scale cmd=2 -a proper-barbecue Scaling processes... but first, coffee! done in 36s === proper-barbecue Processes --- cmd (started): 2 proper-barbecue-v18-cmd-rk644 up (v18) proper-barbecue-v18-cmd-0ag04 up (v18) Congratulations! You have deployed, configured, and scaled your first application using Drycc Workflow.","title":"Scale Your Application"},{"location":"quickstart/deploy-an-app/#going-further","text":"There is a lot more you can do with Drycc Workflow, play around with the CLI: Important In order to have permission to push an app you must add a SSH key to your user on the Drycc Workflow. For more information, please check Users and SSH Keys and Troubleshooting Workflow . Roll back to a previous release with drycc rollback -a proper-barbecue See application logs with drycc logs -a proper-barbecue Try one of our other example applications like: drycc/ruby-getting-started drycc/python-getting-started drycc/php-getting-started Read about using application Buildpacks or Dockerfiles Join our #community slack channel and meet the team!","title":"Going Further"},{"location":"quickstart/install-cli-tools/","text":"Drycc Workflow Client CLI \u00b6 The Drycc command-line interface (CLI), lets you interact with Drycc Workflow. Use the CLI to create and configure and manage applications. Install the drycc client for Linux or Mac OS X with: $ curl -sfL https://www.drycc.cc/install-cli.sh | bash - Important Users in Chinese mainland can use the following methods to speed up installation: $ curl -sfL https://www.drycc.cc/install-cli.sh | INSTALL_DRYCC_MIRROR=cn bash - Others please visit: https://github.com/drycc/workflow-cli/releases The installer places the drycc binary in your current directory, but you should move it somewhere in your $PATH: $ sudo ln -fs $PWD/drycc /usr/local/bin/drycc or : $ sudo mv $PWD/drycc /usr/local/bin/drycc Check your work by running drycc version : $ drycc version v1.1.0 Note Note that version numbers may vary as new releases become available","title":"Install CLI Tools"},{"location":"quickstart/install-cli-tools/#drycc-workflow-client-cli","text":"The Drycc command-line interface (CLI), lets you interact with Drycc Workflow. Use the CLI to create and configure and manage applications. Install the drycc client for Linux or Mac OS X with: $ curl -sfL https://www.drycc.cc/install-cli.sh | bash - Important Users in Chinese mainland can use the following methods to speed up installation: $ curl -sfL https://www.drycc.cc/install-cli.sh | INSTALL_DRYCC_MIRROR=cn bash - Others please visit: https://github.com/drycc/workflow-cli/releases The installer places the drycc binary in your current directory, but you should move it somewhere in your $PATH: $ sudo ln -fs $PWD/drycc /usr/local/bin/drycc or : $ sudo mv $PWD/drycc /usr/local/bin/drycc Check your work by running drycc version : $ drycc version v1.1.0 Note Note that version numbers may vary as new releases become available","title":"Drycc Workflow Client CLI"},{"location":"quickstart/install-workflow/","text":"Install Workflow \u00b6 If you have a pure host, it can be a cloud server, bare metal server, virtual machine, or even your laptop. Then this chapter is very suitable for you. Operating Systems \u00b6 Drycc is expected to work on most modern Linux systems. Some OSS have specific requirements: (Red Hat/CentOS) Enterprise Linux, they usually use RPM package management. Ubuntu (Desktop/Server/Cloud) Linux, a very popular distribution. Debian GNU Linux, a very pure distribution of opensource software. If you want to add more Linux distribution support, please submit a issue on github or submit PR directly. System Software \u00b6 Some basic software needs to be installed before installing drycc workflow. OS configuration \u00b6 K8s requires a large number of ports. If you are not sure what they are, please close the local firewall or open these ports. At the same time, because k8s you need system time, you need to ensure that the system time is correct. Installing open-iscsi \u00b6 The command used to install open-iscsi differs depending on the Linux distribution. We recommend using Ubuntu as the guest OS image since it contains open-iscsi already. You may need to edit the cluster security group to allow SSH access. For SUSE and openSUSE, use this command: $ zypper install open-iscsi For Debian and Ubuntu, use this command: $ apt-get install open-iscsi For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command: $ yum install iscsi-initiator-utils Installing NFSv4 client \u00b6 The command used to install a NFSv4 client differs depending on the Linux distribution. For Debian and Ubuntu, use this command: $ apt-get install nfs-common For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command: $ yum install nfs-utils Installing curl \u00b6 For Debian and Ubuntu, use this command: $ apt-get install curl For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command: $ yum install curl Installing bc \u00b6 For Debian and Ubuntu, use this command: $ apt-get install bc For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command: $ yum install bc Hardware \u00b6 Hardware requirements scale based on the size of your deployments. Minimum recommendations are outlined here. RAM: 1G Minimum (we recommend at least 2GB) CPU: 1 Minimum This configuration only contains the minimum requirements that can meet the operation. Disk \u00b6 Drycc performance depends on the performance of the database. To ensure optimal speed, we recommend using an SSD when possible. Disk performance will vary on ARM devices utilizing an SD card or eMMC. Domain Name \u00b6 Drycc needs a root domain name under your full control and points this domain name to the server to be installed. Suppose there is a wildcard domain pointing to the current server to install drycc, which is the name *.dryccdoman.com . We need to set the PLATFORM_DOMAIN environment variables before installation. $ export PLATFORM_DOMAIN=dryccdoman.co Of course, if it is a test environment, we can also use nip.io , an IP to domain name service. For example, your host IP is 59.46.3.190 , we will get the following domain name 59.46.3.190.nip.io $ export PLATFORM_DOMAIN=59.46.3.190.nip.io Install \u00b6 Before installation, please make sure whether your installation environment is a public network. If it is an intranet environment and there is no public IP, you need to disable the automatic certificate. $ export CERT_MANAGER_ENABLED=false Then you can use the installation script available at https://www.drycc.cc/install.sh to install drycc as a service on systemd and openrc based systems. $ curl -sfL https://www.drycc.cc/install.sh | bash - Important If you are in China, you need to use mirror acceleration: $ curl -sfL https://www.drycc.cc/install.sh | INSTALL_DRYCC_MIRROR=cn bash - Install Node \u00b6 Node can be a simple agent or a server; Server has the function of agent. Multiple servers have high availability, but the number of servers should not exceed 7 at most. There is no limit to the number of agents. First, check the cluster token of the master. $ cat /var/lib/rancher/k3s/server/node-token K1078e7213ca32bdaabb44536f14b9ce7926bb201f41c3f3edd39975c16ff4901ea::server:33bde27f-ac49-4483-b6ac-f4eec2c6dbfa We assume that the IP address of the cluster master is 192.168.6.240 , in that way. Then, Set the environment variable: $ export K3S_URL=https://192.168.6.240:6443 $ export K3S_TOKEN=\"K1078e7213ca32bdaabb44536f14b9ce7926bb201f41c3f3edd39975c16ff4901ea::server:33bde27f-ac49-4483-b6ac-f4eec2c6dbfa\" Important If you are in China, you need to use mirror acceleration: $ export INSTALL_DRYCC_MIRROR=cn Join the cluster as server: $ curl -sfL https://www.drycc.cc/install.sh | bash -s - install_k3s_server Join the cluster as agent: $ curl -sfL https://www.drycc.cc/install.sh | bash -s - install_k3s_agent Install Options \u00b6 When using this method to install drycc, the following environment variables can be used to configure the installation: ENVIRONMENT VARIABLE DESCRIPTION PLATFORM_DOMAIN Required item, specify drycc's domain name DRYCC_ADMIN_USERNAME Required item, specify drycc's admin username DRYCC_ADMIN_PASSWORD Required item, specify drycc's admin password CERT_MANAGER_ENABLED Whether to use automatic certificate. It is true by default CHANNEL By default, stable channel will be installed. You can also specify testing CONTAINERD_FILE The config.yaml file path used by containerd KUBE_API_SERVER_ADDRESS Set with the IP address of the loadbalancer that was in front of kube-apiserver, The default is the IP address of the current node KUBE_API_SERVER_PORT Set with the PORT of the loadbalancer that was in front of kube-apiserver, which is 6443 by default METALLB_CONFIG_FILE The metallb config file path, layer 2 network is used by default INSTALL_DRYCC_MIRROR Specify the accelerated mirror location. Currently, only cn is supported BUILDER_REPLICAS Number of builder replicas to deploy CONTROLLER_API_REPLICAS Number of controller api replicas to deploy CONTROLLER_CELERY_REPLICAS Number of controller celery replicas to deploy CONTROLLER_WEBHOOK_REPLICAS Number of controller webhook replicas to deploy CONTROLLER_APP_RUNTIME_CLASS RuntimeClass is a feature for selecting the container runtime configuration. CONTROLLER_APP_STORAGE_CLASS StorageClass allocated by drycc volumes ; default storageClass is used by default REDIS_REPLICAS Number of redis replicas to deploy REDIS_PERSISTENCE_SIZE The size of the persistence space allocated to redis , which is 5Gi by default REDIS_PERSISTENCE_STORAGE_CLASS StorangeClass of redis ; default storangeclass is used by default STORAGE_CSI_STATEFULSET_REPLICAS Number of storage csi controller replicas to deploy STORAGE_MAINNODE_TIPD_REPLICAS Number of storage mainode tipd replicas to deploy STORAGE_MAINNODE_TIPD_PERSISTENCE_SIZE The size of the persistence space allocated to mainnode tipd , which is 10Gi by default STORAGE_MAINNODE_TIPD_PERSISTENCE_STORAGE_CLASS StorangeClass of mainnode tipd ; default storangeclass is used by default STORAGE_MAINNODE_WEED_REPLICAS Number of storage mainode weed replicas to deploy STORAGE_MAINNODE_WEED_PERSISTENCE_SIZE The size of the persistence space allocated to mainnode weed , which is 10Gi by default STORAGE_MAINNODE_WEED_PERSISTENCE_STORAGE_CLASS StorangeClass of mainnode weed ; default storangeclass is used by default STORAGE_METANODE_TIKV_REPLICAS Number of storage metanode tikv replicas to deploy STORAGE_METANODE_TIKV_PERSISTENCE_SIZE The size of the persistence space allocated to metanode tikv , which is 10Gi by default STORAGE_METANODE_TIKV_PERSISTENCE_STORAGE_CLASS StorangeClass of mainnode tikv ; default storangeclass is used by default STORAGE_METANODE_WEED_REPLICAS Number of storage metanode weed replicas to deploy STORAGE_METANODE_WEED_PERSISTENCE_SIZE The size of the persistence space allocated to metanode weed , which is 10Gi by default STORAGE_METANODE_WEED_PERSISTENCE_STORAGE_CLASS StorangeClass of mainnode weed ; default storangeclass is used by default STORAGE_DATANODE_WEED_REPLICAS Number of storage datanode weed replicas to deploy STORAGE_DATANODE_WEED_PERSISTENCE_SIZE The size of the persistence space allocated to datanode weed , which is 20Gi by default STORAGE_DATANODE_WEED_PERSISTENCE_STORAGE_CLASS StorangeClass of datanode weed ; default storangeclass is used by default MONITOR_GRAFANA_PERSISTENCE_SIZE The size of the persistence space allocated to monitor.grafana , which is 5Gi by default MONITOR_GRAFANA_PERSISTENCE_STORAGE_CLASS StorangeClass of monitor grafana; default storangeclass is used by default LOGGER_REPLICAS Number of logger replicas to deploy RABBITMQ_REPLICAS Number of rabbitmq replicas to deploy RABBITMQ_PERSISTENCE_SIZE The size of the persistence space allocated to rabbitmq , which is 5Gi by default RABBITMQ_PERSISTENCE_STORAGE_CLASS StorangeClass of rabbitmq ; default storangeclass is used by default DATABASE_REPLICAS Number of database replicas to deploy DATABASE_PERSISTENCE_SIZE The size of the persistence space allocated to database , which is 5Gi by default DATABASE_PERSISTENCE_STORAGE_CLASS StorangeClass of database ; default storangeclass is used by default TIMESERIES_REPLICAS Number of timeseries replicas to deploy TIMESERIES_PERSISTENCE_SIZE The size of the persistence space allocated to timeseries , which is 5Gi by default TIMESERIES_PERSISTENCE_STORAGE_CLASS StorangeClass of timeseries ; default storangeclass is used by default PASSPORT_REPLICAS Number of passport replicas to deploy REGISTRY_REPLICAS Number of registry replicas to deploy HELMBROKER_REPLICAS Number of helmbroker api replicas to deploy HELMBROKER_CELERY_REPLICAS Number of helmbroker celery replicas to deploy HELMBROKER_PERSISTENCE_SIZE The size of the persistence space allocated to helmbroker , which is 5Gi by default HELMBROKER_PERSISTENCE_STORAGE_CLASS StorangeClass of helmbroker ; default storangeclass is used by default PROMETHEUS_SERVER_RETENTION Prometheus data retention period (default if not specified is 15 days) PROMETHEUS_SERVER_PERSISTENCE_SIZE The size of the persistence space allocated to prometheus-server , which is 10Gi by default PROMETHEUS_SERVER_PERSISTENCE_STORAGE_CLASS StorangeClass of prometheus-server ; default storangeclass is used by default K3S_DATA_DIR The config of k3s data dir; If not set, the default path is used ACME_SERVER ACME Server url, default use letsencrypt ACME_EAB_KEY_ID The key ID of which your external account binding is indexed by the external account ACME_EAB_KEY_SECRET The key Secret of which your external account symmetric MAC key Since the installation script will install k3s, other environment variables can refer to k3s installation environment variables . Uninstall \u00b6 If you installed drycc using an installation script, you can uninstall the entire drycc using this script. $ curl -sfL https://www.drycc.cc/uninstall.sh | bash -","title":"Install Workflow"},{"location":"quickstart/install-workflow/#install-workflow","text":"If you have a pure host, it can be a cloud server, bare metal server, virtual machine, or even your laptop. Then this chapter is very suitable for you.","title":"Install Workflow"},{"location":"quickstart/install-workflow/#operating-systems","text":"Drycc is expected to work on most modern Linux systems. Some OSS have specific requirements: (Red Hat/CentOS) Enterprise Linux, they usually use RPM package management. Ubuntu (Desktop/Server/Cloud) Linux, a very popular distribution. Debian GNU Linux, a very pure distribution of opensource software. If you want to add more Linux distribution support, please submit a issue on github or submit PR directly.","title":"Operating Systems"},{"location":"quickstart/install-workflow/#system-software","text":"Some basic software needs to be installed before installing drycc workflow.","title":"System Software"},{"location":"quickstart/install-workflow/#os-configuration","text":"K8s requires a large number of ports. If you are not sure what they are, please close the local firewall or open these ports. At the same time, because k8s you need system time, you need to ensure that the system time is correct.","title":"OS configuration"},{"location":"quickstart/install-workflow/#installing-open-iscsi","text":"The command used to install open-iscsi differs depending on the Linux distribution. We recommend using Ubuntu as the guest OS image since it contains open-iscsi already. You may need to edit the cluster security group to allow SSH access. For SUSE and openSUSE, use this command: $ zypper install open-iscsi For Debian and Ubuntu, use this command: $ apt-get install open-iscsi For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command: $ yum install iscsi-initiator-utils","title":"Installing open-iscsi"},{"location":"quickstart/install-workflow/#installing-nfsv4-client","text":"The command used to install a NFSv4 client differs depending on the Linux distribution. For Debian and Ubuntu, use this command: $ apt-get install nfs-common For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command: $ yum install nfs-utils","title":"Installing NFSv4 client"},{"location":"quickstart/install-workflow/#installing-curl","text":"For Debian and Ubuntu, use this command: $ apt-get install curl For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command: $ yum install curl","title":"Installing curl"},{"location":"quickstart/install-workflow/#installing-bc","text":"For Debian and Ubuntu, use this command: $ apt-get install bc For RHEL, CentOS, and EKS with EKS Kubernetes Worker AMI with AmazonLinux2 image, use this command: $ yum install bc","title":"Installing bc"},{"location":"quickstart/install-workflow/#hardware","text":"Hardware requirements scale based on the size of your deployments. Minimum recommendations are outlined here. RAM: 1G Minimum (we recommend at least 2GB) CPU: 1 Minimum This configuration only contains the minimum requirements that can meet the operation.","title":"Hardware"},{"location":"quickstart/install-workflow/#disk","text":"Drycc performance depends on the performance of the database. To ensure optimal speed, we recommend using an SSD when possible. Disk performance will vary on ARM devices utilizing an SD card or eMMC.","title":"Disk"},{"location":"quickstart/install-workflow/#domain-name","text":"Drycc needs a root domain name under your full control and points this domain name to the server to be installed. Suppose there is a wildcard domain pointing to the current server to install drycc, which is the name *.dryccdoman.com . We need to set the PLATFORM_DOMAIN environment variables before installation. $ export PLATFORM_DOMAIN=dryccdoman.co Of course, if it is a test environment, we can also use nip.io , an IP to domain name service. For example, your host IP is 59.46.3.190 , we will get the following domain name 59.46.3.190.nip.io $ export PLATFORM_DOMAIN=59.46.3.190.nip.io","title":"Domain Name"},{"location":"quickstart/install-workflow/#install","text":"Before installation, please make sure whether your installation environment is a public network. If it is an intranet environment and there is no public IP, you need to disable the automatic certificate. $ export CERT_MANAGER_ENABLED=false Then you can use the installation script available at https://www.drycc.cc/install.sh to install drycc as a service on systemd and openrc based systems. $ curl -sfL https://www.drycc.cc/install.sh | bash - Important If you are in China, you need to use mirror acceleration: $ curl -sfL https://www.drycc.cc/install.sh | INSTALL_DRYCC_MIRROR=cn bash -","title":"Install"},{"location":"quickstart/install-workflow/#install-node","text":"Node can be a simple agent or a server; Server has the function of agent. Multiple servers have high availability, but the number of servers should not exceed 7 at most. There is no limit to the number of agents. First, check the cluster token of the master. $ cat /var/lib/rancher/k3s/server/node-token K1078e7213ca32bdaabb44536f14b9ce7926bb201f41c3f3edd39975c16ff4901ea::server:33bde27f-ac49-4483-b6ac-f4eec2c6dbfa We assume that the IP address of the cluster master is 192.168.6.240 , in that way. Then, Set the environment variable: $ export K3S_URL=https://192.168.6.240:6443 $ export K3S_TOKEN=\"K1078e7213ca32bdaabb44536f14b9ce7926bb201f41c3f3edd39975c16ff4901ea::server:33bde27f-ac49-4483-b6ac-f4eec2c6dbfa\" Important If you are in China, you need to use mirror acceleration: $ export INSTALL_DRYCC_MIRROR=cn Join the cluster as server: $ curl -sfL https://www.drycc.cc/install.sh | bash -s - install_k3s_server Join the cluster as agent: $ curl -sfL https://www.drycc.cc/install.sh | bash -s - install_k3s_agent","title":"Install Node"},{"location":"quickstart/install-workflow/#install-options","text":"When using this method to install drycc, the following environment variables can be used to configure the installation: ENVIRONMENT VARIABLE DESCRIPTION PLATFORM_DOMAIN Required item, specify drycc's domain name DRYCC_ADMIN_USERNAME Required item, specify drycc's admin username DRYCC_ADMIN_PASSWORD Required item, specify drycc's admin password CERT_MANAGER_ENABLED Whether to use automatic certificate. It is true by default CHANNEL By default, stable channel will be installed. You can also specify testing CONTAINERD_FILE The config.yaml file path used by containerd KUBE_API_SERVER_ADDRESS Set with the IP address of the loadbalancer that was in front of kube-apiserver, The default is the IP address of the current node KUBE_API_SERVER_PORT Set with the PORT of the loadbalancer that was in front of kube-apiserver, which is 6443 by default METALLB_CONFIG_FILE The metallb config file path, layer 2 network is used by default INSTALL_DRYCC_MIRROR Specify the accelerated mirror location. Currently, only cn is supported BUILDER_REPLICAS Number of builder replicas to deploy CONTROLLER_API_REPLICAS Number of controller api replicas to deploy CONTROLLER_CELERY_REPLICAS Number of controller celery replicas to deploy CONTROLLER_WEBHOOK_REPLICAS Number of controller webhook replicas to deploy CONTROLLER_APP_RUNTIME_CLASS RuntimeClass is a feature for selecting the container runtime configuration. CONTROLLER_APP_STORAGE_CLASS StorageClass allocated by drycc volumes ; default storageClass is used by default REDIS_REPLICAS Number of redis replicas to deploy REDIS_PERSISTENCE_SIZE The size of the persistence space allocated to redis , which is 5Gi by default REDIS_PERSISTENCE_STORAGE_CLASS StorangeClass of redis ; default storangeclass is used by default STORAGE_CSI_STATEFULSET_REPLICAS Number of storage csi controller replicas to deploy STORAGE_MAINNODE_TIPD_REPLICAS Number of storage mainode tipd replicas to deploy STORAGE_MAINNODE_TIPD_PERSISTENCE_SIZE The size of the persistence space allocated to mainnode tipd , which is 10Gi by default STORAGE_MAINNODE_TIPD_PERSISTENCE_STORAGE_CLASS StorangeClass of mainnode tipd ; default storangeclass is used by default STORAGE_MAINNODE_WEED_REPLICAS Number of storage mainode weed replicas to deploy STORAGE_MAINNODE_WEED_PERSISTENCE_SIZE The size of the persistence space allocated to mainnode weed , which is 10Gi by default STORAGE_MAINNODE_WEED_PERSISTENCE_STORAGE_CLASS StorangeClass of mainnode weed ; default storangeclass is used by default STORAGE_METANODE_TIKV_REPLICAS Number of storage metanode tikv replicas to deploy STORAGE_METANODE_TIKV_PERSISTENCE_SIZE The size of the persistence space allocated to metanode tikv , which is 10Gi by default STORAGE_METANODE_TIKV_PERSISTENCE_STORAGE_CLASS StorangeClass of mainnode tikv ; default storangeclass is used by default STORAGE_METANODE_WEED_REPLICAS Number of storage metanode weed replicas to deploy STORAGE_METANODE_WEED_PERSISTENCE_SIZE The size of the persistence space allocated to metanode weed , which is 10Gi by default STORAGE_METANODE_WEED_PERSISTENCE_STORAGE_CLASS StorangeClass of mainnode weed ; default storangeclass is used by default STORAGE_DATANODE_WEED_REPLICAS Number of storage datanode weed replicas to deploy STORAGE_DATANODE_WEED_PERSISTENCE_SIZE The size of the persistence space allocated to datanode weed , which is 20Gi by default STORAGE_DATANODE_WEED_PERSISTENCE_STORAGE_CLASS StorangeClass of datanode weed ; default storangeclass is used by default MONITOR_GRAFANA_PERSISTENCE_SIZE The size of the persistence space allocated to monitor.grafana , which is 5Gi by default MONITOR_GRAFANA_PERSISTENCE_STORAGE_CLASS StorangeClass of monitor grafana; default storangeclass is used by default LOGGER_REPLICAS Number of logger replicas to deploy RABBITMQ_REPLICAS Number of rabbitmq replicas to deploy RABBITMQ_PERSISTENCE_SIZE The size of the persistence space allocated to rabbitmq , which is 5Gi by default RABBITMQ_PERSISTENCE_STORAGE_CLASS StorangeClass of rabbitmq ; default storangeclass is used by default DATABASE_REPLICAS Number of database replicas to deploy DATABASE_PERSISTENCE_SIZE The size of the persistence space allocated to database , which is 5Gi by default DATABASE_PERSISTENCE_STORAGE_CLASS StorangeClass of database ; default storangeclass is used by default TIMESERIES_REPLICAS Number of timeseries replicas to deploy TIMESERIES_PERSISTENCE_SIZE The size of the persistence space allocated to timeseries , which is 5Gi by default TIMESERIES_PERSISTENCE_STORAGE_CLASS StorangeClass of timeseries ; default storangeclass is used by default PASSPORT_REPLICAS Number of passport replicas to deploy REGISTRY_REPLICAS Number of registry replicas to deploy HELMBROKER_REPLICAS Number of helmbroker api replicas to deploy HELMBROKER_CELERY_REPLICAS Number of helmbroker celery replicas to deploy HELMBROKER_PERSISTENCE_SIZE The size of the persistence space allocated to helmbroker , which is 5Gi by default HELMBROKER_PERSISTENCE_STORAGE_CLASS StorangeClass of helmbroker ; default storangeclass is used by default PROMETHEUS_SERVER_RETENTION Prometheus data retention period (default if not specified is 15 days) PROMETHEUS_SERVER_PERSISTENCE_SIZE The size of the persistence space allocated to prometheus-server , which is 10Gi by default PROMETHEUS_SERVER_PERSISTENCE_STORAGE_CLASS StorangeClass of prometheus-server ; default storangeclass is used by default K3S_DATA_DIR The config of k3s data dir; If not set, the default path is used ACME_SERVER ACME Server url, default use letsencrypt ACME_EAB_KEY_ID The key ID of which your external account binding is indexed by the external account ACME_EAB_KEY_SECRET The key Secret of which your external account symmetric MAC key Since the installation script will install k3s, other environment variables can refer to k3s installation environment variables .","title":"Install Options"},{"location":"quickstart/install-workflow/#uninstall","text":"If you installed drycc using an installation script, you can uninstall the entire drycc using this script. $ curl -sfL https://www.drycc.cc/uninstall.sh | bash -","title":"Uninstall"},{"location":"reference-guide/creating-a-self-signed-ssl-certificate/","text":"Creating a Self-Signed SSL Certificate \u00b6 When using the app ssl feature for non-production applications or when installing SSL for the platform , you can avoid the costs associated with the SSL certificate by using a self-signed SSL certificate. Though the certificate implements full encryption, visitors to your site will see a browser warning indicating that the certificate should not be trusted. Prerequisites \u00b6 The openssl library is required to generate your own certificate. Run the following command in your local environment to see if you already have openssl installed. $ which openssl /usr/bin/openssl If the which command does not return a path then you will need to install openssl yourself: If you have... Install with... Mac OS X Homebrew: brew install openssl Windows complete package .exe installed Ubuntu Linux apt-get install openssl Generate Private Key and Certificate Signing Request \u00b6 A private key and certificate signing request are required to create an SSL certificate. These can be generated with a few simple commands. When the openssl req command asks for a \u201cchallenge password\u201d, just press return, leaving the password empty. $ openssl genrsa -des3 -passout pass:x -out server.pass.key 2048 ... $ openssl rsa -passin pass:x -in server.pass.key -out server.key writing RSA key $ rm server.pass.key $ openssl req -new -key server.key -out server.csr ... Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:California ... A challenge password []: ... Generate SSL Certificate \u00b6 The self-signed SSL certificate is generated from the server.key private key and server.csr files. $ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt The server.crt file is your site certificate suitable for use with Drycc's SSL endpoint along with the server.key private key.","title":"Creating a Self-Signed SSL Certificate"},{"location":"reference-guide/creating-a-self-signed-ssl-certificate/#creating-a-self-signed-ssl-certificate","text":"When using the app ssl feature for non-production applications or when installing SSL for the platform , you can avoid the costs associated with the SSL certificate by using a self-signed SSL certificate. Though the certificate implements full encryption, visitors to your site will see a browser warning indicating that the certificate should not be trusted.","title":"Creating a Self-Signed SSL Certificate"},{"location":"reference-guide/creating-a-self-signed-ssl-certificate/#prerequisites","text":"The openssl library is required to generate your own certificate. Run the following command in your local environment to see if you already have openssl installed. $ which openssl /usr/bin/openssl If the which command does not return a path then you will need to install openssl yourself: If you have... Install with... Mac OS X Homebrew: brew install openssl Windows complete package .exe installed Ubuntu Linux apt-get install openssl","title":"Prerequisites"},{"location":"reference-guide/creating-a-self-signed-ssl-certificate/#generate-private-key-and-certificate-signing-request","text":"A private key and certificate signing request are required to create an SSL certificate. These can be generated with a few simple commands. When the openssl req command asks for a \u201cchallenge password\u201d, just press return, leaving the password empty. $ openssl genrsa -des3 -passout pass:x -out server.pass.key 2048 ... $ openssl rsa -passin pass:x -in server.pass.key -out server.key writing RSA key $ rm server.pass.key $ openssl req -new -key server.key -out server.csr ... Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:California ... A challenge password []: ...","title":"Generate Private Key and Certificate Signing Request"},{"location":"reference-guide/creating-a-self-signed-ssl-certificate/#generate-ssl-certificate","text":"The self-signed SSL certificate is generated from the server.key private key and server.csr files. $ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt The server.crt file is your site certificate suitable for use with Drycc's SSL endpoint along with the server.key private key.","title":"Generate SSL Certificate"},{"location":"reference-guide/terms/","text":"Terms \u00b6 Application \u00b6 An application services requests and background jobs for a deployed git repository. Each application includes a set of Containers used to run isolated processes, and a Release that defines the current Build and Config deployed by containers. Build \u00b6 Drycc builds are created automatically on the controller when a developer uses git push drycc master . When a new build is created, a new Release is created automatically. Config \u00b6 Config refers to a set of environment variables used by Containers in as Application. When Config is changed, a new Release is created automatically. Container \u00b6 Drycc containers are instances of containers used to run Applications. Containers perform the actual work of an Application by servicing requests or by running background tasks as part of the cluster. Ephemeral Filesystem \u00b6 Each container gets its own ephemeral filesystem, with a fresh copy of the most recently deployed code. During the container\u2019s lifetime, its running processes can use the filesystem as a temporary scratchpad, but no files that are written are visible to processes in any other container. Any files written to the ephemeral filesystem will be discarded the moment the container is either stopped or restarted. Container States \u00b6 There are several states that a container can be in at any time. The states are: initialized - the state of the container before it is created created - the container is built and ready for operation up - the container is running down - the container crashed or is stopped destroyed - the container has been destroyed Controller \u00b6 The controller is the \"brain\" of the Drycc platform. A controller manages Applications and their lifecycle. The controller is in charge of: Processing client API calls Managing containers that perform work for applications Managing proxies that route traffic to containers Managing users, keys and other base configuration The Controller stack includes: Django API Server for handling API calls Key \u00b6 Drycc keys are SSH Keys used during the git push process. Each user can use the client to manage a list of keys on the Controller. Release \u00b6 A Drycc release is a combination of a Build with a Config. Each Application is associated with one release at a time. Drycc releases are numbered and new releases always increment by one (e.g. v1, v2, v3). Containers that host an application use these release versions to pull the correct code and configuration. Scheduler \u00b6 The Scheduler is responsible for creating, starting, stopping, and destroying Containers. For example, a command such as drycc scale cmd=10 tells the Scheduler to run ten Containers from the Container image for your Application. The Scheduler must decide which machines are eligible to run these container jobs. Scheduler backends vary in the details of their job allocation policies and whether or not they are resource-aware, among other features. The Drycc scheduler client is implemented in the Controller component. Service \u00b6 A Kubernetes Service is an abstraction which defines a logical set of Pods and a policy by which to access them. In Workflow, a Service is used to load-balance an application's Containers internally through a virtual IP address.","title":"Terms"},{"location":"reference-guide/terms/#terms","text":"","title":"Terms"},{"location":"reference-guide/terms/#application","text":"An application services requests and background jobs for a deployed git repository. Each application includes a set of Containers used to run isolated processes, and a Release that defines the current Build and Config deployed by containers.","title":"Application"},{"location":"reference-guide/terms/#build","text":"Drycc builds are created automatically on the controller when a developer uses git push drycc master . When a new build is created, a new Release is created automatically.","title":"Build"},{"location":"reference-guide/terms/#config","text":"Config refers to a set of environment variables used by Containers in as Application. When Config is changed, a new Release is created automatically.","title":"Config"},{"location":"reference-guide/terms/#container","text":"Drycc containers are instances of containers used to run Applications. Containers perform the actual work of an Application by servicing requests or by running background tasks as part of the cluster.","title":"Container"},{"location":"reference-guide/terms/#ephemeral-filesystem","text":"Each container gets its own ephemeral filesystem, with a fresh copy of the most recently deployed code. During the container\u2019s lifetime, its running processes can use the filesystem as a temporary scratchpad, but no files that are written are visible to processes in any other container. Any files written to the ephemeral filesystem will be discarded the moment the container is either stopped or restarted.","title":"Ephemeral Filesystem"},{"location":"reference-guide/terms/#container-states","text":"There are several states that a container can be in at any time. The states are: initialized - the state of the container before it is created created - the container is built and ready for operation up - the container is running down - the container crashed or is stopped destroyed - the container has been destroyed","title":"Container States"},{"location":"reference-guide/terms/#controller","text":"The controller is the \"brain\" of the Drycc platform. A controller manages Applications and their lifecycle. The controller is in charge of: Processing client API calls Managing containers that perform work for applications Managing proxies that route traffic to containers Managing users, keys and other base configuration The Controller stack includes: Django API Server for handling API calls","title":"Controller"},{"location":"reference-guide/terms/#key","text":"Drycc keys are SSH Keys used during the git push process. Each user can use the client to manage a list of keys on the Controller.","title":"Key"},{"location":"reference-guide/terms/#release","text":"A Drycc release is a combination of a Build with a Config. Each Application is associated with one release at a time. Drycc releases are numbered and new releases always increment by one (e.g. v1, v2, v3). Containers that host an application use these release versions to pull the correct code and configuration.","title":"Release"},{"location":"reference-guide/terms/#scheduler","text":"The Scheduler is responsible for creating, starting, stopping, and destroying Containers. For example, a command such as drycc scale cmd=10 tells the Scheduler to run ten Containers from the Container image for your Application. The Scheduler must decide which machines are eligible to run these container jobs. Scheduler backends vary in the details of their job allocation policies and whether or not they are resource-aware, among other features. The Drycc scheduler client is implemented in the Controller component.","title":"Scheduler"},{"location":"reference-guide/terms/#service","text":"A Kubernetes Service is an abstraction which defines a logical set of Pods and a policy by which to access them. In Workflow, a Service is used to load-balance an application's Containers internally through a virtual IP address.","title":"Service"},{"location":"reference-guide/controller-api/v2.0/","text":"Controller API v2.0 \u00b6 This is the v2.0 REST API for the Controller. What's New \u00b6 New! format of POST /v2/apps//run has changed. Authentication \u00b6 Register a New User \u00b6 Example Request: POST /v2/auth/register/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json { \"username\": \"test\", \"password\": \"opensesame\", \"email\": \"test@example.com\" } Optional Parameters: { \"first_name\": \"test\", \"last_name\": \"testerson\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } Log in \u00b6 Example Request: POST /v2/auth/login/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json {\"username\": \"test\", \"password\": \"opensesame\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"token\": \"abc123\"} Cancel Account \u00b6 Example Request: DELETE /v2/auth/cancel/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Regenerate Token \u00b6 note This command could require administrative privileges Example Request: POST /v2/auth/tokens/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional Parameters: { \"username\" : \"test\" \"all\" : \"true\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"token\": \"abc123\"} Change Password \u00b6 Example Request: POST /v2/auth/passwd/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"password\": \"foo\", \"new_password\": \"bar\" } Optional parameters: {\"username\": \"testuser\"} note Using the username parameter requires administrative privileges and makes the password parameter optional. Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Applications \u00b6 List all Applications \u00b6 Example Request: GET /v2/apps HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] } Create an Application \u00b6 Example Request: POST /v2/apps/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 Optional parameters: {\"id\": \"example-go\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Destroy an Application \u00b6 Example Request: DELETE /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 List Application Details \u00b6 Example Request: GET /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Update Application Details \u00b6 Example Request: POST /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional parameters: { \"owner\": \"test\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 1.8.0 Content-Type: application/json Retrieve Application Logs \u00b6 Example Request: GET /v2/apps/example-go/logs/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional URL Query Parameters: ?log_lines= Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: text/plain \"16:51:14 drycc[api]: test created initial release\\n\" Run one-off Commands \u00b6 POST /v2/apps/example-go/run/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"command\": \"echo hi\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"exit_code\": 0, \"output\": \"hi\\n\"} Certificates \u00b6 List all Certificates \u00b6 Example Request: GET /v2/certs HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } ] } Get Certificate Details \u00b6 Example Request: GET /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } Create Certificate \u00b6 Example Request: POST /v2/certs/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 { \"name\": \"foo\" \"certificate\": \"-----BEGIN CERTIFICATE-----\", \"key\": \"-----BEGIN RSA PRIVATE KEY-----\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } Destroy a Certificate \u00b6 Example Request: DELETE /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Attach a Domain to a Certificate \u00b6 Example Request: POST /v2/certs/foo/domain/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"domain\": \"test.com\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Remove a Domain from a Certificate \u00b6 Example Request: DELETE /v2/certs/foo/domain/test.com/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Pods \u00b6 List all Pods \u00b6 Example Request: GET /v2/apps/example-go/pods/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] } List all Pods by Type \u00b6 Example Request: GET /v2/apps/example-go/pods/web/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] } Restart All Pods \u00b6 Example Request: POST /v2/apps/example-go/pods/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ] Restart Pods by Type \u00b6 Example Request: POST /v2/apps/example-go/pods/web/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ] Restart Pods by Type and Name \u00b6 Example Request: POST /v2/apps/example-go/pods/go-v2-web-atots/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ] Scale Pods \u00b6 Example Request: POST /v2/apps/example-go/scale/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"web\": 3} Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Configuration \u00b6 List Application Configuration \u00b6 Example Request: GET /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Create new Config \u00b6 Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": \"world\", \"PLATFORM\": \"drycc\"}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json X-Drycc-Release: 3 { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v3\", \"HELLO\": \"world\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Unset Config Variable \u00b6 Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": null}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json X-Drycc-Release: 4 { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v4\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Domains \u00b6 List Application Domains \u00b6 Example Request: GET /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" } ] } Add Domain \u00b6 Example Request: POST /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {'domain': 'example.example.com'} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" } Remove Domain \u00b6 Example Request: DELETE /v2/apps/example-go/domains/example.example.com HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Builds \u00b6 List Application Builds \u00b6 Example Request: GET /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"FROM drycc/slugrunner RUN mkdir -p /app WORKDIR /app ENTRYPOINT [\\\"/runner/init\\\"] ADD slug.tgz /app ENV GIT_SHA 060da68f654e75fac06dbedd1995d5f8ad9084db\", \"image\": \"example-go\", \"owner\": \"test\", \"procfile\": { \"web\": \"example-go\" }, \"sha\": \"060da68f\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] } Create Application Build \u00b6 Example Request: POST /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"image\": \"drycc/example-go:latest\"} Optional Parameters: { \"procfile\": { \"web\": \"./cmd\" } } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json X-Drycc-Release: 4 { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"\", \"image\": \"drycc/example-go:latest\", \"owner\": \"test\", \"procfile\": {}, \"sha\": \"\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Releases \u00b6 List Application Releases \u00b6 Example Request: GET /v2/apps/example-go/releases/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 3, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"build\": \"202d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"ed637ceb-5d32-44bd-9406-d326a777a513\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test changed nothing\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 3 }, { \"app\": \"example-go\", \"build\": \"202d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test deployed 060da68\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 2 }, { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 } ] } List Release Details \u00b6 Example Request: GET /v2/apps/example-go/releases/v2/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 } Rollback Release \u00b6 Example Request: POST /v2/apps/example-go/releases/rollback/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"version\": 1} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"version\": 5} Keys \u00b6 List Keys \u00b6 Example Request: GET /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"test@example.com\", \"owner\": \"test\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] } Add Key to User \u00b6 Example Request: POST /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"id\": \"example\", \"public\": \"ssh-rsa <...>\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example\", \"owner\": \"example\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Remove Key from User \u00b6 Example Request: DELETE /v2/keys/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Permissions \u00b6 List Application Permissions \u00b6 note This does not include the app owner. Example Request: GET /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"users\": [ \"test\", \"foo\" ] } Create Application Permission \u00b6 Example Request: POST /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Remove Application Permission \u00b6 Example Request: DELETE /v2/apps/example-go/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 List Administrators \u00b6 Example Request: GET /v2/admin/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 2, \"next\": null \"previous\": null, \"results\": [ { \"username\": \"test\", \"is_superuser\": true }, { \"username\": \"foo\", \"is_superuser\": true } ] } Grant User Administrative Privileges \u00b6 note This command requires administrative privileges Example Request: POST /v2/admin/perms HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Remove User's Administrative Privileges \u00b6 note This command requires administrative privileges Example Request: DELETE /v2/admin/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Users \u00b6 List all users \u00b6 note This command requires administrative privileges Example Request: GET /v2/users HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } ] }","title":"Controller API v2.0"},{"location":"reference-guide/controller-api/v2.0/#controller-api-v20","text":"This is the v2.0 REST API for the Controller.","title":"Controller API v2.0"},{"location":"reference-guide/controller-api/v2.0/#whats-new","text":"New! format of POST /v2/apps//run has changed.","title":"What's New"},{"location":"reference-guide/controller-api/v2.0/#authentication","text":"","title":"Authentication"},{"location":"reference-guide/controller-api/v2.0/#register-a-new-user","text":"Example Request: POST /v2/auth/register/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json { \"username\": \"test\", \"password\": \"opensesame\", \"email\": \"test@example.com\" } Optional Parameters: { \"first_name\": \"test\", \"last_name\": \"testerson\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] }","title":"Register a New User"},{"location":"reference-guide/controller-api/v2.0/#log-in","text":"Example Request: POST /v2/auth/login/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json {\"username\": \"test\", \"password\": \"opensesame\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"token\": \"abc123\"}","title":"Log in"},{"location":"reference-guide/controller-api/v2.0/#cancel-account","text":"Example Request: DELETE /v2/auth/cancel/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Cancel Account"},{"location":"reference-guide/controller-api/v2.0/#regenerate-token","text":"note This command could require administrative privileges Example Request: POST /v2/auth/tokens/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional Parameters: { \"username\" : \"test\" \"all\" : \"true\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"token\": \"abc123\"}","title":"Regenerate Token"},{"location":"reference-guide/controller-api/v2.0/#change-password","text":"Example Request: POST /v2/auth/passwd/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"password\": \"foo\", \"new_password\": \"bar\" } Optional parameters: {\"username\": \"testuser\"} note Using the username parameter requires administrative privileges and makes the password parameter optional. Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Change Password"},{"location":"reference-guide/controller-api/v2.0/#applications","text":"","title":"Applications"},{"location":"reference-guide/controller-api/v2.0/#list-all-applications","text":"Example Request: GET /v2/apps HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] }","title":"List all Applications"},{"location":"reference-guide/controller-api/v2.0/#create-an-application","text":"Example Request: POST /v2/apps/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 Optional parameters: {\"id\": \"example-go\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Create an Application"},{"location":"reference-guide/controller-api/v2.0/#destroy-an-application","text":"Example Request: DELETE /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Destroy an Application"},{"location":"reference-guide/controller-api/v2.0/#list-application-details","text":"Example Request: GET /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"List Application Details"},{"location":"reference-guide/controller-api/v2.0/#update-application-details","text":"Example Request: POST /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional parameters: { \"owner\": \"test\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 1.8.0 Content-Type: application/json","title":"Update Application Details"},{"location":"reference-guide/controller-api/v2.0/#retrieve-application-logs","text":"Example Request: GET /v2/apps/example-go/logs/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional URL Query Parameters: ?log_lines= Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: text/plain \"16:51:14 drycc[api]: test created initial release\\n\"","title":"Retrieve Application Logs"},{"location":"reference-guide/controller-api/v2.0/#run-one-off-commands","text":"POST /v2/apps/example-go/run/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"command\": \"echo hi\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"exit_code\": 0, \"output\": \"hi\\n\"}","title":"Run one-off Commands"},{"location":"reference-guide/controller-api/v2.0/#certificates","text":"","title":"Certificates"},{"location":"reference-guide/controller-api/v2.0/#list-all-certificates","text":"Example Request: GET /v2/certs HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } ] }","title":"List all Certificates"},{"location":"reference-guide/controller-api/v2.0/#get-certificate-details","text":"Example Request: GET /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" }","title":"Get Certificate Details"},{"location":"reference-guide/controller-api/v2.0/#create-certificate","text":"Example Request: POST /v2/certs/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 { \"name\": \"foo\" \"certificate\": \"-----BEGIN CERTIFICATE-----\", \"key\": \"-----BEGIN RSA PRIVATE KEY-----\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" }","title":"Create Certificate"},{"location":"reference-guide/controller-api/v2.0/#destroy-a-certificate","text":"Example Request: DELETE /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Destroy a Certificate"},{"location":"reference-guide/controller-api/v2.0/#attach-a-domain-to-a-certificate","text":"Example Request: POST /v2/certs/foo/domain/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"domain\": \"test.com\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Attach a Domain to a Certificate"},{"location":"reference-guide/controller-api/v2.0/#remove-a-domain-from-a-certificate","text":"Example Request: DELETE /v2/certs/foo/domain/test.com/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Remove a Domain from a Certificate"},{"location":"reference-guide/controller-api/v2.0/#pods","text":"","title":"Pods"},{"location":"reference-guide/controller-api/v2.0/#list-all-pods","text":"Example Request: GET /v2/apps/example-go/pods/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] }","title":"List all Pods"},{"location":"reference-guide/controller-api/v2.0/#list-all-pods-by-type","text":"Example Request: GET /v2/apps/example-go/pods/web/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] }","title":"List all Pods by Type"},{"location":"reference-guide/controller-api/v2.0/#restart-all-pods","text":"Example Request: POST /v2/apps/example-go/pods/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ]","title":"Restart All Pods"},{"location":"reference-guide/controller-api/v2.0/#restart-pods-by-type","text":"Example Request: POST /v2/apps/example-go/pods/web/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ]","title":"Restart Pods by Type"},{"location":"reference-guide/controller-api/v2.0/#restart-pods-by-type-and-name","text":"Example Request: POST /v2/apps/example-go/pods/go-v2-web-atots/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ]","title":"Restart Pods by Type and Name"},{"location":"reference-guide/controller-api/v2.0/#scale-pods","text":"Example Request: POST /v2/apps/example-go/scale/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"web\": 3} Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Scale Pods"},{"location":"reference-guide/controller-api/v2.0/#configuration","text":"","title":"Configuration"},{"location":"reference-guide/controller-api/v2.0/#list-application-configuration","text":"Example Request: GET /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"List Application Configuration"},{"location":"reference-guide/controller-api/v2.0/#create-new-config","text":"Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": \"world\", \"PLATFORM\": \"drycc\"}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json X-Drycc-Release: 3 { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v3\", \"HELLO\": \"world\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Create new Config"},{"location":"reference-guide/controller-api/v2.0/#unset-config-variable","text":"Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": null}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json X-Drycc-Release: 4 { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v4\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Unset Config Variable"},{"location":"reference-guide/controller-api/v2.0/#domains","text":"","title":"Domains"},{"location":"reference-guide/controller-api/v2.0/#list-application-domains","text":"Example Request: GET /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" } ] }","title":"List Application Domains"},{"location":"reference-guide/controller-api/v2.0/#add-domain","text":"Example Request: POST /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {'domain': 'example.example.com'} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" }","title":"Add Domain"},{"location":"reference-guide/controller-api/v2.0/#remove-domain","text":"Example Request: DELETE /v2/apps/example-go/domains/example.example.com HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Remove Domain"},{"location":"reference-guide/controller-api/v2.0/#builds","text":"","title":"Builds"},{"location":"reference-guide/controller-api/v2.0/#list-application-builds","text":"Example Request: GET /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"FROM drycc/slugrunner RUN mkdir -p /app WORKDIR /app ENTRYPOINT [\\\"/runner/init\\\"] ADD slug.tgz /app ENV GIT_SHA 060da68f654e75fac06dbedd1995d5f8ad9084db\", \"image\": \"example-go\", \"owner\": \"test\", \"procfile\": { \"web\": \"example-go\" }, \"sha\": \"060da68f\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] }","title":"List Application Builds"},{"location":"reference-guide/controller-api/v2.0/#create-application-build","text":"Example Request: POST /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"image\": \"drycc/example-go:latest\"} Optional Parameters: { \"procfile\": { \"web\": \"./cmd\" } } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json X-Drycc-Release: 4 { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"\", \"image\": \"drycc/example-go:latest\", \"owner\": \"test\", \"procfile\": {}, \"sha\": \"\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Create Application Build"},{"location":"reference-guide/controller-api/v2.0/#releases","text":"","title":"Releases"},{"location":"reference-guide/controller-api/v2.0/#list-application-releases","text":"Example Request: GET /v2/apps/example-go/releases/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 3, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"build\": \"202d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"ed637ceb-5d32-44bd-9406-d326a777a513\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test changed nothing\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 3 }, { \"app\": \"example-go\", \"build\": \"202d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test deployed 060da68\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 2 }, { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 } ] }","title":"List Application Releases"},{"location":"reference-guide/controller-api/v2.0/#list-release-details","text":"Example Request: GET /v2/apps/example-go/releases/v2/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 }","title":"List Release Details"},{"location":"reference-guide/controller-api/v2.0/#rollback-release","text":"Example Request: POST /v2/apps/example-go/releases/rollback/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"version\": 1} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"version\": 5}","title":"Rollback Release"},{"location":"reference-guide/controller-api/v2.0/#keys","text":"","title":"Keys"},{"location":"reference-guide/controller-api/v2.0/#list-keys","text":"Example Request: GET /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"test@example.com\", \"owner\": \"test\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] }","title":"List Keys"},{"location":"reference-guide/controller-api/v2.0/#add-key-to-user","text":"Example Request: POST /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"id\": \"example\", \"public\": \"ssh-rsa <...>\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example\", \"owner\": \"example\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Add Key to User"},{"location":"reference-guide/controller-api/v2.0/#remove-key-from-user","text":"Example Request: DELETE /v2/keys/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Remove Key from User"},{"location":"reference-guide/controller-api/v2.0/#permissions","text":"","title":"Permissions"},{"location":"reference-guide/controller-api/v2.0/#list-application-permissions","text":"note This does not include the app owner. Example Request: GET /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"users\": [ \"test\", \"foo\" ] }","title":"List Application Permissions"},{"location":"reference-guide/controller-api/v2.0/#create-application-permission","text":"Example Request: POST /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Create Application Permission"},{"location":"reference-guide/controller-api/v2.0/#remove-application-permission","text":"Example Request: DELETE /v2/apps/example-go/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Remove Application Permission"},{"location":"reference-guide/controller-api/v2.0/#list-administrators","text":"Example Request: GET /v2/admin/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 2, \"next\": null \"previous\": null, \"results\": [ { \"username\": \"test\", \"is_superuser\": true }, { \"username\": \"foo\", \"is_superuser\": true } ] }","title":"List Administrators"},{"location":"reference-guide/controller-api/v2.0/#grant-user-administrative-privileges","text":"note This command requires administrative privileges Example Request: POST /v2/admin/perms HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Grant User Administrative Privileges"},{"location":"reference-guide/controller-api/v2.0/#remove-users-administrative-privileges","text":"note This command requires administrative privileges Example Request: DELETE /v2/admin/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Remove User's Administrative Privileges"},{"location":"reference-guide/controller-api/v2.0/#users","text":"","title":"Users"},{"location":"reference-guide/controller-api/v2.0/#list-all-users","text":"note This command requires administrative privileges Example Request: GET /v2/users HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.0 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } ] }","title":"List all users"},{"location":"reference-guide/controller-api/v2.1/","text":"Controller API v2.1 \u00b6 This is the v2.1 REST API for the Controller. What's New \u00b6 New! healthcheck field in configuration, deprecates the HEALTHCHECK_* environment variables. New! Unsetting a configuration variable that does not exist will return a 422. New! Creating an identical sequential release returns a 409 rather than create a no-op release. Authentication \u00b6 Register a New User \u00b6 Example Request: POST /v2/auth/register/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json { \"username\": \"test\", \"password\": \"opensesame\", \"email\": \"test@example.com\" } Optional Parameters: { \"first_name\": \"test\", \"last_name\": \"testerson\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } Log in \u00b6 Example Request: POST /v2/auth/login/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json {\"username\": \"test\", \"password\": \"opensesame\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"token\": \"abc123\"} Cancel Account \u00b6 Example Request: DELETE /v2/auth/cancel/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Regenerate Token \u00b6 note This command could require administrative privileges Example Request: POST /v2/auth/tokens/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional Parameters: { \"username\" : \"test\" \"all\" : \"true\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"token\": \"abc123\"} Change Password \u00b6 Example Request: POST /v2/auth/passwd/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"password\": \"foo\", \"new_password\": \"bar\" } Optional parameters: {\"username\": \"testuser\"} note Using the username parameter requires administrative privileges and makes the password parameter optional. Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Applications \u00b6 List all Applications \u00b6 Example Request: GET /v2/apps HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] } Create an Application \u00b6 Example Request: POST /v2/apps/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 Optional parameters: {\"id\": \"example-go\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Destroy an Application \u00b6 Example Request: DELETE /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 List Application Details \u00b6 Example Request: GET /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Update Application Details \u00b6 Example Request: POST /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional parameters: { \"owner\": \"test\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 1.8.0 Content-Type: application/json Retrieve Application Logs \u00b6 Example Request: GET /v2/apps/example-go/logs/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional URL Query Parameters: ?log_lines= Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: text/plain \"16:51:14 drycc[api]: test created initial release\\n\" Run one-off Commands \u00b6 POST /v2/apps/example-go/run/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"command\": \"echo hi\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"exit_code\": 0, \"output\": \"hi\\n\"} Certificates \u00b6 List all Certificates \u00b6 Example Request: GET /v2/certs HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } ] } Get Certificate Details \u00b6 Example Request: GET /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } Create Certificate \u00b6 Example Request: POST /v2/certs/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 { \"name\": \"foo\" \"certificate\": \"-----BEGIN CERTIFICATE-----\", \"key\": \"-----BEGIN RSA PRIVATE KEY-----\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } Destroy a Certificate \u00b6 Example Request: DELETE /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Attach a Domain to a Certificate \u00b6 Example Request: POST /v2/certs/foo/domain/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"domain\": \"test.com\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Remove a Domain from a Certificate \u00b6 Example Request: DELETE /v2/certs/foo/domain/test.com/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Pods \u00b6 List all Pods \u00b6 Example Request: GET /v2/apps/example-go/pods/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] } List all Pods by Type \u00b6 Example Request: GET /v2/apps/example-go/pods/web/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] } Restart All Pods \u00b6 Example Request: POST /v2/apps/example-go/pods/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ] Restart Pods by Type \u00b6 Example Request: POST /v2/apps/example-go/pods/web/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ] Restart Pods by Type and Name \u00b6 Example Request: POST /v2/apps/example-go/pods/go-v2-web-atots/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ] Scale Pods \u00b6 Example Request: POST /v2/apps/example-go/scale/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"web\": 3} Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Configuration \u00b6 List Application Configuration \u00b6 Example Request: GET /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Create new Config \u00b6 Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": \"world\", \"PLATFORM\": \"drycc\"}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v3\", \"HELLO\": \"world\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Unset Config Variable \u00b6 Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": null}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v4\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Domains \u00b6 List Application Domains \u00b6 Example Request: GET /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" } ] } Add Domain \u00b6 Example Request: POST /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {'domain': 'example.example.com'} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" } Remove Domain \u00b6 Example Request: DELETE /v2/apps/example-go/domains/example.example.com HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Builds \u00b6 List Application Builds \u00b6 Example Request: GET /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"FROM drycc/slugrunner RUN mkdir -p /app WORKDIR /app ENTRYPOINT [\\\"/runner/init\\\"] ADD slug.tgz /app ENV GIT_SHA 060da68f654e75fac06dbedd1995d5f8ad9084db\", \"image\": \"example-go\", \"owner\": \"test\", \"procfile\": { \"web\": \"example-go\" }, \"sha\": \"060da68f\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] } Create Application Build \u00b6 Example Request: POST /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"image\": \"drycc/example-go:latest\"} Optional Parameters: { \"procfile\": { \"web\": \"./cmd\" } } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"\", \"image\": \"drycc/example-go:latest\", \"owner\": \"test\", \"procfile\": {}, \"sha\": \"\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Releases \u00b6 List Application Releases \u00b6 Example Request: GET /v2/apps/example-go/releases/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 3, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"build\": \"202d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"ed637ceb-5d32-44bd-9406-d326a777a513\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test changed nothing\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 3 }, { \"app\": \"example-go\", \"build\": \"202d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test deployed 060da68\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 2 }, { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 } ] } List Release Details \u00b6 Example Request: GET /v2/apps/example-go/releases/v2/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 } Rollback Release \u00b6 Example Request: POST /v2/apps/example-go/releases/rollback/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"version\": 1} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"version\": 5} Keys \u00b6 List Keys \u00b6 Example Request: GET /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"test@example.com\", \"owner\": \"test\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] } Add Key to User \u00b6 Example Request: POST /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"id\": \"example\", \"public\": \"ssh-rsa <...>\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example\", \"owner\": \"example\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Remove Key from User \u00b6 Example Request: DELETE /v2/keys/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Permissions \u00b6 List Application Permissions \u00b6 note This does not include the app owner. Example Request: GET /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"users\": [ \"test\", \"foo\" ] } Create Application Permission \u00b6 Example Request: POST /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Remove Application Permission \u00b6 Example Request: DELETE /v2/apps/example-go/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 List Administrators \u00b6 Example Request: GET /v2/admin/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 2, \"next\": null \"previous\": null, \"results\": [ { \"username\": \"test\", \"is_superuser\": true }, { \"username\": \"foo\", \"is_superuser\": true } ] } Grant User Administrative Privileges \u00b6 note This command requires administrative privileges Example Request: POST /v2/admin/perms HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Remove User's Administrative Privileges \u00b6 note This command requires administrative privileges Example Request: DELETE /v2/admin/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Users \u00b6 List all users \u00b6 note This command requires administrative privileges Example Request: GET /v2/users HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } ] }","title":"Controller API v2.1"},{"location":"reference-guide/controller-api/v2.1/#controller-api-v21","text":"This is the v2.1 REST API for the Controller.","title":"Controller API v2.1"},{"location":"reference-guide/controller-api/v2.1/#whats-new","text":"New! healthcheck field in configuration, deprecates the HEALTHCHECK_* environment variables. New! Unsetting a configuration variable that does not exist will return a 422. New! Creating an identical sequential release returns a 409 rather than create a no-op release.","title":"What's New"},{"location":"reference-guide/controller-api/v2.1/#authentication","text":"","title":"Authentication"},{"location":"reference-guide/controller-api/v2.1/#register-a-new-user","text":"Example Request: POST /v2/auth/register/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json { \"username\": \"test\", \"password\": \"opensesame\", \"email\": \"test@example.com\" } Optional Parameters: { \"first_name\": \"test\", \"last_name\": \"testerson\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] }","title":"Register a New User"},{"location":"reference-guide/controller-api/v2.1/#log-in","text":"Example Request: POST /v2/auth/login/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json {\"username\": \"test\", \"password\": \"opensesame\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"token\": \"abc123\"}","title":"Log in"},{"location":"reference-guide/controller-api/v2.1/#cancel-account","text":"Example Request: DELETE /v2/auth/cancel/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Cancel Account"},{"location":"reference-guide/controller-api/v2.1/#regenerate-token","text":"note This command could require administrative privileges Example Request: POST /v2/auth/tokens/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional Parameters: { \"username\" : \"test\" \"all\" : \"true\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"token\": \"abc123\"}","title":"Regenerate Token"},{"location":"reference-guide/controller-api/v2.1/#change-password","text":"Example Request: POST /v2/auth/passwd/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"password\": \"foo\", \"new_password\": \"bar\" } Optional parameters: {\"username\": \"testuser\"} note Using the username parameter requires administrative privileges and makes the password parameter optional. Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Change Password"},{"location":"reference-guide/controller-api/v2.1/#applications","text":"","title":"Applications"},{"location":"reference-guide/controller-api/v2.1/#list-all-applications","text":"Example Request: GET /v2/apps HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] }","title":"List all Applications"},{"location":"reference-guide/controller-api/v2.1/#create-an-application","text":"Example Request: POST /v2/apps/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 Optional parameters: {\"id\": \"example-go\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Create an Application"},{"location":"reference-guide/controller-api/v2.1/#destroy-an-application","text":"Example Request: DELETE /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Destroy an Application"},{"location":"reference-guide/controller-api/v2.1/#list-application-details","text":"Example Request: GET /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"List Application Details"},{"location":"reference-guide/controller-api/v2.1/#update-application-details","text":"Example Request: POST /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional parameters: { \"owner\": \"test\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 1.8.0 Content-Type: application/json","title":"Update Application Details"},{"location":"reference-guide/controller-api/v2.1/#retrieve-application-logs","text":"Example Request: GET /v2/apps/example-go/logs/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional URL Query Parameters: ?log_lines= Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: text/plain \"16:51:14 drycc[api]: test created initial release\\n\"","title":"Retrieve Application Logs"},{"location":"reference-guide/controller-api/v2.1/#run-one-off-commands","text":"POST /v2/apps/example-go/run/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"command\": \"echo hi\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"exit_code\": 0, \"output\": \"hi\\n\"}","title":"Run one-off Commands"},{"location":"reference-guide/controller-api/v2.1/#certificates","text":"","title":"Certificates"},{"location":"reference-guide/controller-api/v2.1/#list-all-certificates","text":"Example Request: GET /v2/certs HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } ] }","title":"List all Certificates"},{"location":"reference-guide/controller-api/v2.1/#get-certificate-details","text":"Example Request: GET /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" }","title":"Get Certificate Details"},{"location":"reference-guide/controller-api/v2.1/#create-certificate","text":"Example Request: POST /v2/certs/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 { \"name\": \"foo\" \"certificate\": \"-----BEGIN CERTIFICATE-----\", \"key\": \"-----BEGIN RSA PRIVATE KEY-----\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" }","title":"Create Certificate"},{"location":"reference-guide/controller-api/v2.1/#destroy-a-certificate","text":"Example Request: DELETE /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Destroy a Certificate"},{"location":"reference-guide/controller-api/v2.1/#attach-a-domain-to-a-certificate","text":"Example Request: POST /v2/certs/foo/domain/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"domain\": \"test.com\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Attach a Domain to a Certificate"},{"location":"reference-guide/controller-api/v2.1/#remove-a-domain-from-a-certificate","text":"Example Request: DELETE /v2/certs/foo/domain/test.com/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Remove a Domain from a Certificate"},{"location":"reference-guide/controller-api/v2.1/#pods","text":"","title":"Pods"},{"location":"reference-guide/controller-api/v2.1/#list-all-pods","text":"Example Request: GET /v2/apps/example-go/pods/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] }","title":"List all Pods"},{"location":"reference-guide/controller-api/v2.1/#list-all-pods-by-type","text":"Example Request: GET /v2/apps/example-go/pods/web/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] }","title":"List all Pods by Type"},{"location":"reference-guide/controller-api/v2.1/#restart-all-pods","text":"Example Request: POST /v2/apps/example-go/pods/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ]","title":"Restart All Pods"},{"location":"reference-guide/controller-api/v2.1/#restart-pods-by-type","text":"Example Request: POST /v2/apps/example-go/pods/web/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ]","title":"Restart Pods by Type"},{"location":"reference-guide/controller-api/v2.1/#restart-pods-by-type-and-name","text":"Example Request: POST /v2/apps/example-go/pods/go-v2-web-atots/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ]","title":"Restart Pods by Type and Name"},{"location":"reference-guide/controller-api/v2.1/#scale-pods","text":"Example Request: POST /v2/apps/example-go/scale/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"web\": 3} Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Scale Pods"},{"location":"reference-guide/controller-api/v2.1/#configuration","text":"","title":"Configuration"},{"location":"reference-guide/controller-api/v2.1/#list-application-configuration","text":"Example Request: GET /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"List Application Configuration"},{"location":"reference-guide/controller-api/v2.1/#create-new-config","text":"Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": \"world\", \"PLATFORM\": \"drycc\"}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v3\", \"HELLO\": \"world\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Create new Config"},{"location":"reference-guide/controller-api/v2.1/#unset-config-variable","text":"Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": null}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v4\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Unset Config Variable"},{"location":"reference-guide/controller-api/v2.1/#domains","text":"","title":"Domains"},{"location":"reference-guide/controller-api/v2.1/#list-application-domains","text":"Example Request: GET /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" } ] }","title":"List Application Domains"},{"location":"reference-guide/controller-api/v2.1/#add-domain","text":"Example Request: POST /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {'domain': 'example.example.com'} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" }","title":"Add Domain"},{"location":"reference-guide/controller-api/v2.1/#remove-domain","text":"Example Request: DELETE /v2/apps/example-go/domains/example.example.com HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Remove Domain"},{"location":"reference-guide/controller-api/v2.1/#builds","text":"","title":"Builds"},{"location":"reference-guide/controller-api/v2.1/#list-application-builds","text":"Example Request: GET /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"FROM drycc/slugrunner RUN mkdir -p /app WORKDIR /app ENTRYPOINT [\\\"/runner/init\\\"] ADD slug.tgz /app ENV GIT_SHA 060da68f654e75fac06dbedd1995d5f8ad9084db\", \"image\": \"example-go\", \"owner\": \"test\", \"procfile\": { \"web\": \"example-go\" }, \"sha\": \"060da68f\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] }","title":"List Application Builds"},{"location":"reference-guide/controller-api/v2.1/#create-application-build","text":"Example Request: POST /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"image\": \"drycc/example-go:latest\"} Optional Parameters: { \"procfile\": { \"web\": \"./cmd\" } } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"\", \"image\": \"drycc/example-go:latest\", \"owner\": \"test\", \"procfile\": {}, \"sha\": \"\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Create Application Build"},{"location":"reference-guide/controller-api/v2.1/#releases","text":"","title":"Releases"},{"location":"reference-guide/controller-api/v2.1/#list-application-releases","text":"Example Request: GET /v2/apps/example-go/releases/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 3, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"build\": \"202d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"ed637ceb-5d32-44bd-9406-d326a777a513\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test changed nothing\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 3 }, { \"app\": \"example-go\", \"build\": \"202d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test deployed 060da68\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 2 }, { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 } ] }","title":"List Application Releases"},{"location":"reference-guide/controller-api/v2.1/#list-release-details","text":"Example Request: GET /v2/apps/example-go/releases/v2/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 }","title":"List Release Details"},{"location":"reference-guide/controller-api/v2.1/#rollback-release","text":"Example Request: POST /v2/apps/example-go/releases/rollback/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"version\": 1} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json {\"version\": 5}","title":"Rollback Release"},{"location":"reference-guide/controller-api/v2.1/#keys","text":"","title":"Keys"},{"location":"reference-guide/controller-api/v2.1/#list-keys","text":"Example Request: GET /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"test@example.com\", \"owner\": \"test\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] }","title":"List Keys"},{"location":"reference-guide/controller-api/v2.1/#add-key-to-user","text":"Example Request: POST /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"id\": \"example\", \"public\": \"ssh-rsa <...>\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example\", \"owner\": \"example\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Add Key to User"},{"location":"reference-guide/controller-api/v2.1/#remove-key-from-user","text":"Example Request: DELETE /v2/keys/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Remove Key from User"},{"location":"reference-guide/controller-api/v2.1/#permissions","text":"","title":"Permissions"},{"location":"reference-guide/controller-api/v2.1/#list-application-permissions","text":"note This does not include the app owner. Example Request: GET /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"users\": [ \"test\", \"foo\" ] }","title":"List Application Permissions"},{"location":"reference-guide/controller-api/v2.1/#create-application-permission","text":"Example Request: POST /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Create Application Permission"},{"location":"reference-guide/controller-api/v2.1/#remove-application-permission","text":"Example Request: DELETE /v2/apps/example-go/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Remove Application Permission"},{"location":"reference-guide/controller-api/v2.1/#list-administrators","text":"Example Request: GET /v2/admin/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 2, \"next\": null \"previous\": null, \"results\": [ { \"username\": \"test\", \"is_superuser\": true }, { \"username\": \"foo\", \"is_superuser\": true } ] }","title":"List Administrators"},{"location":"reference-guide/controller-api/v2.1/#grant-user-administrative-privileges","text":"note This command requires administrative privileges Example Request: POST /v2/admin/perms HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Grant User Administrative Privileges"},{"location":"reference-guide/controller-api/v2.1/#remove-users-administrative-privileges","text":"note This command requires administrative privileges Example Request: DELETE /v2/admin/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0","title":"Remove User's Administrative Privileges"},{"location":"reference-guide/controller-api/v2.1/#users","text":"","title":"Users"},{"location":"reference-guide/controller-api/v2.1/#list-all-users","text":"note This command requires administrative privileges Example Request: GET /v2/users HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.1 DRYCC_PLATFORM_VERSION: 2.1.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } ] }","title":"List all users"},{"location":"reference-guide/controller-api/v2.2/","text":"Controller API v2.2 \u00b6 This is the v2.2 REST API for the Controller. What's New \u00b6 New! /v2/auth/whoami endpoint Authentication \u00b6 Register a New User \u00b6 Example Request: POST /v2/auth/register/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json { \"username\": \"test\", \"password\": \"opensesame\", \"email\": \"test@example.com\" } Optional Parameters: { \"first_name\": \"test\", \"last_name\": \"testerson\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } Log in \u00b6 Example Request: POST /v2/auth/login/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json {\"username\": \"test\", \"password\": \"opensesame\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json {\"token\": \"abc123\"} Cancel Account \u00b6 Example Request: DELETE /v2/auth/cancel/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Who Am I \u00b6 Example Request: GET /v2/auth/whoami/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } Regenerate Token \u00b6 note This command could require administrative privileges Example Request: POST /v2/auth/tokens/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional Parameters: { \"username\" : \"test\" \"all\" : \"true\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json {\"token\": \"abc123\"} Change Password \u00b6 Example Request: POST /v2/auth/passwd/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"password\": \"foo\", \"new_password\": \"bar\" } Optional parameters: {\"username\": \"testuser\"} note Using the username parameter requires administrative privileges and makes the password parameter optional. Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Applications \u00b6 List all Applications \u00b6 Example Request: GET /v2/apps HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] } Create an Application \u00b6 Example Request: POST /v2/apps/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 Optional parameters: {\"id\": \"example-go\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Destroy an Application \u00b6 Example Request: DELETE /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 List Application Details \u00b6 Example Request: GET /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Update Application Details \u00b6 Example Request: POST /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional parameters: { \"owner\": \"test\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 1.8.0 Content-Type: application/json Retrieve Application Logs \u00b6 Example Request: GET /v2/apps/example-go/logs/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional URL Query Parameters: ?log_lines= Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: text/plain \"16:51:14 drycc[api]: test created initial release\\n\" Run one-off Commands \u00b6 POST /v2/apps/example-go/run/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"command\": \"echo hi\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json {\"exit_code\": 0, \"output\": \"hi\\n\"} Certificates \u00b6 List all Certificates \u00b6 Example Request: GET /v2/certs HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } ] } Get Certificate Details \u00b6 Example Request: GET /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } Create Certificate \u00b6 Example Request: POST /v2/certs/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 { \"name\": \"foo\" \"certificate\": \"-----BEGIN CERTIFICATE-----\", \"key\": \"-----BEGIN RSA PRIVATE KEY-----\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } Destroy a Certificate \u00b6 Example Request: DELETE /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Attach a Domain to a Certificate \u00b6 Example Request: POST /v2/certs/foo/domain/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"domain\": \"test.com\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Remove a Domain from a Certificate \u00b6 Example Request: DELETE /v2/certs/foo/domain/test.com/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Pods \u00b6 List all Pods \u00b6 Example Request: GET /v2/apps/example-go/pods/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] } List all Pods by Type \u00b6 Example Request: GET /v2/apps/example-go/pods/web/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] } Restart All Pods \u00b6 Example Request: POST /v2/apps/example-go/pods/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ] Restart Pods by Type \u00b6 Example Request: POST /v2/apps/example-go/pods/web/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ] Restart Pods by Type and Name \u00b6 Example Request: POST /v2/apps/example-go/pods/go-v2-web-atots/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ] Scale Pods \u00b6 Example Request: POST /v2/apps/example-go/scale/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"web\": 3} Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Configuration \u00b6 List Application Configuration \u00b6 Example Request: GET /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Create new Config \u00b6 Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": \"world\", \"PLATFORM\": \"drycc\"}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v3\", \"HELLO\": \"world\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Unset Config Variable \u00b6 Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": null}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v4\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Domains \u00b6 List Application Domains \u00b6 Example Request: GET /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" } ] } Add Domain \u00b6 Example Request: POST /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {'domain': 'example.example.com'} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" } Remove Domain \u00b6 Example Request: DELETE /v2/apps/example-go/domains/example.example.com HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Builds \u00b6 List Application Builds \u00b6 Example Request: GET /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"FROM drycc/slugrunner RUN mkdir -p /app WORKDIR /app ENTRYPOINT [\\\"/runner/init\\\"] ADD slug.tgz /app ENV GIT_SHA 060da68f654e75fac06dbedd1995d5f8ad9084db\", \"image\": \"example-go\", \"owner\": \"test\", \"procfile\": { \"web\": \"example-go\" }, \"sha\": \"060da68f\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] } Create Application Build \u00b6 Example Request: POST /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"image\": \"drycc/example-go:latest\"} Optional Parameters: { \"procfile\": { \"web\": \"./cmd\" } } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"\", \"image\": \"drycc/example-go:latest\", \"owner\": \"test\", \"procfile\": {}, \"sha\": \"\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Releases \u00b6 List Application Releases \u00b6 Example Request: GET /v2/apps/example-go/releases/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 3, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"build\": \"202d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"ed637ceb-5d32-44bd-9406-d326a777a513\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test changed nothing\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 3 }, { \"app\": \"example-go\", \"build\": \"202d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test deployed 060da68\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 2 }, { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 } ] } List Release Details \u00b6 Example Request: GET /v2/apps/example-go/releases/v2/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 } Rollback Release \u00b6 Example Request: POST /v2/apps/example-go/releases/rollback/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"version\": 1} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json {\"version\": 5} Keys \u00b6 List Keys \u00b6 Example Request: GET /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"test@example.com\", \"owner\": \"test\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] } Add Key to User \u00b6 Example Request: POST /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"id\": \"example\", \"public\": \"ssh-rsa <...>\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example\", \"owner\": \"example\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Remove Key from User \u00b6 Example Request: DELETE /v2/keys/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Permissions \u00b6 List Application Permissions \u00b6 note This does not include the app owner. Example Request: GET /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"users\": [ \"test\", \"foo\" ] } Create Application Permission \u00b6 Example Request: POST /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Remove Application Permission \u00b6 Example Request: DELETE /v2/apps/example-go/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 List Administrators \u00b6 Example Request: GET /v2/admin/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 2, \"next\": null \"previous\": null, \"results\": [ { \"username\": \"test\", \"is_superuser\": true }, { \"username\": \"foo\", \"is_superuser\": true } ] } Grant User Administrative Privileges \u00b6 note This command requires administrative privileges Example Request: POST /v2/admin/perms HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Remove User's Administrative Privileges \u00b6 note This command requires administrative privileges Example Request: DELETE /v2/admin/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Users \u00b6 List all users \u00b6 note This command requires administrative privileges Example Request: GET /v2/users HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } ] }","title":"Controller API v2.2"},{"location":"reference-guide/controller-api/v2.2/#controller-api-v22","text":"This is the v2.2 REST API for the Controller.","title":"Controller API v2.2"},{"location":"reference-guide/controller-api/v2.2/#whats-new","text":"New! /v2/auth/whoami endpoint","title":"What's New"},{"location":"reference-guide/controller-api/v2.2/#authentication","text":"","title":"Authentication"},{"location":"reference-guide/controller-api/v2.2/#register-a-new-user","text":"Example Request: POST /v2/auth/register/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json { \"username\": \"test\", \"password\": \"opensesame\", \"email\": \"test@example.com\" } Optional Parameters: { \"first_name\": \"test\", \"last_name\": \"testerson\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] }","title":"Register a New User"},{"location":"reference-guide/controller-api/v2.2/#log-in","text":"Example Request: POST /v2/auth/login/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json {\"username\": \"test\", \"password\": \"opensesame\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json {\"token\": \"abc123\"}","title":"Log in"},{"location":"reference-guide/controller-api/v2.2/#cancel-account","text":"Example Request: DELETE /v2/auth/cancel/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Cancel Account"},{"location":"reference-guide/controller-api/v2.2/#who-am-i","text":"Example Request: GET /v2/auth/whoami/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] }","title":"Who Am I"},{"location":"reference-guide/controller-api/v2.2/#regenerate-token","text":"note This command could require administrative privileges Example Request: POST /v2/auth/tokens/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional Parameters: { \"username\" : \"test\" \"all\" : \"true\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json {\"token\": \"abc123\"}","title":"Regenerate Token"},{"location":"reference-guide/controller-api/v2.2/#change-password","text":"Example Request: POST /v2/auth/passwd/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"password\": \"foo\", \"new_password\": \"bar\" } Optional parameters: {\"username\": \"testuser\"} note Using the username parameter requires administrative privileges and makes the password parameter optional. Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Change Password"},{"location":"reference-guide/controller-api/v2.2/#applications","text":"","title":"Applications"},{"location":"reference-guide/controller-api/v2.2/#list-all-applications","text":"Example Request: GET /v2/apps HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] }","title":"List all Applications"},{"location":"reference-guide/controller-api/v2.2/#create-an-application","text":"Example Request: POST /v2/apps/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 Optional parameters: {\"id\": \"example-go\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Create an Application"},{"location":"reference-guide/controller-api/v2.2/#destroy-an-application","text":"Example Request: DELETE /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Destroy an Application"},{"location":"reference-guide/controller-api/v2.2/#list-application-details","text":"Example Request: GET /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"List Application Details"},{"location":"reference-guide/controller-api/v2.2/#update-application-details","text":"Example Request: POST /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional parameters: { \"owner\": \"test\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 1.8.0 Content-Type: application/json","title":"Update Application Details"},{"location":"reference-guide/controller-api/v2.2/#retrieve-application-logs","text":"Example Request: GET /v2/apps/example-go/logs/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional URL Query Parameters: ?log_lines= Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: text/plain \"16:51:14 drycc[api]: test created initial release\\n\"","title":"Retrieve Application Logs"},{"location":"reference-guide/controller-api/v2.2/#run-one-off-commands","text":"POST /v2/apps/example-go/run/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"command\": \"echo hi\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json {\"exit_code\": 0, \"output\": \"hi\\n\"}","title":"Run one-off Commands"},{"location":"reference-guide/controller-api/v2.2/#certificates","text":"","title":"Certificates"},{"location":"reference-guide/controller-api/v2.2/#list-all-certificates","text":"Example Request: GET /v2/certs HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } ] }","title":"List all Certificates"},{"location":"reference-guide/controller-api/v2.2/#get-certificate-details","text":"Example Request: GET /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" }","title":"Get Certificate Details"},{"location":"reference-guide/controller-api/v2.2/#create-certificate","text":"Example Request: POST /v2/certs/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 { \"name\": \"foo\" \"certificate\": \"-----BEGIN CERTIFICATE-----\", \"key\": \"-----BEGIN RSA PRIVATE KEY-----\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22T22:24:20Z\", \"updated\": \"2016-06-22T22:24:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" }","title":"Create Certificate"},{"location":"reference-guide/controller-api/v2.2/#destroy-a-certificate","text":"Example Request: DELETE /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Destroy a Certificate"},{"location":"reference-guide/controller-api/v2.2/#attach-a-domain-to-a-certificate","text":"Example Request: POST /v2/certs/foo/domain/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"domain\": \"test.com\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Attach a Domain to a Certificate"},{"location":"reference-guide/controller-api/v2.2/#remove-a-domain-from-a-certificate","text":"Example Request: DELETE /v2/certs/foo/domain/test.com/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Remove a Domain from a Certificate"},{"location":"reference-guide/controller-api/v2.2/#pods","text":"","title":"Pods"},{"location":"reference-guide/controller-api/v2.2/#list-all-pods","text":"Example Request: GET /v2/apps/example-go/pods/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] }","title":"List all Pods"},{"location":"reference-guide/controller-api/v2.2/#list-all-pods-by-type","text":"Example Request: GET /v2/apps/example-go/pods/web/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] }","title":"List all Pods by Type"},{"location":"reference-guide/controller-api/v2.2/#restart-all-pods","text":"Example Request: POST /v2/apps/example-go/pods/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ]","title":"Restart All Pods"},{"location":"reference-guide/controller-api/v2.2/#restart-pods-by-type","text":"Example Request: POST /v2/apps/example-go/pods/web/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ]","title":"Restart Pods by Type"},{"location":"reference-guide/controller-api/v2.2/#restart-pods-by-type-and-name","text":"Example Request: POST /v2/apps/example-go/pods/go-v2-web-atots/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ]","title":"Restart Pods by Type and Name"},{"location":"reference-guide/controller-api/v2.2/#scale-pods","text":"Example Request: POST /v2/apps/example-go/scale/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"web\": 3} Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Scale Pods"},{"location":"reference-guide/controller-api/v2.2/#configuration","text":"","title":"Configuration"},{"location":"reference-guide/controller-api/v2.2/#list-application-configuration","text":"Example Request: GET /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"List Application Configuration"},{"location":"reference-guide/controller-api/v2.2/#create-new-config","text":"Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": \"world\", \"PLATFORM\": \"drycc\"}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v3\", \"HELLO\": \"world\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Create new Config"},{"location":"reference-guide/controller-api/v2.2/#unset-config-variable","text":"Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": null}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v4\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Unset Config Variable"},{"location":"reference-guide/controller-api/v2.2/#domains","text":"","title":"Domains"},{"location":"reference-guide/controller-api/v2.2/#list-application-domains","text":"Example Request: GET /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" } ] }","title":"List Application Domains"},{"location":"reference-guide/controller-api/v2.2/#add-domain","text":"Example Request: POST /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {'domain': 'example.example.com'} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" }","title":"Add Domain"},{"location":"reference-guide/controller-api/v2.2/#remove-domain","text":"Example Request: DELETE /v2/apps/example-go/domains/example.example.com HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Remove Domain"},{"location":"reference-guide/controller-api/v2.2/#builds","text":"","title":"Builds"},{"location":"reference-guide/controller-api/v2.2/#list-application-builds","text":"Example Request: GET /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"FROM drycc/slugrunner RUN mkdir -p /app WORKDIR /app ENTRYPOINT [\\\"/runner/init\\\"] ADD slug.tgz /app ENV GIT_SHA 060da68f654e75fac06dbedd1995d5f8ad9084db\", \"image\": \"example-go\", \"owner\": \"test\", \"procfile\": { \"web\": \"example-go\" }, \"sha\": \"060da68f\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] }","title":"List Application Builds"},{"location":"reference-guide/controller-api/v2.2/#create-application-build","text":"Example Request: POST /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"image\": \"drycc/example-go:latest\"} Optional Parameters: { \"procfile\": { \"web\": \"./cmd\" } } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"\", \"image\": \"drycc/example-go:latest\", \"owner\": \"test\", \"procfile\": {}, \"sha\": \"\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Create Application Build"},{"location":"reference-guide/controller-api/v2.2/#releases","text":"","title":"Releases"},{"location":"reference-guide/controller-api/v2.2/#list-application-releases","text":"Example Request: GET /v2/apps/example-go/releases/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 3, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"build\": \"202d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"ed637ceb-5d32-44bd-9406-d326a777a513\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test changed nothing\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 3 }, { \"app\": \"example-go\", \"build\": \"202d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test deployed 060da68\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 2 }, { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 } ] }","title":"List Application Releases"},{"location":"reference-guide/controller-api/v2.2/#list-release-details","text":"Example Request: GET /v2/apps/example-go/releases/v2/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 }","title":"List Release Details"},{"location":"reference-guide/controller-api/v2.2/#rollback-release","text":"Example Request: POST /v2/apps/example-go/releases/rollback/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"version\": 1} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json {\"version\": 5}","title":"Rollback Release"},{"location":"reference-guide/controller-api/v2.2/#keys","text":"","title":"Keys"},{"location":"reference-guide/controller-api/v2.2/#list-keys","text":"Example Request: GET /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"test@example.com\", \"owner\": \"test\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] }","title":"List Keys"},{"location":"reference-guide/controller-api/v2.2/#add-key-to-user","text":"Example Request: POST /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"id\": \"example\", \"public\": \"ssh-rsa <...>\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example\", \"owner\": \"example\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Add Key to User"},{"location":"reference-guide/controller-api/v2.2/#remove-key-from-user","text":"Example Request: DELETE /v2/keys/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Remove Key from User"},{"location":"reference-guide/controller-api/v2.2/#permissions","text":"","title":"Permissions"},{"location":"reference-guide/controller-api/v2.2/#list-application-permissions","text":"note This does not include the app owner. Example Request: GET /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"users\": [ \"test\", \"foo\" ] }","title":"List Application Permissions"},{"location":"reference-guide/controller-api/v2.2/#create-application-permission","text":"Example Request: POST /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Create Application Permission"},{"location":"reference-guide/controller-api/v2.2/#remove-application-permission","text":"Example Request: DELETE /v2/apps/example-go/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Remove Application Permission"},{"location":"reference-guide/controller-api/v2.2/#list-administrators","text":"Example Request: GET /v2/admin/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 2, \"next\": null \"previous\": null, \"results\": [ { \"username\": \"test\", \"is_superuser\": true }, { \"username\": \"foo\", \"is_superuser\": true } ] }","title":"List Administrators"},{"location":"reference-guide/controller-api/v2.2/#grant-user-administrative-privileges","text":"note This command requires administrative privileges Example Request: POST /v2/admin/perms HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Grant User Administrative Privileges"},{"location":"reference-guide/controller-api/v2.2/#remove-users-administrative-privileges","text":"note This command requires administrative privileges Example Request: DELETE /v2/admin/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0","title":"Remove User's Administrative Privileges"},{"location":"reference-guide/controller-api/v2.2/#users","text":"","title":"Users"},{"location":"reference-guide/controller-api/v2.2/#list-all-users","text":"note This command requires administrative privileges Example Request: GET /v2/users HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.2 DRYCC_PLATFORM_VERSION: 2.2.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } ] }","title":"List all users"},{"location":"reference-guide/controller-api/v2.3/","text":"Controller API v2.3 \u00b6 This is the v2.3 REST API for the Controller. What's New \u00b6 New! /v2/apps/{name}/logs endpoint was fixed and no longer returns b'log data' and instead returns a normal string log data Authentication \u00b6 Register a New User \u00b6 Example Request: POST /v2/auth/register/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json { \"username\": \"test\", \"password\": \"opensesame\", \"email\": \"test@example.com\" } Optional Parameters: { \"first_name\": \"test\", \"last_name\": \"testerson\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } Log in \u00b6 Example Request: POST /v2/auth/login/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json {\"username\": \"test\", \"password\": \"opensesame\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json {\"token\": \"abc123\"} Cancel Account \u00b6 Example Request: DELETE /v2/auth/cancel/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Who Am I \u00b6 Example Request: GET /v2/auth/whoami/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } Regenerate Token \u00b6 note This command could require administrative privileges Example Request: POST /v2/auth/tokens/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional Parameters: { \"username\" : \"test\" \"all\" : \"true\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json {\"token\": \"abc123\"} Change Password \u00b6 Example Request: POST /v2/auth/passwd/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"password\": \"foo\", \"new_password\": \"bar\" } Optional parameters: {\"username\": \"testuser\"} note Using the username parameter requires administrative privileges and makes the password parameter optional. Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Applications \u00b6 List all Applications \u00b6 Example Request: GET /v2/apps HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] } Create an Application \u00b6 Example Request: POST /v2/apps/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 Optional parameters: {\"id\": \"example-go\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Destroy an Application \u00b6 Example Request: DELETE /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 List Application Details \u00b6 Example Request: GET /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Update Application Details \u00b6 Example Request: POST /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional parameters: { \"owner\": \"test\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 1.8.0 Content-Type: application/json Retrieve Application Logs \u00b6 Example Request: GET /v2/apps/example-go/logs/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional URL Query Parameters: ?log_lines= Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: text/plain \"16:51:14 drycc[api]: test created initial release\\n\" Run one-off Commands \u00b6 POST /v2/apps/example-go/run/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"command\": \"echo hi\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json {\"exit_code\": 0, \"output\": \"hi\\n\"} Certificates \u00b6 List all Certificates \u00b6 Example Request: GET /v2/certs HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22.32.34:20Z\", \"updated\": \"2016-06-22.32.34:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } ] } Get Certificate Details \u00b6 Example Request: GET /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22.32.34:20Z\", \"updated\": \"2016-06-22.32.34:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } Create Certificate \u00b6 Example Request: POST /v2/certs/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 { \"name\": \"foo\" \"certificate\": \"-----BEGIN CERTIFICATE-----\", \"key\": \"-----BEGIN RSA PRIVATE KEY-----\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22.32.34:20Z\", \"updated\": \"2016-06-22.32.34:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } Destroy a Certificate \u00b6 Example Request: DELETE /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Attach a Domain to a Certificate \u00b6 Example Request: POST /v2/certs/foo/domain/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"domain\": \"test.com\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Remove a Domain from a Certificate \u00b6 Example Request: DELETE /v2/certs/foo/domain/test.com/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Enable or disable TLS \u00b6 Example Request: POST /v2/apps/example-go/tls/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 { \"https_enforced\": true } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"app\": \"example-go\", \"owner\": \"test\", \"https_enforced\": true, \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Get TLS status \u00b6 Example Request: GET /v2/apps/example-go/tls/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"app\": \"example-go\", \"owner\": \"test\", \"https_enforced\": false, \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Pods \u00b6 List all Pods \u00b6 Example Request: GET /v2/apps/example-go/pods/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] } List all Pods by Type \u00b6 Example Request: GET /v2/apps/example-go/pods/web/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] } Restart All Pods \u00b6 Example Request: POST /v2/apps/example-go/pods/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ] Restart Pods by Type \u00b6 Example Request: POST /v2/apps/example-go/pods/web/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ] Restart Pods by Type and Name \u00b6 Example Request: POST /v2/apps/example-go/pods/go-v2-web-atots/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ] Scale Pods \u00b6 Example Request: POST /v2/apps/example-go/scale/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"web\": 3} Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Configuration \u00b6 List Application Configuration \u00b6 Example Request: GET /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Create new Config \u00b6 Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": \"world\", \"PLATFORM\": \"drycc\"}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v3\", \"HELLO\": \"world\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Unset Config Variable \u00b6 Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": null}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v4\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Domains \u00b6 List Application Domains \u00b6 Example Request: GET /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" } ] } Add Domain \u00b6 Example Request: POST /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {'domain': 'example.example.com'} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" } Remove Domain \u00b6 Example Request: DELETE /v2/apps/example-go/domains/example.example.com HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Builds \u00b6 List Application Builds \u00b6 Example Request: GET /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"FROM drycc/slugrunner RUN mkdir -p /app WORKDIR /app ENTRYPOINT [\\\"/runner/init\\\"] ADD slug.tgz /app ENV GIT_SHA 060da68f654e75fac06dbedd1995d5f8ad9084db\", \"image\": \"example-go\", \"owner\": \"test\", \"procfile\": { \"web\": \"example-go\" }, \"sha\": \"060da68f\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] } Create Application Build \u00b6 Example Request: POST /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"image\": \"drycc/example-go:latest\"} Optional Parameters: { \"procfile\": { \"web\": \"./cmd\" } } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"\", \"image\": \"drycc/example-go:latest\", \"owner\": \"test\", \"procfile\": {}, \"sha\": \"\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Releases \u00b6 List Application Releases \u00b6 Example Request: GET /v2/apps/example-go/releases/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 3, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"build\": \"2.3d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"ed637ceb-5d32-44bd-9406-d326a777a513\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test changed nothing\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 3 }, { \"app\": \"example-go\", \"build\": \"2.3d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test deployed 060da68\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 2 }, { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 } ] } List Release Details \u00b6 Example Request: GET /v2/apps/example-go/releases/v2/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 } Rollback Release \u00b6 Example Request: POST /v2/apps/example-go/releases/rollback/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"version\": 1} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json {\"version\": 5} Keys \u00b6 List Keys \u00b6 Example Request: GET /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"test@example.com\", \"owner\": \"test\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] } Add Key to User \u00b6 Example Request: POST /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"id\": \"example\", \"public\": \"ssh-rsa <...>\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example\", \"owner\": \"example\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } Remove Key from User \u00b6 Example Request: DELETE /v2/keys/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Permissions \u00b6 List Application Permissions \u00b6 note This does not include the app owner. Example Request: GET /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"users\": [ \"test\", \"foo\" ] } Create Application Permission \u00b6 Example Request: POST /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Remove Application Permission \u00b6 Example Request: DELETE /v2/apps/example-go/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 List Administrators \u00b6 Example Request: GET /v2/admin/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 2, \"next\": null \"previous\": null, \"results\": [ { \"username\": \"test\", \"is_superuser\": true }, { \"username\": \"foo\", \"is_superuser\": true } ] } Grant User Administrative Privileges \u00b6 note This command requires administrative privileges Example Request: POST /v2/admin/perms HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Remove User's Administrative Privileges \u00b6 note This command requires administrative privileges Example Request: DELETE /v2/admin/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Users \u00b6 List all users \u00b6 note This command requires administrative privileges Example Request: GET /v2/users HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } ] }","title":"Controller API v2.3"},{"location":"reference-guide/controller-api/v2.3/#controller-api-v23","text":"This is the v2.3 REST API for the Controller.","title":"Controller API v2.3"},{"location":"reference-guide/controller-api/v2.3/#whats-new","text":"New! /v2/apps/{name}/logs endpoint was fixed and no longer returns b'log data' and instead returns a normal string log data","title":"What's New"},{"location":"reference-guide/controller-api/v2.3/#authentication","text":"","title":"Authentication"},{"location":"reference-guide/controller-api/v2.3/#register-a-new-user","text":"Example Request: POST /v2/auth/register/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json { \"username\": \"test\", \"password\": \"opensesame\", \"email\": \"test@example.com\" } Optional Parameters: { \"first_name\": \"test\", \"last_name\": \"testerson\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] }","title":"Register a New User"},{"location":"reference-guide/controller-api/v2.3/#log-in","text":"Example Request: POST /v2/auth/login/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json {\"username\": \"test\", \"password\": \"opensesame\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json {\"token\": \"abc123\"}","title":"Log in"},{"location":"reference-guide/controller-api/v2.3/#cancel-account","text":"Example Request: DELETE /v2/auth/cancel/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Cancel Account"},{"location":"reference-guide/controller-api/v2.3/#who-am-i","text":"Example Request: GET /v2/auth/whoami/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] }","title":"Who Am I"},{"location":"reference-guide/controller-api/v2.3/#regenerate-token","text":"note This command could require administrative privileges Example Request: POST /v2/auth/tokens/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional Parameters: { \"username\" : \"test\" \"all\" : \"true\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json {\"token\": \"abc123\"}","title":"Regenerate Token"},{"location":"reference-guide/controller-api/v2.3/#change-password","text":"Example Request: POST /v2/auth/passwd/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"password\": \"foo\", \"new_password\": \"bar\" } Optional parameters: {\"username\": \"testuser\"} note Using the username parameter requires administrative privileges and makes the password parameter optional. Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Change Password"},{"location":"reference-guide/controller-api/v2.3/#applications","text":"","title":"Applications"},{"location":"reference-guide/controller-api/v2.3/#list-all-applications","text":"Example Request: GET /v2/apps HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] }","title":"List all Applications"},{"location":"reference-guide/controller-api/v2.3/#create-an-application","text":"Example Request: POST /v2/apps/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 Optional parameters: {\"id\": \"example-go\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Create an Application"},{"location":"reference-guide/controller-api/v2.3/#destroy-an-application","text":"Example Request: DELETE /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Destroy an Application"},{"location":"reference-guide/controller-api/v2.3/#list-application-details","text":"Example Request: GET /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example-go\", \"owner\": \"test\", \"structure\": {}, \"updated\": \"2014-01-01T00:00:00UTC\", \"url\": \"example-go.example.com\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"List Application Details"},{"location":"reference-guide/controller-api/v2.3/#update-application-details","text":"Example Request: POST /v2/apps/example-go/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional parameters: { \"owner\": \"test\" } Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 1.8.0 Content-Type: application/json","title":"Update Application Details"},{"location":"reference-guide/controller-api/v2.3/#retrieve-application-logs","text":"Example Request: GET /v2/apps/example-go/logs/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Optional URL Query Parameters: ?log_lines= Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: text/plain \"16:51:14 drycc[api]: test created initial release\\n\"","title":"Retrieve Application Logs"},{"location":"reference-guide/controller-api/v2.3/#run-one-off-commands","text":"POST /v2/apps/example-go/run/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"command\": \"echo hi\"} Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json {\"exit_code\": 0, \"output\": \"hi\\n\"}","title":"Run one-off Commands"},{"location":"reference-guide/controller-api/v2.3/#certificates","text":"","title":"Certificates"},{"location":"reference-guide/controller-api/v2.3/#list-all-certificates","text":"Example Request: GET /v2/certs HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22.32.34:20Z\", \"updated\": \"2016-06-22.32.34:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" } ] }","title":"List all Certificates"},{"location":"reference-guide/controller-api/v2.3/#get-certificate-details","text":"Example Request: GET /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22.32.34:20Z\", \"updated\": \"2016-06-22.32.34:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" }","title":"Get Certificate Details"},{"location":"reference-guide/controller-api/v2.3/#create-certificate","text":"Example Request: POST /v2/certs/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 { \"name\": \"foo\" \"certificate\": \"-----BEGIN CERTIFICATE-----\", \"key\": \"-----BEGIN RSA PRIVATE KEY-----\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"id\": 22, \"owner\": \"test\", \"san\": [], \"domains\": [], \"created\": \"2016-06-22.32.34:20Z\", \"updated\": \"2016-06-22.32.34:20Z\", \"name\": \"foo\", \"common_name\": \"bar.com\", \"fingerprint\": \"7A:CA:B8:50:FF:8D:EB:03:3D:AC:AD:13:4F:EE:03:D5:5D:EB:5E:37:51:8C:E0:98:F8:1B:36:2B:20:83:0D:C0\", \"expires\": \"2017-01-14T23:57:57Z\", \"starts\": \"2016-01-15T23:57:57Z\", \"issuer\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\", \"subject\": \"/C=US/ST=CA/L=San Francisco/O=Drycc/OU=Engineering/CN=bar.com/emailAddress=engineering@drycc.cc\" }","title":"Create Certificate"},{"location":"reference-guide/controller-api/v2.3/#destroy-a-certificate","text":"Example Request: DELETE /v2/certs/foo HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Destroy a Certificate"},{"location":"reference-guide/controller-api/v2.3/#attach-a-domain-to-a-certificate","text":"Example Request: POST /v2/certs/foo/domain/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"domain\": \"test.com\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Attach a Domain to a Certificate"},{"location":"reference-guide/controller-api/v2.3/#remove-a-domain-from-a-certificate","text":"Example Request: DELETE /v2/certs/foo/domain/test.com/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Remove a Domain from a Certificate"},{"location":"reference-guide/controller-api/v2.3/#enable-or-disable-tls","text":"Example Request: POST /v2/apps/example-go/tls/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 { \"https_enforced\": true } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"app\": \"example-go\", \"owner\": \"test\", \"https_enforced\": true, \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Enable or disable TLS"},{"location":"reference-guide/controller-api/v2.3/#get-tls-status","text":"Example Request: GET /v2/apps/example-go/tls/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"app\": \"example-go\", \"owner\": \"test\", \"https_enforced\": false, \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Get TLS status"},{"location":"reference-guide/controller-api/v2.3/#pods","text":"","title":"Pods"},{"location":"reference-guide/controller-api/v2.3/#list-all-pods","text":"Example Request: GET /v2/apps/example-go/pods/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] }","title":"List all Pods"},{"location":"reference-guide/controller-api/v2.3/#list-all-pods-by-type","text":"Example Request: GET /v2/apps/example-go/pods/web/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"results\": [ { \"name\": \"go-v2-web-e7dej\", \"release\": \"v2\", \"started\": \"2014-01-01T00:00:00Z\", \"state\": \"up\", \"type\": \"web\" } ] }","title":"List all Pods by Type"},{"location":"reference-guide/controller-api/v2.3/#restart-all-pods","text":"Example Request: POST /v2/apps/example-go/pods/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ]","title":"Restart All Pods"},{"location":"reference-guide/controller-api/v2.3/#restart-pods-by-type","text":"Example Request: POST /v2/apps/example-go/pods/web/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ]","title":"Restart Pods by Type"},{"location":"reference-guide/controller-api/v2.3/#restart-pods-by-type-and-name","text":"Example Request: POST /v2/apps/example-go/pods/go-v2-web-atots/restart/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json [ { \"name\": \"go-v2-web-atots\", \"release\": \"v2\", \"started\": \"2016-04-11T21:07:54Z\", \"state\": \"up\", \"type\": \"web\" } ]","title":"Restart Pods by Type and Name"},{"location":"reference-guide/controller-api/v2.3/#scale-pods","text":"Example Request: POST /v2/apps/example-go/scale/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"web\": 3} Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Scale Pods"},{"location":"reference-guide/controller-api/v2.3/#configuration","text":"","title":"Configuration"},{"location":"reference-guide/controller-api/v2.3/#list-application-configuration","text":"Example Request: GET /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"List Application Configuration"},{"location":"reference-guide/controller-api/v2.3/#create-new-config","text":"Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": \"world\", \"PLATFORM\": \"drycc\"}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v3\", \"HELLO\": \"world\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Create new Config"},{"location":"reference-guide/controller-api/v2.3/#unset-config-variable","text":"Example Request: POST /v2/apps/example-go/config/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"values\": {\"HELLO\": null}} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"owner\": \"test\", \"app\": \"example-go\", \"values\": { \"DRYCC_APP\": \"example-go\", \"DRYCC_RELEASE\": \"v4\", \"PLATFORM\": \"drycc\" }, \"memory\": {}, \"cpu\": {}, \"tags\": {}, \"healthcheck\": {}, \"created\": \"2014-01-01T00:00:00UTC\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Unset Config Variable"},{"location":"reference-guide/controller-api/v2.3/#domains","text":"","title":"Domains"},{"location":"reference-guide/controller-api/v2.3/#list-application-domains","text":"Example Request: GET /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" } ] }","title":"List Application Domains"},{"location":"reference-guide/controller-api/v2.3/#add-domain","text":"Example Request: POST /v2/apps/example-go/domains/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {'domain': 'example.example.com'} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"domain\": \"example.example.com\", \"owner\": \"test\", \"updated\": \"2014-01-01T00:00:00UTC\" }","title":"Add Domain"},{"location":"reference-guide/controller-api/v2.3/#remove-domain","text":"Example Request: DELETE /v2/apps/example-go/domains/example.example.com HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Remove Domain"},{"location":"reference-guide/controller-api/v2.3/#builds","text":"","title":"Builds"},{"location":"reference-guide/controller-api/v2.3/#list-application-builds","text":"Example Request: GET /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"FROM drycc/slugrunner RUN mkdir -p /app WORKDIR /app ENTRYPOINT [\\\"/runner/init\\\"] ADD slug.tgz /app ENV GIT_SHA 060da68f654e75fac06dbedd1995d5f8ad9084db\", \"image\": \"example-go\", \"owner\": \"test\", \"procfile\": { \"web\": \"example-go\" }, \"sha\": \"060da68f\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] }","title":"List Application Builds"},{"location":"reference-guide/controller-api/v2.3/#create-application-build","text":"Example Request: POST /v2/apps/example-go/builds/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"image\": \"drycc/example-go:latest\"} Optional Parameters: { \"procfile\": { \"web\": \"./cmd\" } } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"app\": \"example-go\", \"created\": \"2014-01-01T00:00:00UTC\", \"dockerfile\": \"\", \"image\": \"drycc/example-go:latest\", \"owner\": \"test\", \"procfile\": {}, \"sha\": \"\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Create Application Build"},{"location":"reference-guide/controller-api/v2.3/#releases","text":"","title":"Releases"},{"location":"reference-guide/controller-api/v2.3/#list-application-releases","text":"Example Request: GET /v2/apps/example-go/releases/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 3, \"next\": null, \"previous\": null, \"results\": [ { \"app\": \"example-go\", \"build\": \"2.3d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"ed637ceb-5d32-44bd-9406-d326a777a513\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test changed nothing\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 3 }, { \"app\": \"example-go\", \"build\": \"2.3d8e4b-600e-4425-a85c-ffc7ea607f61\", \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test deployed 060da68\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 2 }, { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 } ] }","title":"List Application Releases"},{"location":"reference-guide/controller-api/v2.3/#list-release-details","text":"Example Request: GET /v2/apps/example-go/releases/v2/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"app\": \"example-go\", \"build\": null, \"config\": \"95bd6dea-1685-4f78-a03d-fd7270b058d1\", \"created\": \"2014-01-01T00:00:00UTC\", \"owner\": \"test\", \"summary\": \"test created initial release\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\", \"version\": 1 }","title":"List Release Details"},{"location":"reference-guide/controller-api/v2.3/#rollback-release","text":"Example Request: POST /v2/apps/example-go/releases/rollback/ HTTP/1.1 Host: drycc.example.com Content-Type: application/json Authorization: token abc123 {\"version\": 1} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json {\"version\": 5}","title":"Rollback Release"},{"location":"reference-guide/controller-api/v2.3/#keys","text":"","title":"Keys"},{"location":"reference-guide/controller-api/v2.3/#list-keys","text":"Example Request: GET /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"test@example.com\", \"owner\": \"test\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" } ] }","title":"List Keys"},{"location":"reference-guide/controller-api/v2.3/#add-key-to-user","text":"Example Request: POST /v2/keys/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 { \"id\": \"example\", \"public\": \"ssh-rsa <...>\" } Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"created\": \"2014-01-01T00:00:00UTC\", \"id\": \"example\", \"owner\": \"example\", \"public\": \"ssh-rsa <...>\", \"updated\": \"2014-01-01T00:00:00UTC\", \"uuid\": \"de1bf5b5-4a72-4f94-a10c-d2a3741cdf75\" }","title":"Add Key to User"},{"location":"reference-guide/controller-api/v2.3/#remove-key-from-user","text":"Example Request: DELETE /v2/keys/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Remove Key from User"},{"location":"reference-guide/controller-api/v2.3/#permissions","text":"","title":"Permissions"},{"location":"reference-guide/controller-api/v2.3/#list-application-permissions","text":"note This does not include the app owner. Example Request: GET /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"users\": [ \"test\", \"foo\" ] }","title":"List Application Permissions"},{"location":"reference-guide/controller-api/v2.3/#create-application-permission","text":"Example Request: POST /v2/apps/example-go/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Create Application Permission"},{"location":"reference-guide/controller-api/v2.3/#remove-application-permission","text":"Example Request: DELETE /v2/apps/example-go/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Remove Application Permission"},{"location":"reference-guide/controller-api/v2.3/#list-administrators","text":"Example Request: GET /v2/admin/perms/ HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 2, \"next\": null \"previous\": null, \"results\": [ { \"username\": \"test\", \"is_superuser\": true }, { \"username\": \"foo\", \"is_superuser\": true } ] }","title":"List Administrators"},{"location":"reference-guide/controller-api/v2.3/#grant-user-administrative-privileges","text":"note This command requires administrative privileges Example Request: POST /v2/admin/perms HTTP/1.1 Host: drycc.example.com Authorization: token abc123 {\"username\": \"example\"} Example Response: HTTP/1.1 201 CREATED DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Grant User Administrative Privileges"},{"location":"reference-guide/controller-api/v2.3/#remove-users-administrative-privileges","text":"note This command requires administrative privileges Example Request: DELETE /v2/admin/perms/example HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 204 NO CONTENT DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0","title":"Remove User's Administrative Privileges"},{"location":"reference-guide/controller-api/v2.3/#users","text":"","title":"Users"},{"location":"reference-guide/controller-api/v2.3/#list-all-users","text":"note This command requires administrative privileges Example Request: GET /v2/users HTTP/1.1 Host: drycc.example.com Authorization: token abc123 Example Response: HTTP/1.1 200 OK DRYCC_API_VERSION: 2.3 DRYCC_PLATFORM_VERSION: 2.3.0 Content-Type: application/json { \"count\": 1, \"next\": null, \"previous\": null, \"results\": [ { \"id\": 1, \"last_login\": \"2014-10-19T22:01:00.601Z\", \"is_superuser\": true, \"username\": \"test\", \"first_name\": \"test\", \"last_name\": \"testerson\", \"email\": \"test@example.com\", \"is_staff\": true, \"is_active\": true, \"date_joined\": \"2014-10-19T22:01:00.601Z\", \"groups\": [], \"user_permissions\": [] } ] }","title":"List all users"},{"location":"roadmap/planning-process/","text":"Planning Process \u00b6 Drycc features a lightweight process that emphasizes openness and ensures every community member can be an integral part of planning for the future. The Role of Maintainers \u00b6 Maintainers lead the Drycc projects. Their duties include proposing the Roadmap, reviewing and integrating contributions and maintaining the vision of the project. Open Roadmap \u00b6 The Drycc Roadmap is a community document. While Maintainers propose the Roadmap, it gets discussed and refined in Release Planning Meetings. Contributing to the Roadmap \u00b6 Proposals and issues can be opened by anyone. Every member of the community is welcome to participate in the discussion by providing feedback and/or offering counter-proposals. Release Milestones \u00b6 The Roadmap gets delivered progressively via the Release Schedule . Releases are defined during Release Planning Meetings and managed using GitHub Milestones which track specific deliverables and work-in-progress. Release Planning Meetings \u00b6 Major decisions affecting the Roadmap are discussed during Release Planning Meetings on the first Thursday of each month, aligned with the Release Schedule . Release Planning Meetings are open to the public with access coordinated via the Drycc #community Slack channel . Notes from past meetings are below, along with links to a recording of the entire meeting on YouTube. Credits \u00b6 Thanks to Amy Lindburg and our friends at Podman for their inspiration.","title":"Planning Process"},{"location":"roadmap/planning-process/#planning-process","text":"Drycc features a lightweight process that emphasizes openness and ensures every community member can be an integral part of planning for the future.","title":"Planning Process"},{"location":"roadmap/planning-process/#the-role-of-maintainers","text":"Maintainers lead the Drycc projects. Their duties include proposing the Roadmap, reviewing and integrating contributions and maintaining the vision of the project.","title":"The Role of Maintainers"},{"location":"roadmap/planning-process/#open-roadmap","text":"The Drycc Roadmap is a community document. While Maintainers propose the Roadmap, it gets discussed and refined in Release Planning Meetings.","title":"Open Roadmap"},{"location":"roadmap/planning-process/#contributing-to-the-roadmap","text":"Proposals and issues can be opened by anyone. Every member of the community is welcome to participate in the discussion by providing feedback and/or offering counter-proposals.","title":"Contributing to the Roadmap"},{"location":"roadmap/planning-process/#release-milestones","text":"The Roadmap gets delivered progressively via the Release Schedule . Releases are defined during Release Planning Meetings and managed using GitHub Milestones which track specific deliverables and work-in-progress.","title":"Release Milestones"},{"location":"roadmap/planning-process/#release-planning-meetings","text":"Major decisions affecting the Roadmap are discussed during Release Planning Meetings on the first Thursday of each month, aligned with the Release Schedule . Release Planning Meetings are open to the public with access coordinated via the Drycc #community Slack channel . Notes from past meetings are below, along with links to a recording of the entire meeting on YouTube.","title":"Release Planning Meetings"},{"location":"roadmap/planning-process/#credits","text":"Thanks to Amy Lindburg and our friends at Podman for their inspiration.","title":"Credits"},{"location":"roadmap/releases/","text":"Releases \u00b6 Drycc uses a continuous delivery approach for creating releases. Every merged commit that passes testing results in a deliverable that can be given a semantic version tag and shipped. The master git branch of a project should always work. Only changes considered ready to be released publicly are merged. Components Release as Needed \u00b6 Drycc components release new versions as often as needed. Fixing a high priority bug requires the project maintainer to create a new patch release. Merging a backward-compatible feature implies a minor release. By releasing often, each component release becomes a safe and routine event. This makes it faster and easier for users to obtain specific fixes. Continuous delivery also reduces the work necessary to release a product such as Drycc Workflow, which integrates several components. \"Components\" applies not just to Drycc Workflow projects, but also to development and release tools, to Container base images, and to other Drycc projects that do semantic version releases. See \" How to Release a Component \" for more detail. Workflow Releases Each Month \u00b6 Drycc Workflow has a regular, public release cadence. From v2.8.0 onward, new Workflow feature releases arrive on the first Thursday of each month. Patch releases are created at any time, as needed. GitHub milestones are used to communicate the content and timing of major and minor releases, and longer-term planning is visible at the Roadmap . Workflow release timing is not linked to specific features. If a feature is merged before the release date, it is included in the next release. See \" How to Release Workflow \" for more detail. Semantic Versioning \u00b6 Drycc releases comply with semantic versioning , with the \"public API\" broadly defined as: REST, gRPC, or other API that is network-accessible Library or framework API intended for public use \"Pluggable\" socket-level protocols users can redirect CLI commands and output formats In general, changes to anything a user might reasonably link to, customize, or integrate with should be backward-compatible, or else require a major release. Drycc users can be confident that upgrading to a patch or to a minor release will not break anything. How to Release a Component \u00b6 Most Drycc projects are \"components\" which produce a Container image or binary executable as a deliverable. This section leads a maintainer through creating a component release. Step 1: Update Code and Run the Release Tool \u00b6 Major or minor releases should happen on the master branch. Patch releases should check out the previous release tag and cherry-pick specific commits from master. Note: if a patch release, the release artifact will have to be manually promoted by triggering the component-promote job with the following values: COMPONENT_NAME= COMPONENT_SHA= Make sure you have the dryccrel release tool in your search $PATH . Run dryccrel release once with a fake semver tag to proofread the changelog content. (If HEAD of master is not what is intended for the release, add the --sha flag as described in dryccrel release --help .) $ dryccrel release controller v0.0.0 Doing a dry run of the component release... skipping commit 943a49267eeb28546819a266654806cfcbae0e38 Creating changelog for controller with tag v2.8.1 through commit 943a49267eeb28546819a266654806cfcbae0e38 ### v2.8.1 -> v0.0.0 #### Fixes - [`615b834`](https://github.com/drycc/controller/commit/615b834f39cb68a854cc1f1e2f0f82d862ea2731) boot: Ensure DRYCC_DEBUG==true for debug output Based on the changelog content, determine whether the component deserves a minor or patch release. Run the command again with that semver tag and --dry-run=false . You will still be asked for confirmation before the release is created: $ dryccrel release controller v2.8.2 --dry-run=false skipping commit 943a49267eeb28546819a266654806cfcbae0e38 Creating changelog for controller with tag v2.8.1 through commit 943a49267eeb28546819a266654806cfcbae0e38 ### v2.8.1 -> v2.8.2 #### Fixes - [`615b834`](https://github.com/drycc/controller/commit/615b834f39cb68a854cc1f1e2f0f82d862ea2731) boot: Ensure DRYCC_DEBUG==true for debug output Please review the above changelog contents and ensure: 1. All intended commits are mentioned 2. The changes agree with the semver release tag (major, minor, or patch) Create release for Drycc Controller v2.8.2? [y/n]: y New release is available at https://github.com/drycc/controller/releases/tag/v2.8.2 Step 2: Verify the Component is Available \u00b6 Tagging the component (see Step 1 ) starts a CI job that eventually results in an artifact being made available for public download. Please see the CI flow diagrams for details. Double-check that the artifact is available, either by a podman pull command or by running the appropriate installer script. If the artifact can't be downloaded, ensure that its CI release jobs are still in progress, or fix whatever issue arose in the pipeline. For example, the master merge pipeline may have failed to promote the :git-abc1d23 candidate image and needs to be restarted with that component and commit. If the component has a correlating Kubernetes Helm chart, this chart will also be packaged, signed and uploaded to its production chart repo. Please verify it can be fetched (and verified): $ helm fetch oci://registry.drycc.cc/charts/controller --version 1.0.0 Verification: &{0xc4207ec870 sha256:026e766e918ff28d2a7041bc3d560d149ee7eb0cb84165c9d9d00a3045ff45c3 controller-v1.0.1.tgz} How to Release Workflow \u00b6 Drycc Workflow integrates multiple component releases together with a Kubernetes Helm chart deliverable. This section leads a maintainer through creating a Workflow release. Step 1: Set Environment Variables \u00b6 Export two environment variables that will be used in later steps: export WORKFLOW_RELEASE=v2.17.0 WORKFLOW_PREV_RELEASE=v2.16.0 # for example Step 2: Tag Supporting Repositories \u00b6 Some Workflow components not in the Helm chart must also be tagged in sync with the release. Follow the component release process above and ensure that these components are tagged: drycc/workflow-cli drycc/workflow-e2e The version number for drycc/workflow-cli should always match the overall Workflow version number. Step 3: Create Helm Chart \u00b6 To create and stage a release candidate chart for Workflow, we will build the workflow-chart-stage job with the following parameters: RELEASE_TAG=$WORKFLOW_RELEASE This job will gather all of the latest component release tags and use these to specify the versions of all component charts. It will then package the Workflow chart, upload it to the staging chart repo and kick off an e2e run against said chart. Step 4: Manual Testing \u00b6 Now it's time to go above and beyond current CI tests. Create a testing matrix spreadsheet (copying from the previous document is a good start) and sign up testers to cover all permutations. Testers should pay special attention to the overall user experience, make sure upgrading from earlier versions is smooth, and cover various storage configurations and Kubernetes versions and infrastructure providers. When showstopper-level bugs are found, the process is as follows: Create a component PR that fixes the bug. Once the PR passes and is reviewed, merge it and do a new component release Trigger the same workflow-chart-stage job as mentioned in Step 3 to upload the newly-generated Workflow release candidate chart to staging. Step 5: Release the Chart \u00b6 When testing has completed without uncovering any new showstopper bugs, kick off the workflow-chart-release job with the following parameter: RELEASE_TAG=$WORKFLOW_RELEASE This job will copy the release candidate chart (now approved by CI and manual testing) from the staging repo to the production repo, signing it if it has not done so already. Step 6: Assemble Master Changelog \u00b6 Each component already updated its release notes on GitHub with CHANGELOG content. We'll now generate the master changelog for the Workflow chart, consisting of all component and auxilliary repo changes. We'll employ the requirements.lock file from the WORKFLOW_PREV_RELEASE chart, as well as a repo-to-chart-name mapping file , this time invoking dryccrel changelog global to get all component changes between the chart versions existing in the WORKFLOW_PREV_RELEASE chart and the most recent releases existing in GitHub. (Therefore, if there are any unreleased commits in a component repo, they will not appear here): helm fetch --untar oci://registry.drycc.cc/charts/workflow --version $WORKFLOW_PREV_RELEASE dryccrel changelog global workflow/requirements.lock map.json > changelog-$WORKFLOW_RELEASE.md This master changelog should then be placed into a single gist. The file will also be added to the documentation update PR created in the next step. Step 7: Update Documentation \u00b6 Create a new pull request at drycc/workflow that updates version references to the new release. Use git grep $WORKFLOW_PREV_RELEASE to find any references, but be careful not to change CHANGELOG.md . Place the $WORKFLOW_RELEASE master changelog generated in Step 7 in the changelogs directory. Make sure to add a header to the page to make it clear that this is for a Workflow release, e.g.: ## Workflow v2.16.0 -> v2.17.0 Once the PR has been reviewed and merged, do a component release of drycc/workflow itself. The version number for drycc/workflow should always match the overall Workflow version number. Step 8: Close GitHub Milestones \u00b6 Create a pull request at seed-repo to close the release milestone and create the next one. When changes are merged to seed-repo, milestones on all relevant projects will be updated. If there are open issues attached to the milestone, move them to the next upcoming milestone before merging the pull request. Milestones map to Drycc Workflow releases in drycc/workflow . These milestones do not correspond to individual component release tags. Step 9: Release Workflow CLI Stable \u00b6 Now that the $WORKFLOW_RELEASE version of Workflow CLI has been vetted, we can push stable artifacts based on this version. Kick off https://ci.drycc.info/job/workflow-cli-build-stable/ with the TAG build parameter of $WORKFLOW_RELEASE and then verify stable artifacts are available and appropriately updated after the job completes: $ curl -sfL https://www.drycc.cc/install-cli.sh | bash - $ ./drycc version # (Should show $WORKFLOW_RELEASE) Step 10: Let Everyone Know \u00b6 Let the rest of the team know they can start blogging and tweeting about the new Workflow release. Post a message to the #company channel on Slack. Include a link to the released chart and to the master CHANGELOG: @here Drycc Workflow v2.17.0 is now live! Master CHANGELOG: https://drycc.info/docs/workflow/changelogs/v2.17.0/ You're done with the release. Nice job!","title":"Releases"},{"location":"roadmap/releases/#releases","text":"Drycc uses a continuous delivery approach for creating releases. Every merged commit that passes testing results in a deliverable that can be given a semantic version tag and shipped. The master git branch of a project should always work. Only changes considered ready to be released publicly are merged.","title":"Releases"},{"location":"roadmap/releases/#components-release-as-needed","text":"Drycc components release new versions as often as needed. Fixing a high priority bug requires the project maintainer to create a new patch release. Merging a backward-compatible feature implies a minor release. By releasing often, each component release becomes a safe and routine event. This makes it faster and easier for users to obtain specific fixes. Continuous delivery also reduces the work necessary to release a product such as Drycc Workflow, which integrates several components. \"Components\" applies not just to Drycc Workflow projects, but also to development and release tools, to Container base images, and to other Drycc projects that do semantic version releases. See \" How to Release a Component \" for more detail.","title":"Components Release as Needed"},{"location":"roadmap/releases/#workflow-releases-each-month","text":"Drycc Workflow has a regular, public release cadence. From v2.8.0 onward, new Workflow feature releases arrive on the first Thursday of each month. Patch releases are created at any time, as needed. GitHub milestones are used to communicate the content and timing of major and minor releases, and longer-term planning is visible at the Roadmap . Workflow release timing is not linked to specific features. If a feature is merged before the release date, it is included in the next release. See \" How to Release Workflow \" for more detail.","title":"Workflow Releases Each Month"},{"location":"roadmap/releases/#semantic-versioning","text":"Drycc releases comply with semantic versioning , with the \"public API\" broadly defined as: REST, gRPC, or other API that is network-accessible Library or framework API intended for public use \"Pluggable\" socket-level protocols users can redirect CLI commands and output formats In general, changes to anything a user might reasonably link to, customize, or integrate with should be backward-compatible, or else require a major release. Drycc users can be confident that upgrading to a patch or to a minor release will not break anything.","title":"Semantic Versioning"},{"location":"roadmap/releases/#how-to-release-a-component","text":"Most Drycc projects are \"components\" which produce a Container image or binary executable as a deliverable. This section leads a maintainer through creating a component release.","title":"How to Release a Component"},{"location":"roadmap/releases/#step-1-update-code-and-run-the-release-tool","text":"Major or minor releases should happen on the master branch. Patch releases should check out the previous release tag and cherry-pick specific commits from master. Note: if a patch release, the release artifact will have to be manually promoted by triggering the component-promote job with the following values: COMPONENT_NAME= COMPONENT_SHA= Make sure you have the dryccrel release tool in your search $PATH . Run dryccrel release once with a fake semver tag to proofread the changelog content. (If HEAD of master is not what is intended for the release, add the --sha flag as described in dryccrel release --help .) $ dryccrel release controller v0.0.0 Doing a dry run of the component release... skipping commit 943a49267eeb28546819a266654806cfcbae0e38 Creating changelog for controller with tag v2.8.1 through commit 943a49267eeb28546819a266654806cfcbae0e38 ### v2.8.1 -> v0.0.0 #### Fixes - [`615b834`](https://github.com/drycc/controller/commit/615b834f39cb68a854cc1f1e2f0f82d862ea2731) boot: Ensure DRYCC_DEBUG==true for debug output Based on the changelog content, determine whether the component deserves a minor or patch release. Run the command again with that semver tag and --dry-run=false . You will still be asked for confirmation before the release is created: $ dryccrel release controller v2.8.2 --dry-run=false skipping commit 943a49267eeb28546819a266654806cfcbae0e38 Creating changelog for controller with tag v2.8.1 through commit 943a49267eeb28546819a266654806cfcbae0e38 ### v2.8.1 -> v2.8.2 #### Fixes - [`615b834`](https://github.com/drycc/controller/commit/615b834f39cb68a854cc1f1e2f0f82d862ea2731) boot: Ensure DRYCC_DEBUG==true for debug output Please review the above changelog contents and ensure: 1. All intended commits are mentioned 2. The changes agree with the semver release tag (major, minor, or patch) Create release for Drycc Controller v2.8.2? [y/n]: y New release is available at https://github.com/drycc/controller/releases/tag/v2.8.2","title":"Step 1: Update Code and Run the Release Tool"},{"location":"roadmap/releases/#step-2-verify-the-component-is-available","text":"Tagging the component (see Step 1 ) starts a CI job that eventually results in an artifact being made available for public download. Please see the CI flow diagrams for details. Double-check that the artifact is available, either by a podman pull command or by running the appropriate installer script. If the artifact can't be downloaded, ensure that its CI release jobs are still in progress, or fix whatever issue arose in the pipeline. For example, the master merge pipeline may have failed to promote the :git-abc1d23 candidate image and needs to be restarted with that component and commit. If the component has a correlating Kubernetes Helm chart, this chart will also be packaged, signed and uploaded to its production chart repo. Please verify it can be fetched (and verified): $ helm fetch oci://registry.drycc.cc/charts/controller --version 1.0.0 Verification: &{0xc4207ec870 sha256:026e766e918ff28d2a7041bc3d560d149ee7eb0cb84165c9d9d00a3045ff45c3 controller-v1.0.1.tgz}","title":"Step 2: Verify the Component is Available"},{"location":"roadmap/releases/#how-to-release-workflow","text":"Drycc Workflow integrates multiple component releases together with a Kubernetes Helm chart deliverable. This section leads a maintainer through creating a Workflow release.","title":"How to Release Workflow"},{"location":"roadmap/releases/#step-1-set-environment-variables","text":"Export two environment variables that will be used in later steps: export WORKFLOW_RELEASE=v2.17.0 WORKFLOW_PREV_RELEASE=v2.16.0 # for example","title":"Step 1: Set Environment Variables"},{"location":"roadmap/releases/#step-2-tag-supporting-repositories","text":"Some Workflow components not in the Helm chart must also be tagged in sync with the release. Follow the component release process above and ensure that these components are tagged: drycc/workflow-cli drycc/workflow-e2e The version number for drycc/workflow-cli should always match the overall Workflow version number.","title":"Step 2: Tag Supporting Repositories"},{"location":"roadmap/releases/#step-3-create-helm-chart","text":"To create and stage a release candidate chart for Workflow, we will build the workflow-chart-stage job with the following parameters: RELEASE_TAG=$WORKFLOW_RELEASE This job will gather all of the latest component release tags and use these to specify the versions of all component charts. It will then package the Workflow chart, upload it to the staging chart repo and kick off an e2e run against said chart.","title":"Step 3: Create Helm Chart"},{"location":"roadmap/releases/#step-4-manual-testing","text":"Now it's time to go above and beyond current CI tests. Create a testing matrix spreadsheet (copying from the previous document is a good start) and sign up testers to cover all permutations. Testers should pay special attention to the overall user experience, make sure upgrading from earlier versions is smooth, and cover various storage configurations and Kubernetes versions and infrastructure providers. When showstopper-level bugs are found, the process is as follows: Create a component PR that fixes the bug. Once the PR passes and is reviewed, merge it and do a new component release Trigger the same workflow-chart-stage job as mentioned in Step 3 to upload the newly-generated Workflow release candidate chart to staging.","title":"Step 4: Manual Testing"},{"location":"roadmap/releases/#step-5-release-the-chart","text":"When testing has completed without uncovering any new showstopper bugs, kick off the workflow-chart-release job with the following parameter: RELEASE_TAG=$WORKFLOW_RELEASE This job will copy the release candidate chart (now approved by CI and manual testing) from the staging repo to the production repo, signing it if it has not done so already.","title":"Step 5: Release the Chart"},{"location":"roadmap/releases/#step-6-assemble-master-changelog","text":"Each component already updated its release notes on GitHub with CHANGELOG content. We'll now generate the master changelog for the Workflow chart, consisting of all component and auxilliary repo changes. We'll employ the requirements.lock file from the WORKFLOW_PREV_RELEASE chart, as well as a repo-to-chart-name mapping file , this time invoking dryccrel changelog global to get all component changes between the chart versions existing in the WORKFLOW_PREV_RELEASE chart and the most recent releases existing in GitHub. (Therefore, if there are any unreleased commits in a component repo, they will not appear here): helm fetch --untar oci://registry.drycc.cc/charts/workflow --version $WORKFLOW_PREV_RELEASE dryccrel changelog global workflow/requirements.lock map.json > changelog-$WORKFLOW_RELEASE.md This master changelog should then be placed into a single gist. The file will also be added to the documentation update PR created in the next step.","title":"Step 6: Assemble Master Changelog"},{"location":"roadmap/releases/#step-7-update-documentation","text":"Create a new pull request at drycc/workflow that updates version references to the new release. Use git grep $WORKFLOW_PREV_RELEASE to find any references, but be careful not to change CHANGELOG.md . Place the $WORKFLOW_RELEASE master changelog generated in Step 7 in the changelogs directory. Make sure to add a header to the page to make it clear that this is for a Workflow release, e.g.: ## Workflow v2.16.0 -> v2.17.0 Once the PR has been reviewed and merged, do a component release of drycc/workflow itself. The version number for drycc/workflow should always match the overall Workflow version number.","title":"Step 7: Update Documentation"},{"location":"roadmap/releases/#step-8-close-github-milestones","text":"Create a pull request at seed-repo to close the release milestone and create the next one. When changes are merged to seed-repo, milestones on all relevant projects will be updated. If there are open issues attached to the milestone, move them to the next upcoming milestone before merging the pull request. Milestones map to Drycc Workflow releases in drycc/workflow . These milestones do not correspond to individual component release tags.","title":"Step 8: Close GitHub Milestones"},{"location":"roadmap/releases/#step-9-release-workflow-cli-stable","text":"Now that the $WORKFLOW_RELEASE version of Workflow CLI has been vetted, we can push stable artifacts based on this version. Kick off https://ci.drycc.info/job/workflow-cli-build-stable/ with the TAG build parameter of $WORKFLOW_RELEASE and then verify stable artifacts are available and appropriately updated after the job completes: $ curl -sfL https://www.drycc.cc/install-cli.sh | bash - $ ./drycc version # (Should show $WORKFLOW_RELEASE)","title":"Step 9: Release Workflow CLI Stable"},{"location":"roadmap/releases/#step-10-let-everyone-know","text":"Let the rest of the team know they can start blogging and tweeting about the new Workflow release. Post a message to the #company channel on Slack. Include a link to the released chart and to the master CHANGELOG: @here Drycc Workflow v2.17.0 is now live! Master CHANGELOG: https://drycc.info/docs/workflow/changelogs/v2.17.0/ You're done with the release. Nice job!","title":"Step 10: Let Everyone Know"},{"location":"roadmap/roadmap/","text":"Drycc Workflow Roadmap \u00b6 The Drycc Workflow Roadmap is a community document created as part of the open Planning Process . Each roadmap item describes a high-level capability or grouping of features that are deemed important to the future of Drycc. Given the project's rapid Release Schedule , roadmap items are designed to provide a sense of direction over many releases. Interactive drycc run /bin/bash \u00b6 Provide the ability for developers to launch an interactive terminal session in their application environment. Related issues: https://github.com/drycc/workflow-cli/issues/28 https://github.com/drycc/drycc/issues/117 Log Streaming \u00b6 Stream application logs via drycc logs -f https://github.com/drycc/drycc/issues/465 Teams and Permissions \u00b6 Teams and Permissions represents a more flexible permissions model to allow more nuanced control to applications, capabilities and resources on the platform. There have been a number of proposals in this area which need to be reconciled for Drycc Workflow before we begin implementation. Related issues: Deploy Keys: https://github.com/drycc/drycc/issues/3875 Teams: https://github.com/drycc/drycc/issues/4173 Fine grained permissions: https://github.com/drycc/drycc/issues/4150 Admins create apps only: https://github.com/drycc/drycc/issues/4052 Admin Certificate Permissions: https://github.com/drycc/drycc/issues/4576#issuecomment-170987223 Monitoring \u00b6 Define and deliver alerts with Kapacitor: https://github.com/drycc/monitor/issues/44 Workflow Addons/Services \u00b6 Developers should be able to quickly and easily provision application dependencies using a services or addon abstraction. https://github.com/drycc/drycc/issues/231 Inbound/Outbound Webhooks \u00b6 Drycc Workflow should be able to send and receive webhooks from external systems. Facilitating integration with third party services like GitHub, Gitlab, Slack, Hipchat. Send webhook on platform events: https://github.com/drycc/drycc/issues/1486 (Workflow v2.10)","title":"Roadmap"},{"location":"roadmap/roadmap/#drycc-workflow-roadmap","text":"The Drycc Workflow Roadmap is a community document created as part of the open Planning Process . Each roadmap item describes a high-level capability or grouping of features that are deemed important to the future of Drycc. Given the project's rapid Release Schedule , roadmap items are designed to provide a sense of direction over many releases.","title":"Drycc Workflow Roadmap"},{"location":"roadmap/roadmap/#interactive-drycc-run-binbash","text":"Provide the ability for developers to launch an interactive terminal session in their application environment. Related issues: https://github.com/drycc/workflow-cli/issues/28 https://github.com/drycc/drycc/issues/117","title":"Interactive drycc run /bin/bash"},{"location":"roadmap/roadmap/#log-streaming","text":"Stream application logs via drycc logs -f https://github.com/drycc/drycc/issues/465","title":"Log Streaming"},{"location":"roadmap/roadmap/#teams-and-permissions","text":"Teams and Permissions represents a more flexible permissions model to allow more nuanced control to applications, capabilities and resources on the platform. There have been a number of proposals in this area which need to be reconciled for Drycc Workflow before we begin implementation. Related issues: Deploy Keys: https://github.com/drycc/drycc/issues/3875 Teams: https://github.com/drycc/drycc/issues/4173 Fine grained permissions: https://github.com/drycc/drycc/issues/4150 Admins create apps only: https://github.com/drycc/drycc/issues/4052 Admin Certificate Permissions: https://github.com/drycc/drycc/issues/4576#issuecomment-170987223","title":"Teams and Permissions"},{"location":"roadmap/roadmap/#monitoring","text":"Define and deliver alerts with Kapacitor: https://github.com/drycc/monitor/issues/44","title":"Monitoring"},{"location":"roadmap/roadmap/#workflow-addonsservices","text":"Developers should be able to quickly and easily provision application dependencies using a services or addon abstraction. https://github.com/drycc/drycc/issues/231","title":"Workflow Addons/Services"},{"location":"roadmap/roadmap/#inboundoutbound-webhooks","text":"Drycc Workflow should be able to send and receive webhooks from external systems. Facilitating integration with third party services like GitHub, Gitlab, Slack, Hipchat. Send webhook on platform events: https://github.com/drycc/drycc/issues/1486 (Workflow v2.10)","title":"Inbound/Outbound Webhooks"},{"location":"troubleshooting/","text":"Troubleshooting Workflow \u00b6 Common issues that users have run into when provisioning Workflow are detailed below. A Component Fails to Start \u00b6 For information on troubleshooting a failing component, see Troubleshooting with Kubectl . An Application Fails to Start \u00b6 For information on troubleshooting application deployment issues, see Troubleshooting Applications . Permission denied (publickey) \u00b6 The most common problem for this issue is the user forgetting to run drycc keys:add or add their private key to their SSH agent. To do so, run ssh-add ~/.ssh/id_rsa and try running git push drycc master again. If you happen get a Could not open a connection to your authentication agent error after trying to run ssh-add command above, you may need to load the SSH agent environment variables issuing the eval \"$(ssh-agent)\" command before. Other Issues \u00b6 Running into something not detailed here? Please open an issue or hop into #community on Slack for help!","title":"Troubleshooting Workflow"},{"location":"troubleshooting/#troubleshooting-workflow","text":"Common issues that users have run into when provisioning Workflow are detailed below.","title":"Troubleshooting Workflow"},{"location":"troubleshooting/#a-component-fails-to-start","text":"For information on troubleshooting a failing component, see Troubleshooting with Kubectl .","title":"A Component Fails to Start"},{"location":"troubleshooting/#an-application-fails-to-start","text":"For information on troubleshooting application deployment issues, see Troubleshooting Applications .","title":"An Application Fails to Start"},{"location":"troubleshooting/#permission-denied-publickey","text":"The most common problem for this issue is the user forgetting to run drycc keys:add or add their private key to their SSH agent. To do so, run ssh-add ~/.ssh/id_rsa and try running git push drycc master again. If you happen get a Could not open a connection to your authentication agent error after trying to run ssh-add command above, you may need to load the SSH agent environment variables issuing the eval \"$(ssh-agent)\" command before.","title":"Permission denied (publickey)"},{"location":"troubleshooting/#other-issues","text":"Running into something not detailed here? Please open an issue or hop into #community on Slack for help!","title":"Other Issues"},{"location":"troubleshooting/applications/","text":"Troubleshooting Applications \u00b6 This document describes how one can troubleshoot common issues when deploying or debugging an application that fails to start or deploy. Application has a Dockerfile, but a Buildpack Deployment Occurs \u00b6 When you deploy an application to Workflow using git push drycc master and the Builder attempts to deploy using the Buildpack workflow, check the following steps: Are you deploying the correct project? Are you pushing the correct git branch ( git push drycc )? Is the Dockerfile in the project's root directory? Have you committed the Dockerfile to the project? Application was Deployed, but is Failing to Start \u00b6 If you deployed your application but it is failing to start, you can use drycc logs to check why the application fails to boot. Sometimes, the application container may fail to boot without logging any information about the error. This typically occurs when the healthcheck configured for the application fails. In this case, you can start by troubleshooting using kubectl . You can inspect the application's current state by examining the pod deployed in the application's namespace. To do that, run $ kubectl --namespace=myapp get pods NAME READY STATUS RESTARTS AGE myapp-cmd-1585713350-3brbo 0/1 CrashLoopBackOff 2 43s We can then describe the pod and determine why it is failing to boot: Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 43s 43s 1 {default-scheduler } Normal Scheduled Successfully assigned myapp-cmd-1585713350-3brbo to kubernetes-node-1 41s 41s 1 {kubelet kubernetes-node-1} spec.containers{myapp-cmd} Normal Created Created container with container id b86bd851a61f 41s 41s 1 {kubelet kubernetes-node-1} spec.containers{myapp-cmd} Normal Started Started container with container id b86bd851a61f 37s 35s 1 {kubelet kubernetes-node-1} spec.containers{myapp-cmd} Warning Unhealthy Liveness probe failed: Get http://10.246.39.13:8000/healthz: dial tcp 10.246.39.13:8000: getsockopt: connection refused In this instance, we set the healthcheck initial delay timeout for the application at 1 second, which is too aggressive. The application needs some time to set up the API server after the container has booted. By increasing the healthcheck initial delay timeout to 10 seconds, the application is able to boot and is responding correctly. See Custom Health Checks for more information on how to customize the application's health checks to better suit the application's needs.","title":"Troubleshooting Applications"},{"location":"troubleshooting/applications/#troubleshooting-applications","text":"This document describes how one can troubleshoot common issues when deploying or debugging an application that fails to start or deploy.","title":"Troubleshooting Applications"},{"location":"troubleshooting/applications/#application-has-a-dockerfile-but-a-buildpack-deployment-occurs","text":"When you deploy an application to Workflow using git push drycc master and the Builder attempts to deploy using the Buildpack workflow, check the following steps: Are you deploying the correct project? Are you pushing the correct git branch ( git push drycc )? Is the Dockerfile in the project's root directory? Have you committed the Dockerfile to the project?","title":"Application has a Dockerfile, but a Buildpack Deployment Occurs"},{"location":"troubleshooting/applications/#application-was-deployed-but-is-failing-to-start","text":"If you deployed your application but it is failing to start, you can use drycc logs to check why the application fails to boot. Sometimes, the application container may fail to boot without logging any information about the error. This typically occurs when the healthcheck configured for the application fails. In this case, you can start by troubleshooting using kubectl . You can inspect the application's current state by examining the pod deployed in the application's namespace. To do that, run $ kubectl --namespace=myapp get pods NAME READY STATUS RESTARTS AGE myapp-cmd-1585713350-3brbo 0/1 CrashLoopBackOff 2 43s We can then describe the pod and determine why it is failing to boot: Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 43s 43s 1 {default-scheduler } Normal Scheduled Successfully assigned myapp-cmd-1585713350-3brbo to kubernetes-node-1 41s 41s 1 {kubelet kubernetes-node-1} spec.containers{myapp-cmd} Normal Created Created container with container id b86bd851a61f 41s 41s 1 {kubelet kubernetes-node-1} spec.containers{myapp-cmd} Normal Started Started container with container id b86bd851a61f 37s 35s 1 {kubelet kubernetes-node-1} spec.containers{myapp-cmd} Warning Unhealthy Liveness probe failed: Get http://10.246.39.13:8000/healthz: dial tcp 10.246.39.13:8000: getsockopt: connection refused In this instance, we set the healthcheck initial delay timeout for the application at 1 second, which is too aggressive. The application needs some time to set up the API server after the container has booted. By increasing the healthcheck initial delay timeout to 10 seconds, the application is able to boot and is responding correctly. See Custom Health Checks for more information on how to customize the application's health checks to better suit the application's needs.","title":"Application was Deployed, but is Failing to Start"},{"location":"troubleshooting/kubectl/","text":"Troubleshooting using Kubectl \u00b6 This document describes how one can use kubectl to debug any issues with the cluster. Diving into the Components \u00b6 Using kubectl , one can inspect the cluster's current state. When Workflow is installed with helm , Workflow is installed into the drycc namespace. To inspect if Workflow is running, run: $ kubectl --namespace=drycc get pods NAME READY STATUS RESTARTS AGE drycc-builder-gqum7 0/1 ContainerCreating 0 4s drycc-controller-h6lk6 0/1 ContainerCreating 0 4s drycc-controller-celery-cmxxn 0/3 ContainerCreating 0 4s drycc-database-56v39 0/1 ContainerCreating 0 4s drycc-logger-fluentbit-xihr1 0/1 Pending 0 2s drycc-logger-grupg 0/1 ContainerCreating 0 3s drycc-storage-c2exb 0/1 Pending 0 3s drycc-monitor-grafana-9ccur 0/1 Pending 0 3s drycc-monitor-telegraf-dc3y3 0/1 Pending 0 2s drycc-registry-5bor6 0/1 Pending 0 3s drycc-rabbitmq-0 0/1 ContainerCreating 0 3s Tip To save precious keystrokes, alias kubectl --namespace=drycc to kd so it is easier to type in the future. To fetch the logs of a specific component, use kubectl logs : $ kubectl --namespace=drycc logs drycc-controller-h6lk6 system information: Django Version: 1.9.6 Python 3.5.1 addgroup: gid '0' in use Django checks: System check identified no issues (2 silenced). [...] To dive into a running container to inspect its environment, use kubectl exec : $ kubectl --namespace=drycc exec -it drycc-database-56v39 gosu postgres psql psql (13.4 (Debian 13.4-1.pgdg100+1)) Type \"help\" for help. postgres=# \\l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -------------------+----------+----------+------------+------------+----------------------- drycc_controller | postgres | UTF8 | en_US.utf8 | en_US.utf8 | drycc_passport | postgres | UTF8 | en_US.utf8 | en_US.utf8 | postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + | | | | | postgres=CTc/postgres (4 rows) postgres=# \\connect drycc_controller You are now connected to database \"drycc_controller\" as user \"postgres\". drycc_controller=# \\dt List of relations Schema | Name | Type | Owner --------+--------------------------------+-------+------------------- public | api_app | table | drycc_controller public | api_build | table | drycc_controller public | api_certificate | table | drycc_controller public | api_config | table | drycc_controller public | api_domain | table | drycc_controller public | api_key | table | drycc_controller public | api_push | table | drycc_controller public | api_release | table | drycc_controller public | auth_group | table | drycc_controller --More-- drycc_controller=# SELECT COUNT(*) from api_app; count ------- 0 (1 row)","title":"Troubleshooting using Kubectl"},{"location":"troubleshooting/kubectl/#troubleshooting-using-kubectl","text":"This document describes how one can use kubectl to debug any issues with the cluster.","title":"Troubleshooting using Kubectl"},{"location":"troubleshooting/kubectl/#diving-into-the-components","text":"Using kubectl , one can inspect the cluster's current state. When Workflow is installed with helm , Workflow is installed into the drycc namespace. To inspect if Workflow is running, run: $ kubectl --namespace=drycc get pods NAME READY STATUS RESTARTS AGE drycc-builder-gqum7 0/1 ContainerCreating 0 4s drycc-controller-h6lk6 0/1 ContainerCreating 0 4s drycc-controller-celery-cmxxn 0/3 ContainerCreating 0 4s drycc-database-56v39 0/1 ContainerCreating 0 4s drycc-logger-fluentbit-xihr1 0/1 Pending 0 2s drycc-logger-grupg 0/1 ContainerCreating 0 3s drycc-storage-c2exb 0/1 Pending 0 3s drycc-monitor-grafana-9ccur 0/1 Pending 0 3s drycc-monitor-telegraf-dc3y3 0/1 Pending 0 2s drycc-registry-5bor6 0/1 Pending 0 3s drycc-rabbitmq-0 0/1 ContainerCreating 0 3s Tip To save precious keystrokes, alias kubectl --namespace=drycc to kd so it is easier to type in the future. To fetch the logs of a specific component, use kubectl logs : $ kubectl --namespace=drycc logs drycc-controller-h6lk6 system information: Django Version: 1.9.6 Python 3.5.1 addgroup: gid '0' in use Django checks: System check identified no issues (2 silenced). [...] To dive into a running container to inspect its environment, use kubectl exec : $ kubectl --namespace=drycc exec -it drycc-database-56v39 gosu postgres psql psql (13.4 (Debian 13.4-1.pgdg100+1)) Type \"help\" for help. postgres=# \\l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -------------------+----------+----------+------------+------------+----------------------- drycc_controller | postgres | UTF8 | en_US.utf8 | en_US.utf8 | drycc_passport | postgres | UTF8 | en_US.utf8 | en_US.utf8 | postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + | | | | | postgres=CTc/postgres (4 rows) postgres=# \\connect drycc_controller You are now connected to database \"drycc_controller\" as user \"postgres\". drycc_controller=# \\dt List of relations Schema | Name | Type | Owner --------+--------------------------------+-------+------------------- public | api_app | table | drycc_controller public | api_build | table | drycc_controller public | api_certificate | table | drycc_controller public | api_config | table | drycc_controller public | api_domain | table | drycc_controller public | api_key | table | drycc_controller public | api_push | table | drycc_controller public | api_release | table | drycc_controller public | auth_group | table | drycc_controller --More-- drycc_controller=# SELECT COUNT(*) from api_app; count ------- 0 (1 row)","title":"Diving into the Components"},{"location":"understanding-workflow/architecture/","text":"Architecture \u00b6 Drycc Workflow is built using a service oriented architecture. All components are published as a set of container images which can be deployed to any compliant Kubernetes cluster. Overview \u00b6 Operators use Helm to configure and install the Workflow components which interface directly with the underlying Kubernetes cluster. Service discovery, container availability and networking are all delegated to Kubernetes, while Workflow provides a clean and simple developer experience. Platform Services \u00b6 Drycc Workflow provides additional functionality to your Kubernetes cluster, including: Source to Image Builder which compiles your Application code via Buildpacks or Dockerfiles Cross-Pod Log Aggregation which gathers logs from all of your Application processes Simple REST API which powers the CLI and any external integrations Application release and rollback Authentication and Authorization to Application resources HTTP/HTTPS edge routing for your Applications Kubernetes-Native \u00b6 All platform components and applications deployed via Workflow expect to be running on an existing Kubernetes cluster. This means that you can happily run your Kubernetes-native workloads next to applications that are managed through Drycc Workflow. Application Layout and Edge Routing \u00b6 By default Workflow creates per-application Namespaces and Services so you can easily connect your applications to other on-cluster services through standard Kubernetes mechanisms. The router component is responsible for routing HTTP/s traffic to your Applications as well as proxying git push and platform API traffic. By default, the router component is deployed as a Kubernetes service with type LoadBalancer ; which, depending on your configuration, will provision a cloud-native load balancer automatically. The router automatically discovers routable Applications, SSL/TLS certificates and application-specific configurations through the use of Kubernetes annotations. Any changes to router configuration or certificates are applied within seconds. Topologies \u00b6 Drycc Workflow no longer dictates a specific topology or server count for your deployment. The platform components will happily run on single-server configurations as well as multi-server production clusters.","title":"Architecture"},{"location":"understanding-workflow/architecture/#architecture","text":"Drycc Workflow is built using a service oriented architecture. All components are published as a set of container images which can be deployed to any compliant Kubernetes cluster.","title":"Architecture"},{"location":"understanding-workflow/architecture/#overview","text":"Operators use Helm to configure and install the Workflow components which interface directly with the underlying Kubernetes cluster. Service discovery, container availability and networking are all delegated to Kubernetes, while Workflow provides a clean and simple developer experience.","title":"Overview"},{"location":"understanding-workflow/architecture/#platform-services","text":"Drycc Workflow provides additional functionality to your Kubernetes cluster, including: Source to Image Builder which compiles your Application code via Buildpacks or Dockerfiles Cross-Pod Log Aggregation which gathers logs from all of your Application processes Simple REST API which powers the CLI and any external integrations Application release and rollback Authentication and Authorization to Application resources HTTP/HTTPS edge routing for your Applications","title":"Platform Services"},{"location":"understanding-workflow/architecture/#kubernetes-native","text":"All platform components and applications deployed via Workflow expect to be running on an existing Kubernetes cluster. This means that you can happily run your Kubernetes-native workloads next to applications that are managed through Drycc Workflow.","title":"Kubernetes-Native"},{"location":"understanding-workflow/architecture/#application-layout-and-edge-routing","text":"By default Workflow creates per-application Namespaces and Services so you can easily connect your applications to other on-cluster services through standard Kubernetes mechanisms. The router component is responsible for routing HTTP/s traffic to your Applications as well as proxying git push and platform API traffic. By default, the router component is deployed as a Kubernetes service with type LoadBalancer ; which, depending on your configuration, will provision a cloud-native load balancer automatically. The router automatically discovers routable Applications, SSL/TLS certificates and application-specific configurations through the use of Kubernetes annotations. Any changes to router configuration or certificates are applied within seconds.","title":"Application Layout and Edge Routing"},{"location":"understanding-workflow/architecture/#topologies","text":"Drycc Workflow no longer dictates a specific topology or server count for your deployment. The platform components will happily run on single-server configurations as well as multi-server production clusters.","title":"Topologies"},{"location":"understanding-workflow/components/","text":"Components \u00b6 Workflow is comprised of a number of small, independent services that combine to create a distributed PaaS. All Workflow components are deployed as services (and associated controllers) in your Kubernetes cluster. If you are interested we have a more detailed exploration of the Workflow architecture . All of the componentry for Workflow is built with composability in mind. If you need to customize one of the components for your specific deployment or need the functionality in your own project we invite you to give it a shot! Controller \u00b6 Project Location: drycc/controller The controller component is an HTTP API server which serves as the endpoint for the drycc CLI. The controller provides all of the platform functionality as well as interfacing with your Kubernetes cluster. The controller persists all of its data to the database component. Passport \u00b6 Project Location: drycc/passport The passport component exposes a web API and provide OAuth2 authentication. Database \u00b6 Project Location: drycc/postgres The database component is a managed instance of PostgreSQL which holds a majority of the platforms state. Backups and WAL files are pushed to object storage via WAL-E . When the database is restarted, backups are fetched and replayed from object storage so no data is lost. Builder \u00b6 Project Location: drycc/builder The builder component is responsible for accepting code pushes via Git and managing the build process of your Application . The builder process is: Receives incoming git push requests over SSH Authenticates the user via SSH key fingerprint Authorizes the user's access to push code to the Application Starts the Application Build phase (see below) Triggers a new Release via the Controller Builder currently supports both buildpack and Dockerfile based builds. Project Location: drycc/imagebuilder For Buildpack-based deploys, the builder component will launch a one-shot Job in the drycc namespace. This job runs imagebuilder component which handles default and custom buildpacks (specified by .packbuilder ). The completed image is pushed to the managed Container registry on cluster. For more information about buildpacks see using buildpacks . Unlike buildpack-based, For Applications which contain a Dockerfile in the root of the repository, it generates a Container image (using the underlying Container engine). For more information see using Dockerfiles . Object Storage \u00b6 Project Location: drycc/storage All of the Workflow components that need to persist data will ship them to the object storage that was configured for the cluster.For example, database ships its WAL files, registry stores Container images, and slugbuilder stores slugs. Workflow supports either on or off-cluster storage. For production deployments we highly recommend that you configure off-cluster object storage . To facilitate experimentation, development and test environments, the default charts for Workflow include on-cluster storage via storage . If you also feel comfortable using Kubernetes persistent volumes you may configure storage to use persistent storage available in your environment. Registry \u00b6 Project Location: drycc/registry The registry component is a managed container registry which holds application images generated from the builder component. Registry persists the Container image images to either local storage (in development mode) or to object storage configured for the cluster. Logger: fluentbit, logger \u00b6 The logging subsystem consists of two components. Fluentbit handles log shipping and logger maintains a ring-buffer of application logs. Project Location: drycc/fluentbit Fluentbit is deployed to your Kubernetes cluster via Daemon Sets. Fluentbit subscribes to all container logs, decorates the output with Kubernetes metadata and can be configured to drain logs to multiple destinations. By default, Fluentbit ships logs to the logger component, which powers drycc logs . Project Location: drycc/logger The logger component receives log streams from fluentbit , collating by Application name. Logger does not persist logs to disk, instead maintaining an in-memory ring buffer. For more information on logger see the project documentation . Monitor \u00b6 Project Location: drycc/monitor The monitoring subsystem consists of two components: Telegraf and Grafana. Telegraf is the is the metrics collection agent that runs using the daemon set API. It runs on every worker node in the cluster, fetches information about the pods currently running and ships it to Prometheus. Grafana is a standalone graphing application. It natively supports Prometheus as a datasource and provides a robust engine for creating dashboards on top of timeseries data. Workflow provides a few dashboards out of the box for monitoring Drycc Workflow and Kubernetes. The dashboards can be used as a starting point for creating more custom dashboards to suit a user's needs. Prometheus \u00b6 Project Location: drycc/prometheus Prometheus is a system monitoring and alerting system. It was opensourced by SoundCloud in 2012 and is the second project both to join and to graduate within Cloud Native Computing Foundation after Kubernetes. Prometheus stores all metrics data as time series, i.e metrics information is stored along with the timestamp at which it was recorded, optional key-value pairs called as labels can also be stored along with metrics. Rabbitmq \u00b6 Project Location: drycc/rabbitmq RabbitMQ is the most widely deployed open source message broker. Controller use celery with rabbitMQ to execute the asynchronous task. HelmBroker \u00b6 Project Location: drycc/rabbitmq Helm Broker is a Service Broker that exposes Helm charts as Service Classes in Service Catalog. To do so, Helm Broker uses the concept of addons. An addon is an abstraction layer over a Helm chart which provides all information required to convert the chart into a Service Class. Prometheus \u00b6 Project Location: drycc/rabbitmq Prometheus is an open-source systemsmonitoring and alerting toolkit originally built atSoundCloud. See Also \u00b6 Workflow Concepts Workflow Architecture","title":"Components"},{"location":"understanding-workflow/components/#components","text":"Workflow is comprised of a number of small, independent services that combine to create a distributed PaaS. All Workflow components are deployed as services (and associated controllers) in your Kubernetes cluster. If you are interested we have a more detailed exploration of the Workflow architecture . All of the componentry for Workflow is built with composability in mind. If you need to customize one of the components for your specific deployment or need the functionality in your own project we invite you to give it a shot!","title":"Components"},{"location":"understanding-workflow/components/#controller","text":"Project Location: drycc/controller The controller component is an HTTP API server which serves as the endpoint for the drycc CLI. The controller provides all of the platform functionality as well as interfacing with your Kubernetes cluster. The controller persists all of its data to the database component.","title":"Controller"},{"location":"understanding-workflow/components/#passport","text":"Project Location: drycc/passport The passport component exposes a web API and provide OAuth2 authentication.","title":"Passport"},{"location":"understanding-workflow/components/#database","text":"Project Location: drycc/postgres The database component is a managed instance of PostgreSQL which holds a majority of the platforms state. Backups and WAL files are pushed to object storage via WAL-E . When the database is restarted, backups are fetched and replayed from object storage so no data is lost.","title":"Database"},{"location":"understanding-workflow/components/#builder","text":"Project Location: drycc/builder The builder component is responsible for accepting code pushes via Git and managing the build process of your Application . The builder process is: Receives incoming git push requests over SSH Authenticates the user via SSH key fingerprint Authorizes the user's access to push code to the Application Starts the Application Build phase (see below) Triggers a new Release via the Controller Builder currently supports both buildpack and Dockerfile based builds. Project Location: drycc/imagebuilder For Buildpack-based deploys, the builder component will launch a one-shot Job in the drycc namespace. This job runs imagebuilder component which handles default and custom buildpacks (specified by .packbuilder ). The completed image is pushed to the managed Container registry on cluster. For more information about buildpacks see using buildpacks . Unlike buildpack-based, For Applications which contain a Dockerfile in the root of the repository, it generates a Container image (using the underlying Container engine). For more information see using Dockerfiles .","title":"Builder"},{"location":"understanding-workflow/components/#object-storage","text":"Project Location: drycc/storage All of the Workflow components that need to persist data will ship them to the object storage that was configured for the cluster.For example, database ships its WAL files, registry stores Container images, and slugbuilder stores slugs. Workflow supports either on or off-cluster storage. For production deployments we highly recommend that you configure off-cluster object storage . To facilitate experimentation, development and test environments, the default charts for Workflow include on-cluster storage via storage . If you also feel comfortable using Kubernetes persistent volumes you may configure storage to use persistent storage available in your environment.","title":"Object Storage"},{"location":"understanding-workflow/components/#registry","text":"Project Location: drycc/registry The registry component is a managed container registry which holds application images generated from the builder component. Registry persists the Container image images to either local storage (in development mode) or to object storage configured for the cluster.","title":"Registry"},{"location":"understanding-workflow/components/#logger-fluentbit-logger","text":"The logging subsystem consists of two components. Fluentbit handles log shipping and logger maintains a ring-buffer of application logs. Project Location: drycc/fluentbit Fluentbit is deployed to your Kubernetes cluster via Daemon Sets. Fluentbit subscribes to all container logs, decorates the output with Kubernetes metadata and can be configured to drain logs to multiple destinations. By default, Fluentbit ships logs to the logger component, which powers drycc logs . Project Location: drycc/logger The logger component receives log streams from fluentbit , collating by Application name. Logger does not persist logs to disk, instead maintaining an in-memory ring buffer. For more information on logger see the project documentation .","title":"Logger: fluentbit, logger"},{"location":"understanding-workflow/components/#monitor","text":"Project Location: drycc/monitor The monitoring subsystem consists of two components: Telegraf and Grafana. Telegraf is the is the metrics collection agent that runs using the daemon set API. It runs on every worker node in the cluster, fetches information about the pods currently running and ships it to Prometheus. Grafana is a standalone graphing application. It natively supports Prometheus as a datasource and provides a robust engine for creating dashboards on top of timeseries data. Workflow provides a few dashboards out of the box for monitoring Drycc Workflow and Kubernetes. The dashboards can be used as a starting point for creating more custom dashboards to suit a user's needs.","title":"Monitor"},{"location":"understanding-workflow/components/#prometheus","text":"Project Location: drycc/prometheus Prometheus is a system monitoring and alerting system. It was opensourced by SoundCloud in 2012 and is the second project both to join and to graduate within Cloud Native Computing Foundation after Kubernetes. Prometheus stores all metrics data as time series, i.e metrics information is stored along with the timestamp at which it was recorded, optional key-value pairs called as labels can also be stored along with metrics.","title":"Prometheus"},{"location":"understanding-workflow/components/#rabbitmq","text":"Project Location: drycc/rabbitmq RabbitMQ is the most widely deployed open source message broker. Controller use celery with rabbitMQ to execute the asynchronous task.","title":"Rabbitmq"},{"location":"understanding-workflow/components/#helmbroker","text":"Project Location: drycc/rabbitmq Helm Broker is a Service Broker that exposes Helm charts as Service Classes in Service Catalog. To do so, Helm Broker uses the concept of addons. An addon is an abstraction layer over a Helm chart which provides all information required to convert the chart into a Service Class.","title":"HelmBroker"},{"location":"understanding-workflow/components/#prometheus_1","text":"Project Location: drycc/rabbitmq Prometheus is an open-source systemsmonitoring and alerting toolkit originally built atSoundCloud.","title":"Prometheus"},{"location":"understanding-workflow/components/#see-also","text":"Workflow Concepts Workflow Architecture","title":"See Also"},{"location":"understanding-workflow/concepts/","text":"Concepts \u00b6 Drycc Workflow is a lightweight application platform that deploys and scales Twelve-Factor apps as containers across a Kubernetes cluster. Twelve-Factor Applications \u00b6 The Twelve-Factor App is a methodology for building modern applications that can be scaled across a distributed system. Twelve-factor is a valuable synthesis of years of experience with software-as-a-service apps in the wild, particularly on the Heroku platform. Workflow is designed to run applications that adhere to the Twelve-Factor App methodology and best practices. Kubernetes \u00b6 Kubernetes is an open-source cluster manager developed by Google and donated to the Cloud Native Compute Foundation . Kubernetes manages all the activity on your cluster, including: desired state convergence, stable service addresses, health monitoring, service discovery, and DNS resolution. Workflow builds upon Kubernetes abstractions like Services, Deployments and Pods to provide a developer-friendly experience. Building containers directly from application source code, aggregating logs, and managing deployment configurations and app releases are just some of the features Workflow adds. Drycc Workflow is a set of Kubernetes-native components, installable via Helm . Systems engineers who are familiar with Kubernetes will feel right at home running Workflow. See the components overview for more detail. Container \u00b6 [Container][] is an open source project to build, ship and run any application as a lightweight, portable, self-sufficient container. If you have not yet converted your application to containers, Workflow provides a simple and straightforward \"source to Container image\" capability. Supporting multiple language runtimes via community buildpacks , building your application in a container can be as easy as git push drycc master . Applications which use either a Dockerfile or reference external Container images are launched unmodified. Applications \u00b6 Workflow is designed around the concept of an application , or app. Applications come in one of three forms: a collection of source files stored in a git repository a Dockerfile and associated source files stored in a git repository a reference to an existing image at a Container repository Applications are identified by a unique name for easy reference. If you do not specify a name when creating your application, Workflow generates one for you. Workflow also manages related information, including domain names, SSL certificates, and developer-provided configuration. Build, Release, Run \u00b6 Build Stage \u00b6 The builder component processes incoming git push drycc master requests and manages your application packaging. If your application is using a buildpack , builder will launch an ephemeral job to extract and execute the packaging instructions. The resulting application artifact is stored by the platform for execution during the run stage. If instead builder finds a Dockerfile , it follows those instructions to create a Container image. The resulting artifact is stored in a Drycc-managed registry which will be referenced during the run stage. If another system already builds and packages your application, that container artifact can be used directly. When referencing an external Container image , the builder component doesn't attempt to repackage your app. Release Stage \u00b6 During the release stage, a build is combined with application configuration to create a new, numbered release . New releases are created any time a new build is created or application configuration is changed. Tracking releases as a \"write-only ledger\" this way makes it easy to rollback to any previous release. Run Stage \u00b6 The run stage deploys the new release to the underlying Kubernetes cluster by changing the Deployment object which references the new release. By managing the desired replica count, Workflow orchestrates a zero-downtime, rolling update of your application. Once successfully updated, Workflow removes the last reference to the old release. Note that during the deploy, your application will be running in a mixed mode. Backing Services \u00b6 Workflow treats all persistent services such as databases, caches, storage, messaging systems, and other backing services as resources managed separately from your application. This philosophy aligns with Twelve-Factor best practices. Applications attach to backing services using environment variables . Because apps are decoupled from backing services, they are free to scale up independently, to use services provided by other apps, or to switch to external or third-party vendor services. See Also \u00b6 Workflow Architecture Workflow Components","title":"Concepts"},{"location":"understanding-workflow/concepts/#concepts","text":"Drycc Workflow is a lightweight application platform that deploys and scales Twelve-Factor apps as containers across a Kubernetes cluster.","title":"Concepts"},{"location":"understanding-workflow/concepts/#twelve-factor-applications","text":"The Twelve-Factor App is a methodology for building modern applications that can be scaled across a distributed system. Twelve-factor is a valuable synthesis of years of experience with software-as-a-service apps in the wild, particularly on the Heroku platform. Workflow is designed to run applications that adhere to the Twelve-Factor App methodology and best practices.","title":"Twelve-Factor Applications"},{"location":"understanding-workflow/concepts/#kubernetes","text":"Kubernetes is an open-source cluster manager developed by Google and donated to the Cloud Native Compute Foundation . Kubernetes manages all the activity on your cluster, including: desired state convergence, stable service addresses, health monitoring, service discovery, and DNS resolution. Workflow builds upon Kubernetes abstractions like Services, Deployments and Pods to provide a developer-friendly experience. Building containers directly from application source code, aggregating logs, and managing deployment configurations and app releases are just some of the features Workflow adds. Drycc Workflow is a set of Kubernetes-native components, installable via Helm . Systems engineers who are familiar with Kubernetes will feel right at home running Workflow. See the components overview for more detail.","title":"Kubernetes"},{"location":"understanding-workflow/concepts/#container","text":"[Container][] is an open source project to build, ship and run any application as a lightweight, portable, self-sufficient container. If you have not yet converted your application to containers, Workflow provides a simple and straightforward \"source to Container image\" capability. Supporting multiple language runtimes via community buildpacks , building your application in a container can be as easy as git push drycc master . Applications which use either a Dockerfile or reference external Container images are launched unmodified.","title":"Container"},{"location":"understanding-workflow/concepts/#applications","text":"Workflow is designed around the concept of an application , or app. Applications come in one of three forms: a collection of source files stored in a git repository a Dockerfile and associated source files stored in a git repository a reference to an existing image at a Container repository Applications are identified by a unique name for easy reference. If you do not specify a name when creating your application, Workflow generates one for you. Workflow also manages related information, including domain names, SSL certificates, and developer-provided configuration.","title":"Applications"},{"location":"understanding-workflow/concepts/#build-release-run","text":"","title":"Build, Release, Run"},{"location":"understanding-workflow/concepts/#build-stage","text":"The builder component processes incoming git push drycc master requests and manages your application packaging. If your application is using a buildpack , builder will launch an ephemeral job to extract and execute the packaging instructions. The resulting application artifact is stored by the platform for execution during the run stage. If instead builder finds a Dockerfile , it follows those instructions to create a Container image. The resulting artifact is stored in a Drycc-managed registry which will be referenced during the run stage. If another system already builds and packages your application, that container artifact can be used directly. When referencing an external Container image , the builder component doesn't attempt to repackage your app.","title":"Build Stage"},{"location":"understanding-workflow/concepts/#release-stage","text":"During the release stage, a build is combined with application configuration to create a new, numbered release . New releases are created any time a new build is created or application configuration is changed. Tracking releases as a \"write-only ledger\" this way makes it easy to rollback to any previous release.","title":"Release Stage"},{"location":"understanding-workflow/concepts/#run-stage","text":"The run stage deploys the new release to the underlying Kubernetes cluster by changing the Deployment object which references the new release. By managing the desired replica count, Workflow orchestrates a zero-downtime, rolling update of your application. Once successfully updated, Workflow removes the last reference to the old release. Note that during the deploy, your application will be running in a mixed mode.","title":"Run Stage"},{"location":"understanding-workflow/concepts/#backing-services","text":"Workflow treats all persistent services such as databases, caches, storage, messaging systems, and other backing services as resources managed separately from your application. This philosophy aligns with Twelve-Factor best practices. Applications attach to backing services using environment variables . Because apps are decoupled from backing services, they are free to scale up independently, to use services provided by other apps, or to switch to external or third-party vendor services.","title":"Backing Services"},{"location":"understanding-workflow/concepts/#see-also","text":"Workflow Architecture Workflow Components","title":"See Also"},{"location":"users/cli/","text":"Drycc Workflow CLI \u00b6 The Drycc Workflow command-line interface (CLI), or client, allows you to interact with Drycc Workflow. Installation \u00b6 Install the latest drycc client for Linux or Mac OS X with: $ curl -sfL https://www.drycc.cc/install-cli.sh | bash - The installer puts drycc in your current directory, but you should move it somewhere in your $PATH: $ ln -fs $PWD/drycc /usr/local/bin/drycc Getting Help \u00b6 The Drycc client comes with comprehensive documentation for every command. Use drycc help to explore the commands available to you: $ drycc help The Drycc command-line client issues API calls to a Drycc controller. Usage: drycc [...] Auth commands:: login login to a controller logout logout from the current controller Subcommands, use `drycc help [subcommand]` to learn more:: ... To get help on subcommands, use drycc help [subcommand] : $ drycc help apps Valid commands for apps: apps:create create a new application apps:list list accessible applications apps:info view info about an application apps:open open the application in a browser apps:logs view aggregated application logs apps:run run a command in an ephemeral app container apps:destroy destroy an application apps:transfer transfer app ownership to another user Use `drycc help [command]` to learn more Support for Multiple Profiles \u00b6 The CLI reads from the default client profile, which is located on your workstation at $HOME/.drycc/client.json . Easily switch between multiple Drycc Workflow installations or users by setting the $DRYCC_PROFILE environment variable or by using the -c flag. There are two ways to set the $DRYCC_PROFILE option. Path to a json configuration file. Profile name. If you set profile to just a name, it will be saved alongside the default profile, in $HOME/.drycc/.json . Examples: $ DRYCC_PROFILE=production drycc login drycc.production.com ... Opening browser to http://drycc.example.com/v2/login/drycc/?key=4ccc81ee2dce4349ad5261ceffe72c71 Waiting for login... .o.Logged in as drycc Configuration saved to /home/testuser/.drycc/production.json $ DRYCC_PROFILE=~/config.json drycc login drycc.example.com ... Opening browser to http://drycc.example.com/v2/login/drycc/?key=4ccc81ee2dce4349ad5261ceffe72c71 Waiting for login... .o.Logged in as drycc Configuration saved to /home/testuser/config.json The configuration flag works identically to and overrides $DRYCC_PROFILE : $ drycc whoami -c ~/config.json You are drycc at drycc.example.com Proxy Support \u00b6 If your workstation uses a proxy to reach the network where the cluster lies, set the http_proxy or https_proxy environment variable to enable proxy support: $ export http_proxy=\"http://proxyip:port\" $ export https_proxy=\"http://proxyip:port\" Note Configuring a proxy is generally not necessary for local Minikube clusters. CLI Plugins \u00b6 Plugins allow developers to extend the functionality of the Drycc Client, adding new commands or features. If an unknown command is specified, the client will attempt to execute the command as a dash-separated command. In this case, drycc resource:command will execute drycc-resource with the argument list command . In full form: $ # these two are identical $ drycc accounts:list $ drycc-accounts list Any flags after the command will also be sent to the plugin as an argument: $ # these two are identical $ drycc accounts:list --debug $ drycc-accounts list --debug But flags preceding the command will not: $ # these two are identical $ drycc --debug accounts:list $ drycc-accounts list","title":"Command Line Interface"},{"location":"users/cli/#drycc-workflow-cli","text":"The Drycc Workflow command-line interface (CLI), or client, allows you to interact with Drycc Workflow.","title":"Drycc Workflow CLI"},{"location":"users/cli/#installation","text":"Install the latest drycc client for Linux or Mac OS X with: $ curl -sfL https://www.drycc.cc/install-cli.sh | bash - The installer puts drycc in your current directory, but you should move it somewhere in your $PATH: $ ln -fs $PWD/drycc /usr/local/bin/drycc","title":"Installation"},{"location":"users/cli/#getting-help","text":"The Drycc client comes with comprehensive documentation for every command. Use drycc help to explore the commands available to you: $ drycc help The Drycc command-line client issues API calls to a Drycc controller. Usage: drycc [...] Auth commands:: login login to a controller logout logout from the current controller Subcommands, use `drycc help [subcommand]` to learn more:: ... To get help on subcommands, use drycc help [subcommand] : $ drycc help apps Valid commands for apps: apps:create create a new application apps:list list accessible applications apps:info view info about an application apps:open open the application in a browser apps:logs view aggregated application logs apps:run run a command in an ephemeral app container apps:destroy destroy an application apps:transfer transfer app ownership to another user Use `drycc help [command]` to learn more","title":"Getting Help"},{"location":"users/cli/#support-for-multiple-profiles","text":"The CLI reads from the default client profile, which is located on your workstation at $HOME/.drycc/client.json . Easily switch between multiple Drycc Workflow installations or users by setting the $DRYCC_PROFILE environment variable or by using the -c flag. There are two ways to set the $DRYCC_PROFILE option. Path to a json configuration file. Profile name. If you set profile to just a name, it will be saved alongside the default profile, in $HOME/.drycc/.json . Examples: $ DRYCC_PROFILE=production drycc login drycc.production.com ... Opening browser to http://drycc.example.com/v2/login/drycc/?key=4ccc81ee2dce4349ad5261ceffe72c71 Waiting for login... .o.Logged in as drycc Configuration saved to /home/testuser/.drycc/production.json $ DRYCC_PROFILE=~/config.json drycc login drycc.example.com ... Opening browser to http://drycc.example.com/v2/login/drycc/?key=4ccc81ee2dce4349ad5261ceffe72c71 Waiting for login... .o.Logged in as drycc Configuration saved to /home/testuser/config.json The configuration flag works identically to and overrides $DRYCC_PROFILE : $ drycc whoami -c ~/config.json You are drycc at drycc.example.com","title":"Support for Multiple Profiles"},{"location":"users/cli/#proxy-support","text":"If your workstation uses a proxy to reach the network where the cluster lies, set the http_proxy or https_proxy environment variable to enable proxy support: $ export http_proxy=\"http://proxyip:port\" $ export https_proxy=\"http://proxyip:port\" Note Configuring a proxy is generally not necessary for local Minikube clusters.","title":"Proxy Support"},{"location":"users/cli/#cli-plugins","text":"Plugins allow developers to extend the functionality of the Drycc Client, adding new commands or features. If an unknown command is specified, the client will attempt to execute the command as a dash-separated command. In this case, drycc resource:command will execute drycc-resource with the argument list command . In full form: $ # these two are identical $ drycc accounts:list $ drycc-accounts list Any flags after the command will also be sent to the plugin as an argument: $ # these two are identical $ drycc accounts:list --debug $ drycc-accounts list --debug But flags preceding the command will not: $ # these two are identical $ drycc --debug accounts:list $ drycc-accounts list","title":"CLI Plugins"},{"location":"users/registration/","text":"Users and Registration \u00b6 Workflow use the passport component to create and authorize users, it can config options for LDAP authentication or browse passport web site to register users. Login to Workflow \u00b6 If you already have an account, use drycc login to authenticate against the Drycc Workflow API. $ drycc login http://drycc.example.com Opening browser to http://drycc.example.com/v2/login/drycc/?key=4ccc81ee2dce4349ad5261ceffe72c71 Waiting for login... .o.Logged in as drycc Configuration file written to /root/.drycc/client.json Logout from Workflow \u00b6 Logout of an existing controller session using drycc logout . $ drycc logout Logged out as drycc Verify Your Session \u00b6 You can verify your client configuration by running drycc whoami . $ drycc whoami You are drycc at http://drycc.example.com Note Session and client configuration is stored in the ~/.drycc/client.json file.","title":"Users and Registration"},{"location":"users/registration/#users-and-registration","text":"Workflow use the passport component to create and authorize users, it can config options for LDAP authentication or browse passport web site to register users.","title":"Users and Registration"},{"location":"users/registration/#login-to-workflow","text":"If you already have an account, use drycc login to authenticate against the Drycc Workflow API. $ drycc login http://drycc.example.com Opening browser to http://drycc.example.com/v2/login/drycc/?key=4ccc81ee2dce4349ad5261ceffe72c71 Waiting for login... .o.Logged in as drycc Configuration file written to /root/.drycc/client.json","title":"Login to Workflow"},{"location":"users/registration/#logout-from-workflow","text":"Logout of an existing controller session using drycc logout . $ drycc logout Logged out as drycc","title":"Logout from Workflow"},{"location":"users/registration/#verify-your-session","text":"You can verify your client configuration by running drycc whoami . $ drycc whoami You are drycc at http://drycc.example.com Note Session and client configuration is stored in the ~/.drycc/client.json file.","title":"Verify Your Session"},{"location":"users/ssh-keys/","text":"Users and SSH Keys \u00b6 For Dockerfile and Buildpack based application deploys via git push , Drycc Workflow identifies users via SSH keys. SSH keys are pushed to the platform and must be unique to each user. Users may have multiple SSH keys as needed. Generate an SSH Key \u00b6 If you do not already have an SSH key or would like to create a new key for Drycc Workflow, generate a new key using ssh-keygen : $ ssh-keygen -f ~/.ssh/id_drycc -t rsa Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /Users/admin/.ssh/id_drycc. Your public key has been saved in /Users/admin/.ssh/id_drycc.pub. The key fingerprint is: 3d:ac:1f:f4:83:f7:64:51:c1:7e:7f:80:b6:70:36:c9 admin@plinth-23437.local The key's randomart image is: +--[ RSA 2048]----+ | .. | | ..| | . o. .| | o. E .o.| | S == o..o| | o +. .o| | . o + o .| | . o = | | . . | +-----------------+ $ ssh-add ~/.ssh/id_drycc Identity added: /Users/admin/.ssh/id_drycc (/Users/admin/.ssh/id_drycc) Adding and Removing SSH Keys \u00b6 By publishing the public half of your SSH key to Drycc Workflow the component responsible for receiving git push will be able to authenticate the user and ensure that they have access to the destination application. $ drycc keys:add ~/.ssh/id_drycc.pub Uploading id_drycc.pub to drycc... done You can always view the keys associated with your user as well: $ drycc keys:list === admin Keys admin@plinth-23437.local ssh-rsa AAAAB3Nz...3437.local admin@subgenius.local ssh-rsa AAAAB3Nz...nius.local Remove keys by their name: $ drycc keys:remove admin@plinth-23437.local Removing admin@plinth-23437.local SSH Key... don","title":"SSH Keys"},{"location":"users/ssh-keys/#users-and-ssh-keys","text":"For Dockerfile and Buildpack based application deploys via git push , Drycc Workflow identifies users via SSH keys. SSH keys are pushed to the platform and must be unique to each user. Users may have multiple SSH keys as needed.","title":"Users and SSH Keys"},{"location":"users/ssh-keys/#generate-an-ssh-key","text":"If you do not already have an SSH key or would like to create a new key for Drycc Workflow, generate a new key using ssh-keygen : $ ssh-keygen -f ~/.ssh/id_drycc -t rsa Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /Users/admin/.ssh/id_drycc. Your public key has been saved in /Users/admin/.ssh/id_drycc.pub. The key fingerprint is: 3d:ac:1f:f4:83:f7:64:51:c1:7e:7f:80:b6:70:36:c9 admin@plinth-23437.local The key's randomart image is: +--[ RSA 2048]----+ | .. | | ..| | . o. .| | o. E .o.| | S == o..o| | o +. .o| | . o + o .| | . o = | | . . | +-----------------+ $ ssh-add ~/.ssh/id_drycc Identity added: /Users/admin/.ssh/id_drycc (/Users/admin/.ssh/id_drycc)","title":"Generate an SSH Key"},{"location":"users/ssh-keys/#adding-and-removing-ssh-keys","text":"By publishing the public half of your SSH key to Drycc Workflow the component responsible for receiving git push will be able to authenticate the user and ensure that they have access to the destination application. $ drycc keys:add ~/.ssh/id_drycc.pub Uploading id_drycc.pub to drycc... done You can always view the keys associated with your user as well: $ drycc keys:list === admin Keys admin@plinth-23437.local ssh-rsa AAAAB3Nz...3437.local admin@subgenius.local ssh-rsa AAAAB3Nz...nius.local Remove keys by their name: $ drycc keys:remove admin@plinth-23437.local Removing admin@plinth-23437.local SSH Key... don","title":"Adding and Removing SSH Keys"}]} \ No newline at end of file diff --git a/search/worker.js b/search/worker.js new file mode 100644 index 000000000..8628dbce9 --- /dev/null +++ b/search/worker.js @@ -0,0 +1,133 @@ +var base_path = 'function' === typeof importScripts ? '.' : '/search/'; +var allowSearch = false; +var index; +var documents = {}; +var lang = ['en']; +var data; + +function getScript(script, callback) { + console.log('Loading script: ' + script); + $.getScript(base_path + script).done(function () { + callback(); + }).fail(function (jqxhr, settings, exception) { + console.log('Error: ' + exception); + }); +} + +function getScriptsInOrder(scripts, callback) { + if (scripts.length === 0) { + callback(); + return; + } + getScript(scripts[0], function() { + getScriptsInOrder(scripts.slice(1), callback); + }); +} + +function loadScripts(urls, callback) { + if( 'function' === typeof importScripts ) { + importScripts.apply(null, urls); + callback(); + } else { + getScriptsInOrder(urls, callback); + } +} + +function onJSONLoaded () { + data = JSON.parse(this.responseText); + var scriptsToLoad = ['lunr.js']; + if (data.config && data.config.lang && data.config.lang.length) { + lang = data.config.lang; + } + if (lang.length > 1 || lang[0] !== "en") { + scriptsToLoad.push('lunr.stemmer.support.js'); + if (lang.length > 1) { + scriptsToLoad.push('lunr.multi.js'); + } + if (lang.includes("ja") || lang.includes("jp")) { + scriptsToLoad.push('tinyseg.js'); + } + for (var i=0; i < lang.length; i++) { + if (lang[i] != 'en') { + scriptsToLoad.push(['lunr', lang[i], 'js'].join('.')); + } + } + } + loadScripts(scriptsToLoad, onScriptsLoaded); +} + +function onScriptsLoaded () { + console.log('All search scripts loaded, building Lunr index...'); + if (data.config && data.config.separator && data.config.separator.length) { + lunr.tokenizer.separator = new RegExp(data.config.separator); + } + + if (data.index) { + index = lunr.Index.load(data.index); + data.docs.forEach(function (doc) { + documents[doc.location] = doc; + }); + console.log('Lunr pre-built index loaded, search ready'); + } else { + index = lunr(function () { + if (lang.length === 1 && lang[0] !== "en" && lunr[lang[0]]) { + this.use(lunr[lang[0]]); + } else if (lang.length > 1) { + this.use(lunr.multiLanguage.apply(null, lang)); // spread operator not supported in all browsers: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Browser_compatibility + } + this.field('title'); + this.field('text'); + this.ref('location'); + + for (var i=0; i < data.docs.length; i++) { + var doc = data.docs[i]; + this.add(doc); + documents[doc.location] = doc; + } + }); + console.log('Lunr index built, search ready'); + } + allowSearch = true; + postMessage({config: data.config}); + postMessage({allowSearch: allowSearch}); +} + +function init () { + var oReq = new XMLHttpRequest(); + oReq.addEventListener("load", onJSONLoaded); + var index_path = base_path + '/search_index.json'; + if( 'function' === typeof importScripts ){ + index_path = 'search_index.json'; + } + oReq.open("GET", index_path); + oReq.send(); +} + +function search (query) { + if (!allowSearch) { + console.error('Assets for search still loading'); + return; + } + + var resultDocuments = []; + var results = index.search(query); + for (var i=0; i < results.length; i++){ + var result = results[i]; + doc = documents[result.ref]; + doc.summary = doc.text.substring(0, 200); + resultDocuments.push(doc); + } + return resultDocuments; +} + +if( 'function' === typeof importScripts ) { + onmessage = function (e) { + if (e.data.init) { + init(); + } else if (e.data.query) { + postMessage({ results: search(e.data.query) }); + } else { + console.error("Worker - Unrecognized message: " + e); + } + }; +} diff --git a/security/1d6a97d0.txt b/security/1d6a97d0.txt new file mode 100644 index 000000000..0282082c5 --- /dev/null +++ b/security/1d6a97d0.txt @@ -0,0 +1,92 @@ +sec 4096R/1D6A97D0 2016-11-03 + Key fingerprint = 41AF 6B6A 9489 9B58 1EB6 9ED1 17E5 26B5 1D6A 97D0 +uid Drycc, Inc. (Helm chart signing key) +ssb 4096R/2CA931B0 2016-11-03 +ssb 4096R/41C9CA1E 2016-11-03 [expires: 2024-11-01] + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +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 +K8I9jWQf2UCagoUuV3w= +=qap/ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 000000000..24f448507 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,310 @@ + + + + + + /docs/workflow/ + + + + + + + /docs/workflow/quickstart/ + + + + /docs/workflow/quickstart/install-workflow/ + + + + /docs/workflow/quickstart/install-cli-tools/ + + + + /docs/workflow/quickstart/deploy-an-app/ + + + + + + + + /docs/workflow/understanding-workflow/concepts/ + + + + /docs/workflow/understanding-workflow/architecture/ + + + + /docs/workflow/understanding-workflow/components/ + + + + + + + + /docs/workflow/installing-workflow/system-requirements/ + + + + /docs/workflow/installing-workflow/gateway/ + + + + /docs/workflow/installing-workflow/ + + + + /docs/workflow/installing-workflow/configuring-object-storage/ + + + + /docs/workflow/installing-workflow/configuring-postgres/ + + + + /docs/workflow/installing-workflow/configuring-registry/ + + + + + + + + /docs/workflow/users/cli/ + + + + /docs/workflow/users/registration/ + + + + /docs/workflow/users/ssh-keys/ + + + + + + + + /docs/workflow/applications/deploying-apps/ + + + + /docs/workflow/applications/using-buildpacks/ + + + + /docs/workflow/applications/using-dockerfiles/ + + + + /docs/workflow/applications/using-container-images/ + + + + /docs/workflow/applications/managing-app-processes/ + + + + /docs/workflow/applications/managing-app-configuration/ + + + + /docs/workflow/applications/managing-app-lifecycle/ + + + + /docs/workflow/applications/managing-app-volumes/ + + + + /docs/workflow/applications/managing-app-gateway/ + + + + /docs/workflow/applications/managing-app-resources/ + + + + /docs/workflow/applications/inter-app-communication/ + + + + /docs/workflow/applications/managing-resource-limits/ + + + + /docs/workflow/applications/domains-and-routing/ + + + + /docs/workflow/applications/ssl-certificates/ + + + + + + + + /docs/workflow/managing-workflow/tuning-component-settings/ + + + + /docs/workflow/managing-workflow/configuring-dns/ + + + + /docs/workflow/managing-workflow/deploy-hooks/ + + + + /docs/workflow/managing-workflow/platform-logging/ + + + + /docs/workflow/managing-workflow/platform-monitoring/ + + + + /docs/workflow/managing-workflow/production-deployments/ + + + + /docs/workflow/managing-workflow/upgrading-workflow/ + + + + + + + + /docs/workflow/troubleshooting/ + + + + /docs/workflow/troubleshooting/kubectl/ + + + + /docs/workflow/troubleshooting/applications/ + + + + + + + + /docs/workflow/roadmap/planning-process/ + + + + /docs/workflow/roadmap/roadmap/ + + + + /docs/workflow/roadmap/releases/ + + + + + + + + /docs/workflow/contributing/overview/ + + + + /docs/workflow/contributing/design-documents/ + + + + /docs/workflow/contributing/development-environment/ + + + + /docs/workflow/contributing/testing/ + + + + /docs/workflow/contributing/submitting-a-pull-request/ + + + + /docs/workflow/contributing/community/ + + + + /docs/workflow/contributing/triaging-issues/ + + + + /docs/workflow/contributing/conduct/ + + + + /docs/workflow/contributing/maintainers/ + + + + + + + + /docs/workflow/reference-guide/creating-a-self-signed-ssl-certificate/ + + + + /docs/workflow/reference-guide/terms/ + + + + /docs/workflow/reference-guide/controller-api/v2.0/ + + + + /docs/workflow/reference-guide/controller-api/v2.1/ + + + + /docs/workflow/reference-guide/controller-api/v2.2/ + + + + /docs/workflow/reference-guide/controller-api/v2.3/ + + + + + + + + /docs/workflow/changelogs/v1.5.0/ + + + + /docs/workflow/changelogs/v1.4.0/ + + + + /docs/workflow/changelogs/v1.3.0/ + + + + /docs/workflow/changelogs/v1.2.0/ + + + + /docs/workflow/changelogs/v1.1.0/ + + + + /docs/workflow/changelogs/v1.0.1/ + + + + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 000000000..e10a72625 Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/static/css/styles.css b/static/css/styles.css new file mode 100644 index 000000000..4a37eddab --- /dev/null +++ b/static/css/styles.css @@ -0,0 +1,16 @@ +@charset "UTF-8";/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}a.button,button{border-radius:8px;color:#555;display:inline-block;font-weight:bold;margin:0;padding:0.9em 2em}a.button .icon.-right,button .icon.-right{margin-left:5px}a.button .icon.-left,button .icon.-left{margin-right:5px}a.button:hover,button:hover{background-color:#6cc3eb;color:#555}a.button.-outline,button.-outline{background-color:transparent;border:3px solid #EEEEEE}a.button.-outline:hover,button.-outline:hover{background-color:transparent;border-color:#d4d4d4}a.button.-fill,button.-fill{background-color:#ff2a53;border:initial;padding:16px 2.1em;color:#fff}a.button.-fill:hover,button.-fill:hover{background-color:#ff5d7c}a.button.-border,button.-border{border:3px solid #FFFFFF}.subheading-link{text-align:center;font-size:1rem;margin:20px 0 0 0}.subheading-link>a{color:#ff2a53}meta.foundation-version{font-family:"/5.5.3/"}meta.foundation-mq-small{font-family:"/only screen/";width:0}meta.foundation-mq-small-only{font-family:"/only screen and (max-width: 40em)/";width:0}meta.foundation-mq-medium{font-family:"/only screen and (min-width:40.0625em)/";width:40.0625em}meta.foundation-mq-medium-only{font-family:"/only screen and (min-width:40.0625em) and (max-width:64em)/";width:40.0625em}meta.foundation-mq-large{font-family:"/only screen and (min-width:64.0625em)/";width:64.0625em}meta.foundation-mq-large-only{font-family:"/only screen and (min-width:64.0625em) and (max-width:90em)/";width:64.0625em}meta.foundation-mq-xlarge{font-family:"/only screen and (min-width:90.0625em)/";width:90.0625em}meta.foundation-mq-xlarge-only{font-family:"/only screen and (min-width:90.0625em) and (max-width:120em)/";width:90.0625em}meta.foundation-mq-xxlarge{font-family:"/only screen and (min-width:120.0625em)/";width:120.0625em}meta.foundation-data-attribute-namespace{font-family:false}html,body{height:100%}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html,body{font-size:100%}body{background:#fff;color:#222;cursor:auto;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:normal;line-height:1.5;margin:0;padding:0;position:relative}a:hover{cursor:pointer}img{max-width:100%;height:auto}img{-ms-interpolation-mode:bicubic}#map_canvas img,#map_canvas embed,#map_canvas object,.map_canvas img,.map_canvas embed,.map_canvas object,.mqa-display img,.mqa-display embed,.mqa-display object{max-width:none !important}.left{float:left !important}.right{float:right !important}.clearfix:before,.clearfix:after{content:" ";display:table}.clearfix:after{clear:both}.hide{display:none}.invisible{visibility:hidden}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}img{display:inline-block;vertical-align:middle}textarea{height:auto;min-height:50px}select{width:100%}.row{margin:0 auto;max-width:59.375rem;width:100%}.row:before,.row:after{content:" ";display:table}.row:after{clear:both}.row.collapse>.column,.row.collapse>.columns{padding-left:0;padding-right:0}.row.collapse .row{margin-left:0;margin-right:0}.row .row{margin:0 -0.9375rem;max-width:none;width:auto}.row .row:before,.row .row:after{content:" ";display:table}.row .row:after{clear:both}.row .row.collapse{margin:0;max-width:none;width:auto}.row .row.collapse:before,.row .row.collapse:after{content:" ";display:table}.row .row.collapse:after{clear:both}.column,.columns{padding-left:0.9375rem;padding-right:0.9375rem;width:100%;float:left}.column+.column:last-child,.columns+.column:last-child,.column+.columns:last-child,.columns+.columns:last-child{float:right}.column+.column.end,.columns+.column.end,.column+.columns.end,.columns+.columns.end{float:left}@media only screen{.small-push-0{position:relative;left:0;right:auto}.small-pull-0{position:relative;right:0;left:auto}.small-push-1{position:relative;left:8.33333%;right:auto}.small-pull-1{position:relative;right:8.33333%;left:auto}.small-push-2{position:relative;left:16.66667%;right:auto}.small-pull-2{position:relative;right:16.66667%;left:auto}.small-push-3{position:relative;left:25%;right:auto}.small-pull-3{position:relative;right:25%;left:auto}.small-push-4{position:relative;left:33.33333%;right:auto}.small-pull-4{position:relative;right:33.33333%;left:auto}.small-push-5{position:relative;left:41.66667%;right:auto}.small-pull-5{position:relative;right:41.66667%;left:auto}.small-push-6{position:relative;left:50%;right:auto}.small-pull-6{position:relative;right:50%;left:auto}.small-push-7{position:relative;left:58.33333%;right:auto}.small-pull-7{position:relative;right:58.33333%;left:auto}.small-push-8{position:relative;left:66.66667%;right:auto}.small-pull-8{position:relative;right:66.66667%;left:auto}.small-push-9{position:relative;left:75%;right:auto}.small-pull-9{position:relative;right:75%;left:auto}.small-push-10{position:relative;left:83.33333%;right:auto}.small-pull-10{position:relative;right:83.33333%;left:auto}.small-push-11{position:relative;left:91.66667%;right:auto}.small-pull-11{position:relative;right:91.66667%;left:auto}.column,.columns{position:relative;padding-left:0.9375rem;padding-right:0.9375rem;float:left}.small-1{width:8.33333%}.small-2{width:16.66667%}.small-3{width:25%}.small-4{width:33.33333%}.small-5{width:41.66667%}.small-6{width:50%}.small-7{width:58.33333%}.small-8{width:66.66667%}.small-9{width:75%}.small-10{width:83.33333%}.small-11{width:91.66667%}.small-12{width:100%}.small-offset-0{margin-left:0 !important}.small-offset-1{margin-left:8.33333% !important}.small-offset-2{margin-left:16.66667% !important}.small-offset-3{margin-left:25% !important}.small-offset-4{margin-left:33.33333% !important}.small-offset-5{margin-left:41.66667% !important}.small-offset-6{margin-left:50% !important}.small-offset-7{margin-left:58.33333% !important}.small-offset-8{margin-left:66.66667% !important}.small-offset-9{margin-left:75% !important}.small-offset-10{margin-left:83.33333% !important}.small-offset-11{margin-left:91.66667% !important}.small-reset-order{float:left;left:auto;margin-left:0;margin-right:0;right:auto}.column.small-centered,.columns.small-centered{margin-left:auto;margin-right:auto;float:none}.column.small-uncentered,.columns.small-uncentered{float:left;margin-left:0;margin-right:0}.column.small-centered:last-child,.columns.small-centered:last-child{float:none}.column.small-uncentered:last-child,.columns.small-uncentered:last-child{float:left}.column.small-uncentered.opposite,.columns.small-uncentered.opposite{float:right}.row.small-collapse>.column,.row.small-collapse>.columns{padding-left:0;padding-right:0}.row.small-collapse .row{margin-left:0;margin-right:0}.row.small-uncollapse>.column,.row.small-uncollapse>.columns{padding-left:0.9375rem;padding-right:0.9375rem;float:left}}@media only screen and (min-width: 40.0625em){.medium-push-0{position:relative;left:0;right:auto}.medium-pull-0{position:relative;right:0;left:auto}.medium-push-1{position:relative;left:8.33333%;right:auto}.medium-pull-1{position:relative;right:8.33333%;left:auto}.medium-push-2{position:relative;left:16.66667%;right:auto}.medium-pull-2{position:relative;right:16.66667%;left:auto}.medium-push-3{position:relative;left:25%;right:auto}.medium-pull-3{position:relative;right:25%;left:auto}.medium-push-4{position:relative;left:33.33333%;right:auto}.medium-pull-4{position:relative;right:33.33333%;left:auto}.medium-push-5{position:relative;left:41.66667%;right:auto}.medium-pull-5{position:relative;right:41.66667%;left:auto}.medium-push-6{position:relative;left:50%;right:auto}.medium-pull-6{position:relative;right:50%;left:auto}.medium-push-7{position:relative;left:58.33333%;right:auto}.medium-pull-7{position:relative;right:58.33333%;left:auto}.medium-push-8{position:relative;left:66.66667%;right:auto}.medium-pull-8{position:relative;right:66.66667%;left:auto}.medium-push-9{position:relative;left:75%;right:auto}.medium-pull-9{position:relative;right:75%;left:auto}.medium-push-10{position:relative;left:83.33333%;right:auto}.medium-pull-10{position:relative;right:83.33333%;left:auto}.medium-push-11{position:relative;left:91.66667%;right:auto}.medium-pull-11{position:relative;right:91.66667%;left:auto}.column,.columns{position:relative;padding-left:0.9375rem;padding-right:0.9375rem;float:left}.medium-1{width:8.33333%}.medium-2{width:16.66667%}.medium-3{width:25%}.medium-4{width:33.33333%}.medium-5{width:41.66667%}.medium-6{width:50%}.medium-7{width:58.33333%}.medium-8{width:66.66667%}.medium-9{width:75%}.medium-10{width:83.33333%}.medium-11{width:91.66667%}.medium-12{width:100%}.medium-offset-0{margin-left:0 !important}.medium-offset-1{margin-left:8.33333% !important}.medium-offset-2{margin-left:16.66667% !important}.medium-offset-3{margin-left:25% !important}.medium-offset-4{margin-left:33.33333% !important}.medium-offset-5{margin-left:41.66667% !important}.medium-offset-6{margin-left:50% !important}.medium-offset-7{margin-left:58.33333% !important}.medium-offset-8{margin-left:66.66667% !important}.medium-offset-9{margin-left:75% !important}.medium-offset-10{margin-left:83.33333% !important}.medium-offset-11{margin-left:91.66667% !important}.medium-reset-order{float:left;left:auto;margin-left:0;margin-right:0;right:auto}.column.medium-centered,.columns.medium-centered{margin-left:auto;margin-right:auto;float:none}.column.medium-uncentered,.columns.medium-uncentered{float:left;margin-left:0;margin-right:0}.column.medium-centered:last-child,.columns.medium-centered:last-child{float:none}.column.medium-uncentered:last-child,.columns.medium-uncentered:last-child{float:left}.column.medium-uncentered.opposite,.columns.medium-uncentered.opposite{float:right}.row.medium-collapse>.column,.row.medium-collapse>.columns{padding-left:0;padding-right:0}.row.medium-collapse .row{margin-left:0;margin-right:0}.row.medium-uncollapse>.column,.row.medium-uncollapse>.columns{padding-left:0.9375rem;padding-right:0.9375rem;float:left}.push-0{position:relative;left:0;right:auto}.pull-0{position:relative;right:0;left:auto}.push-1{position:relative;left:8.33333%;right:auto}.pull-1{position:relative;right:8.33333%;left:auto}.push-2{position:relative;left:16.66667%;right:auto}.pull-2{position:relative;right:16.66667%;left:auto}.push-3{position:relative;left:25%;right:auto}.pull-3{position:relative;right:25%;left:auto}.push-4{position:relative;left:33.33333%;right:auto}.pull-4{position:relative;right:33.33333%;left:auto}.push-5{position:relative;left:41.66667%;right:auto}.pull-5{position:relative;right:41.66667%;left:auto}.push-6{position:relative;left:50%;right:auto}.pull-6{position:relative;right:50%;left:auto}.push-7{position:relative;left:58.33333%;right:auto}.pull-7{position:relative;right:58.33333%;left:auto}.push-8{position:relative;left:66.66667%;right:auto}.pull-8{position:relative;right:66.66667%;left:auto}.push-9{position:relative;left:75%;right:auto}.pull-9{position:relative;right:75%;left:auto}.push-10{position:relative;left:83.33333%;right:auto}.pull-10{position:relative;right:83.33333%;left:auto}.push-11{position:relative;left:91.66667%;right:auto}.pull-11{position:relative;right:91.66667%;left:auto}}@media only screen and (min-width: 64.0625em){.large-push-0{position:relative;left:0;right:auto}.large-pull-0{position:relative;right:0;left:auto}.large-push-1{position:relative;left:8.33333%;right:auto}.large-pull-1{position:relative;right:8.33333%;left:auto}.large-push-2{position:relative;left:16.66667%;right:auto}.large-pull-2{position:relative;right:16.66667%;left:auto}.large-push-3{position:relative;left:25%;right:auto}.large-pull-3{position:relative;right:25%;left:auto}.large-push-4{position:relative;left:33.33333%;right:auto}.large-pull-4{position:relative;right:33.33333%;left:auto}.large-push-5{position:relative;left:41.66667%;right:auto}.large-pull-5{position:relative;right:41.66667%;left:auto}.large-push-6{position:relative;left:50%;right:auto}.large-pull-6{position:relative;right:50%;left:auto}.large-push-7{position:relative;left:58.33333%;right:auto}.large-pull-7{position:relative;right:58.33333%;left:auto}.large-push-8{position:relative;left:66.66667%;right:auto}.large-pull-8{position:relative;right:66.66667%;left:auto}.large-push-9{position:relative;left:75%;right:auto}.large-pull-9{position:relative;right:75%;left:auto}.large-push-10{position:relative;left:83.33333%;right:auto}.large-pull-10{position:relative;right:83.33333%;left:auto}.large-push-11{position:relative;left:91.66667%;right:auto}.large-pull-11{position:relative;right:91.66667%;left:auto}.column,.columns{position:relative;padding-left:0.9375rem;padding-right:0.9375rem;float:left}.large-1{width:8.33333%}.large-2{width:16.66667%}.large-3{width:25%}.large-4{width:33.33333%}.large-5{width:41.66667%}.large-6{width:50%}.large-7{width:58.33333%}.large-8{width:66.66667%}.large-9{width:75%}.large-10{width:83.33333%}.large-11{width:91.66667%}.large-12{width:100%}.large-offset-0{margin-left:0 !important}.large-offset-1{margin-left:8.33333% !important}.large-offset-2{margin-left:16.66667% !important}.large-offset-3{margin-left:25% !important}.large-offset-4{margin-left:33.33333% !important}.large-offset-5{margin-left:41.66667% !important}.large-offset-6{margin-left:50% !important}.large-offset-7{margin-left:58.33333% !important}.large-offset-8{margin-left:66.66667% !important}.large-offset-9{margin-left:75% !important}.large-offset-10{margin-left:83.33333% !important}.large-offset-11{margin-left:91.66667% !important}.large-reset-order{float:left;left:auto;margin-left:0;margin-right:0;right:auto}.column.large-centered,.columns.large-centered{margin-left:auto;margin-right:auto;float:none}.column.large-uncentered,.columns.large-uncentered{float:left;margin-left:0;margin-right:0}.column.large-centered:last-child,.columns.large-centered:last-child{float:none}.column.large-uncentered:last-child,.columns.large-uncentered:last-child{float:left}.column.large-uncentered.opposite,.columns.large-uncentered.opposite{float:right}.row.large-collapse>.column,.row.large-collapse>.columns{padding-left:0;padding-right:0}.row.large-collapse .row{margin-left:0;margin-right:0}.row.large-uncollapse>.column,.row.large-uncollapse>.columns{padding-left:0.9375rem;padding-right:0.9375rem;float:left}.push-0{position:relative;left:0;right:auto}.pull-0{position:relative;right:0;left:auto}.push-1{position:relative;left:8.33333%;right:auto}.pull-1{position:relative;right:8.33333%;left:auto}.push-2{position:relative;left:16.66667%;right:auto}.pull-2{position:relative;right:16.66667%;left:auto}.push-3{position:relative;left:25%;right:auto}.pull-3{position:relative;right:25%;left:auto}.push-4{position:relative;left:33.33333%;right:auto}.pull-4{position:relative;right:33.33333%;left:auto}.push-5{position:relative;left:41.66667%;right:auto}.pull-5{position:relative;right:41.66667%;left:auto}.push-6{position:relative;left:50%;right:auto}.pull-6{position:relative;right:50%;left:auto}.push-7{position:relative;left:58.33333%;right:auto}.pull-7{position:relative;right:58.33333%;left:auto}.push-8{position:relative;left:66.66667%;right:auto}.pull-8{position:relative;right:66.66667%;left:auto}.push-9{position:relative;left:75%;right:auto}.pull-9{position:relative;right:75%;left:auto}.push-10{position:relative;left:83.33333%;right:auto}.pull-10{position:relative;right:83.33333%;left:auto}.push-11{position:relative;left:91.66667%;right:auto}.pull-11{position:relative;right:91.66667%;left:auto}}[class*="block-grid-"]{display:block;padding:0;margin:0 -0.625rem}[class*="block-grid-"]:before,[class*="block-grid-"]:after{content:" ";display:table}[class*="block-grid-"]:after{clear:both}[class*="block-grid-"]>li{display:block;float:left;height:auto;padding:0 0.625rem 1.25rem}@media only screen{.small-block-grid-1>li{list-style:none;width:100%}.small-block-grid-1>li:nth-of-type(1n){clear:none}.small-block-grid-1>li:nth-of-type(1n+1){clear:both}.small-block-grid-2>li{list-style:none;width:50%}.small-block-grid-2>li:nth-of-type(1n){clear:none}.small-block-grid-2>li:nth-of-type(2n+1){clear:both}.small-block-grid-3>li{list-style:none;width:33.33333%}.small-block-grid-3>li:nth-of-type(1n){clear:none}.small-block-grid-3>li:nth-of-type(3n+1){clear:both}.small-block-grid-4>li{list-style:none;width:25%}.small-block-grid-4>li:nth-of-type(1n){clear:none}.small-block-grid-4>li:nth-of-type(4n+1){clear:both}.small-block-grid-5>li{list-style:none;width:20%}.small-block-grid-5>li:nth-of-type(1n){clear:none}.small-block-grid-5>li:nth-of-type(5n+1){clear:both}.small-block-grid-6>li{list-style:none;width:16.66667%}.small-block-grid-6>li:nth-of-type(1n){clear:none}.small-block-grid-6>li:nth-of-type(6n+1){clear:both}.small-block-grid-7>li{list-style:none;width:14.28571%}.small-block-grid-7>li:nth-of-type(1n){clear:none}.small-block-grid-7>li:nth-of-type(7n+1){clear:both}.small-block-grid-8>li{list-style:none;width:12.5%}.small-block-grid-8>li:nth-of-type(1n){clear:none}.small-block-grid-8>li:nth-of-type(8n+1){clear:both}.small-block-grid-9>li{list-style:none;width:11.11111%}.small-block-grid-9>li:nth-of-type(1n){clear:none}.small-block-grid-9>li:nth-of-type(9n+1){clear:both}.small-block-grid-10>li{list-style:none;width:10%}.small-block-grid-10>li:nth-of-type(1n){clear:none}.small-block-grid-10>li:nth-of-type(10n+1){clear:both}.small-block-grid-11>li{list-style:none;width:9.09091%}.small-block-grid-11>li:nth-of-type(1n){clear:none}.small-block-grid-11>li:nth-of-type(11n+1){clear:both}.small-block-grid-12>li{list-style:none;width:8.33333%}.small-block-grid-12>li:nth-of-type(1n){clear:none}.small-block-grid-12>li:nth-of-type(12n+1){clear:both}}@media only screen and (min-width: 40.0625em){.medium-block-grid-1>li{list-style:none;width:100%}.medium-block-grid-1>li:nth-of-type(1n){clear:none}.medium-block-grid-1>li:nth-of-type(1n+1){clear:both}.medium-block-grid-2>li{list-style:none;width:50%}.medium-block-grid-2>li:nth-of-type(1n){clear:none}.medium-block-grid-2>li:nth-of-type(2n+1){clear:both}.medium-block-grid-3>li{list-style:none;width:33.33333%}.medium-block-grid-3>li:nth-of-type(1n){clear:none}.medium-block-grid-3>li:nth-of-type(3n+1){clear:both}.medium-block-grid-4>li{list-style:none;width:25%}.medium-block-grid-4>li:nth-of-type(1n){clear:none}.medium-block-grid-4>li:nth-of-type(4n+1){clear:both}.medium-block-grid-5>li{list-style:none;width:20%}.medium-block-grid-5>li:nth-of-type(1n){clear:none}.medium-block-grid-5>li:nth-of-type(5n+1){clear:both}.medium-block-grid-6>li{list-style:none;width:16.66667%}.medium-block-grid-6>li:nth-of-type(1n){clear:none}.medium-block-grid-6>li:nth-of-type(6n+1){clear:both}.medium-block-grid-7>li{list-style:none;width:14.28571%}.medium-block-grid-7>li:nth-of-type(1n){clear:none}.medium-block-grid-7>li:nth-of-type(7n+1){clear:both}.medium-block-grid-8>li{list-style:none;width:12.5%}.medium-block-grid-8>li:nth-of-type(1n){clear:none}.medium-block-grid-8>li:nth-of-type(8n+1){clear:both}.medium-block-grid-9>li{list-style:none;width:11.11111%}.medium-block-grid-9>li:nth-of-type(1n){clear:none}.medium-block-grid-9>li:nth-of-type(9n+1){clear:both}.medium-block-grid-10>li{list-style:none;width:10%}.medium-block-grid-10>li:nth-of-type(1n){clear:none}.medium-block-grid-10>li:nth-of-type(10n+1){clear:both}.medium-block-grid-11>li{list-style:none;width:9.09091%}.medium-block-grid-11>li:nth-of-type(1n){clear:none}.medium-block-grid-11>li:nth-of-type(11n+1){clear:both}.medium-block-grid-12>li{list-style:none;width:8.33333%}.medium-block-grid-12>li:nth-of-type(1n){clear:none}.medium-block-grid-12>li:nth-of-type(12n+1){clear:both}}@media only screen and (min-width: 64.0625em){.large-block-grid-1>li{list-style:none;width:100%}.large-block-grid-1>li:nth-of-type(1n){clear:none}.large-block-grid-1>li:nth-of-type(1n+1){clear:both}.large-block-grid-2>li{list-style:none;width:50%}.large-block-grid-2>li:nth-of-type(1n){clear:none}.large-block-grid-2>li:nth-of-type(2n+1){clear:both}.large-block-grid-3>li{list-style:none;width:33.33333%}.large-block-grid-3>li:nth-of-type(1n){clear:none}.large-block-grid-3>li:nth-of-type(3n+1){clear:both}.large-block-grid-4>li{list-style:none;width:25%}.large-block-grid-4>li:nth-of-type(1n){clear:none}.large-block-grid-4>li:nth-of-type(4n+1){clear:both}.large-block-grid-5>li{list-style:none;width:20%}.large-block-grid-5>li:nth-of-type(1n){clear:none}.large-block-grid-5>li:nth-of-type(5n+1){clear:both}.large-block-grid-6>li{list-style:none;width:16.66667%}.large-block-grid-6>li:nth-of-type(1n){clear:none}.large-block-grid-6>li:nth-of-type(6n+1){clear:both}.large-block-grid-7>li{list-style:none;width:14.28571%}.large-block-grid-7>li:nth-of-type(1n){clear:none}.large-block-grid-7>li:nth-of-type(7n+1){clear:both}.large-block-grid-8>li{list-style:none;width:12.5%}.large-block-grid-8>li:nth-of-type(1n){clear:none}.large-block-grid-8>li:nth-of-type(8n+1){clear:both}.large-block-grid-9>li{list-style:none;width:11.11111%}.large-block-grid-9>li:nth-of-type(1n){clear:none}.large-block-grid-9>li:nth-of-type(9n+1){clear:both}.large-block-grid-10>li{list-style:none;width:10%}.large-block-grid-10>li:nth-of-type(1n){clear:none}.large-block-grid-10>li:nth-of-type(10n+1){clear:both}.large-block-grid-11>li{list-style:none;width:9.09091%}.large-block-grid-11>li:nth-of-type(1n){clear:none}.large-block-grid-11>li:nth-of-type(11n+1){clear:both}.large-block-grid-12>li{list-style:none;width:8.33333%}.large-block-grid-12>li:nth-of-type(1n){clear:none}.large-block-grid-12>li:nth-of-type(12n+1){clear:both}}.inline-list{list-style:none;margin-top:0;margin-bottom:1.0625rem;margin-left:-1.375rem;margin-right:0;overflow:hidden;padding:0}.inline-list>li{display:block;float:left;list-style:none;margin-left:1.375rem}.inline-list>li>*{display:block}.alert-box{border-style:solid;border-width:1px;display:block;font-size:0.8125rem;font-weight:normal;margin-bottom:1.25rem;padding:0.875rem 1.5rem 0.875rem 0.875rem;position:relative;transition:opacity 300ms ease-out;background-color:#008cba;border-color:#0078a0;color:#fff}.alert-box .close{right:0.25rem;background:inherit;color:#333;font-size:1.375rem;line-height:.9;margin-top:-0.6875rem;opacity:0.3;padding:0 6px 4px;position:absolute;top:50%}.alert-box .close:hover,.alert-box .close:focus{opacity:0.5}.alert-box.radius{border-radius:3px}.alert-box.round{border-radius:1000px}.alert-box.success{background-color:#43ac6a;border-color:#3a945b;color:#fff}.alert-box.alert{background-color:#f04124;border-color:#de2d0f;color:#fff}.alert-box.secondary{background-color:#e7e7e7;border-color:#c7c7c7;color:#4f4f4f}.alert-box.warning{background-color:#f08a24;border-color:#de770f;color:#fff}.alert-box.info{background-color:#a0d3e8;border-color:#74bfdd;color:#4f4f4f}.alert-box.alert-close{opacity:0}.reveal-modal-bg{background:#555;background:rgba(85,85,85,0.45);bottom:0;display:none;left:0;position:fixed;right:0;top:0;z-index:1004;left:0}.reveal-modal{border-radius:3px;display:none;position:absolute;top:0;visibility:hidden;width:100%;z-index:1005;left:0;background-color:#fff;padding:1.875rem;border:solid 1px #666;box-shadow:0 0 10px rgba(85,85,85,0.4)}@media only screen and (max-width: 40em){.reveal-modal{min-height:100vh}}.reveal-modal .column,.reveal-modal .columns{min-width:0}.reveal-modal>:first-child{margin-top:0}.reveal-modal>:last-child{margin-bottom:0}@media only screen and (min-width: 40.0625em){.reveal-modal{left:0;margin:0 auto;max-width:59.375rem;right:0;width:80%}}@media only screen and (min-width: 40.0625em){.reveal-modal{top:6.25rem}}.reveal-modal.radius{box-shadow:none;border-radius:3px}.reveal-modal.round{box-shadow:none;border-radius:1000px}.reveal-modal.collapse{padding:0;box-shadow:none}@media only screen and (min-width: 40.0625em){.reveal-modal.tiny{left:0;margin:0 auto;max-width:59.375rem;right:0;width:30%}}@media only screen and (min-width: 40.0625em){.reveal-modal.small{left:0;margin:0 auto;max-width:59.375rem;right:0;width:40%}}@media only screen and (min-width: 40.0625em){.reveal-modal.medium{left:0;margin:0 auto;max-width:59.375rem;right:0;width:60%}}@media only screen and (min-width: 40.0625em){.reveal-modal.large{left:0;margin:0 auto;max-width:59.375rem;right:0;width:70%}}@media only screen and (min-width: 40.0625em){.reveal-modal.xlarge{left:0;margin:0 auto;max-width:59.375rem;right:0;width:95%}}.reveal-modal.full{height:100vh;height:100%;left:0;margin-left:0 !important;max-width:none !important;min-height:100vh;top:0}@media only screen and (min-width: 40.0625em){.reveal-modal.full{left:0;margin:0 auto;max-width:59.375rem;right:0;width:100%}}.reveal-modal.toback{z-index:1003}.reveal-modal .close-reveal-modal{color:#aaa;cursor:pointer;font-size:2.5rem;font-weight:bold;line-height:1;position:absolute;top:0.625rem;right:1.375rem}button,.button{-webkit-appearance:none;-moz-appearance:none;border-radius:0;border-style:solid;border-width:0;cursor:pointer;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:normal;line-height:normal;margin:0 0 1.25rem;position:relative;text-align:center;text-decoration:none;display:inline-block;padding:1rem 2rem 1.0625rem 2rem;font-size:1rem;background-color:#008cba;border-color:#007095;color:#fff;transition:background-color 300ms ease-out}button:hover,button:focus,.button:hover,.button:focus{background-color:#007095}button:hover,button:focus,.button:hover,.button:focus{color:#fff}button.secondary,.button.secondary{background-color:#e7e7e7;border-color:#b9b9b9;color:#333}button.secondary:hover,button.secondary:focus,.button.secondary:hover,.button.secondary:focus{background-color:#b9b9b9}button.secondary:hover,button.secondary:focus,.button.secondary:hover,.button.secondary:focus{color:#333}button.success,.button.success{background-color:#43ac6a;border-color:#368a55;color:#fff}button.success:hover,button.success:focus,.button.success:hover,.button.success:focus{background-color:#368a55}button.success:hover,button.success:focus,.button.success:hover,.button.success:focus{color:#fff}button.alert,.button.alert{background-color:#f04124;border-color:#cf2a0e;color:#fff}button.alert:hover,button.alert:focus,.button.alert:hover,.button.alert:focus{background-color:#cf2a0e}button.alert:hover,button.alert:focus,.button.alert:hover,.button.alert:focus{color:#fff}button.warning,.button.warning{background-color:#f08a24;border-color:#cf6e0e;color:#fff}button.warning:hover,button.warning:focus,.button.warning:hover,.button.warning:focus{background-color:#cf6e0e}button.warning:hover,button.warning:focus,.button.warning:hover,.button.warning:focus{color:#fff}button.info,.button.info{background-color:#a0d3e8;border-color:#61b6d9;color:#333}button.info:hover,button.info:focus,.button.info:hover,.button.info:focus{background-color:#61b6d9}button.info:hover,button.info:focus,.button.info:hover,.button.info:focus{color:#fff}button.large,.button.large{padding:1.125rem 2.25rem 1.1875rem 2.25rem;font-size:1.25rem}button.small,.button.small{padding:0.875rem 1.75rem 0.9375rem 1.75rem;font-size:0.8125rem}button.tiny,.button.tiny{padding:0.625rem 1.25rem 0.6875rem 1.25rem;font-size:0.6875rem}button.expand,.button.expand{padding:1rem 2rem 1.0625rem 2rem;font-size:1rem;padding-bottom:1.0625rem;padding-top:1rem;padding-left:1rem;padding-right:1rem;width:100%}button.left-align,.button.left-align{text-align:left;text-indent:0.75rem}button.right-align,.button.right-align{text-align:right;padding-right:0.75rem}button.radius,.button.radius{border-radius:3px}button.round,.button.round{border-radius:1000px}button.disabled,button[disabled],.button.disabled,.button[disabled]{background-color:#008cba;border-color:#007095;color:#fff;box-shadow:none;cursor:default;opacity:0.7}button.disabled:hover,button.disabled:focus,button[disabled]:hover,button[disabled]:focus,.button.disabled:hover,.button.disabled:focus,.button[disabled]:hover,.button[disabled]:focus{background-color:#007095}button.disabled:hover,button.disabled:focus,button[disabled]:hover,button[disabled]:focus,.button.disabled:hover,.button.disabled:focus,.button[disabled]:hover,.button[disabled]:focus{color:#fff}button.disabled:hover,button.disabled:focus,button[disabled]:hover,button[disabled]:focus,.button.disabled:hover,.button.disabled:focus,.button[disabled]:hover,.button[disabled]:focus{background-color:#008cba}button.disabled.secondary,button[disabled].secondary,.button.disabled.secondary,.button[disabled].secondary{background-color:#e7e7e7;border-color:#b9b9b9;color:#333;box-shadow:none;cursor:default;opacity:0.7}button.disabled.secondary:hover,button.disabled.secondary:focus,button[disabled].secondary:hover,button[disabled].secondary:focus,.button.disabled.secondary:hover,.button.disabled.secondary:focus,.button[disabled].secondary:hover,.button[disabled].secondary:focus{background-color:#b9b9b9}button.disabled.secondary:hover,button.disabled.secondary:focus,button[disabled].secondary:hover,button[disabled].secondary:focus,.button.disabled.secondary:hover,.button.disabled.secondary:focus,.button[disabled].secondary:hover,.button[disabled].secondary:focus{color:#333}button.disabled.secondary:hover,button.disabled.secondary:focus,button[disabled].secondary:hover,button[disabled].secondary:focus,.button.disabled.secondary:hover,.button.disabled.secondary:focus,.button[disabled].secondary:hover,.button[disabled].secondary:focus{background-color:#e7e7e7}button.disabled.success,button[disabled].success,.button.disabled.success,.button[disabled].success{background-color:#43ac6a;border-color:#368a55;color:#fff;box-shadow:none;cursor:default;opacity:0.7}button.disabled.success:hover,button.disabled.success:focus,button[disabled].success:hover,button[disabled].success:focus,.button.disabled.success:hover,.button.disabled.success:focus,.button[disabled].success:hover,.button[disabled].success:focus{background-color:#368a55}button.disabled.success:hover,button.disabled.success:focus,button[disabled].success:hover,button[disabled].success:focus,.button.disabled.success:hover,.button.disabled.success:focus,.button[disabled].success:hover,.button[disabled].success:focus{color:#fff}button.disabled.success:hover,button.disabled.success:focus,button[disabled].success:hover,button[disabled].success:focus,.button.disabled.success:hover,.button.disabled.success:focus,.button[disabled].success:hover,.button[disabled].success:focus{background-color:#43ac6a}button.disabled.alert,button[disabled].alert,.button.disabled.alert,.button[disabled].alert{background-color:#f04124;border-color:#cf2a0e;color:#fff;box-shadow:none;cursor:default;opacity:0.7}button.disabled.alert:hover,button.disabled.alert:focus,button[disabled].alert:hover,button[disabled].alert:focus,.button.disabled.alert:hover,.button.disabled.alert:focus,.button[disabled].alert:hover,.button[disabled].alert:focus{background-color:#cf2a0e}button.disabled.alert:hover,button.disabled.alert:focus,button[disabled].alert:hover,button[disabled].alert:focus,.button.disabled.alert:hover,.button.disabled.alert:focus,.button[disabled].alert:hover,.button[disabled].alert:focus{color:#fff}button.disabled.alert:hover,button.disabled.alert:focus,button[disabled].alert:hover,button[disabled].alert:focus,.button.disabled.alert:hover,.button.disabled.alert:focus,.button[disabled].alert:hover,.button[disabled].alert:focus{background-color:#f04124}button.disabled.warning,button[disabled].warning,.button.disabled.warning,.button[disabled].warning{background-color:#f08a24;border-color:#cf6e0e;color:#fff;box-shadow:none;cursor:default;opacity:0.7}button.disabled.warning:hover,button.disabled.warning:focus,button[disabled].warning:hover,button[disabled].warning:focus,.button.disabled.warning:hover,.button.disabled.warning:focus,.button[disabled].warning:hover,.button[disabled].warning:focus{background-color:#cf6e0e}button.disabled.warning:hover,button.disabled.warning:focus,button[disabled].warning:hover,button[disabled].warning:focus,.button.disabled.warning:hover,.button.disabled.warning:focus,.button[disabled].warning:hover,.button[disabled].warning:focus{color:#fff}button.disabled.warning:hover,button.disabled.warning:focus,button[disabled].warning:hover,button[disabled].warning:focus,.button.disabled.warning:hover,.button.disabled.warning:focus,.button[disabled].warning:hover,.button[disabled].warning:focus{background-color:#f08a24}button.disabled.info,button[disabled].info,.button.disabled.info,.button[disabled].info{background-color:#a0d3e8;border-color:#61b6d9;color:#333;box-shadow:none;cursor:default;opacity:0.7}button.disabled.info:hover,button.disabled.info:focus,button[disabled].info:hover,button[disabled].info:focus,.button.disabled.info:hover,.button.disabled.info:focus,.button[disabled].info:hover,.button[disabled].info:focus{background-color:#61b6d9}button.disabled.info:hover,button.disabled.info:focus,button[disabled].info:hover,button[disabled].info:focus,.button.disabled.info:hover,.button.disabled.info:focus,.button[disabled].info:hover,.button[disabled].info:focus{color:#fff}button.disabled.info:hover,button.disabled.info:focus,button[disabled].info:hover,button[disabled].info:focus,.button.disabled.info:hover,.button.disabled.info:focus,.button[disabled].info:hover,.button[disabled].info:focus{background-color:#a0d3e8}button::-moz-focus-inner{border:0;padding:0}@media only screen and (min-width: 40.0625em){button,.button{display:inline-block}}.dropdown.button,button.dropdown{position:relative;padding-right:3.5625rem}.dropdown.button::after,button.dropdown::after{border-color:#fff transparent transparent transparent;border-style:solid;content:"";display:block;height:0;position:absolute;top:50%;width:0}.dropdown.button::after,button.dropdown::after{border-width:0.375rem;right:1.40625rem;margin-top:-0.15625rem}.dropdown.button::after,button.dropdown::after{border-color:#fff transparent transparent transparent}.dropdown.button.tiny,button.dropdown.tiny{padding-right:2.625rem}.dropdown.button.tiny:after,button.dropdown.tiny:after{border-width:0.375rem;right:1.125rem;margin-top:-0.125rem}.dropdown.button.tiny::after,button.dropdown.tiny::after{border-color:#fff transparent transparent transparent}.dropdown.button.small,button.dropdown.small{padding-right:3.0625rem}.dropdown.button.small::after,button.dropdown.small::after{border-width:0.4375rem;right:1.3125rem;margin-top:-0.15625rem}.dropdown.button.small::after,button.dropdown.small::after{border-color:#fff transparent transparent transparent}.dropdown.button.large,button.dropdown.large{padding-right:3.625rem}.dropdown.button.large::after,button.dropdown.large::after{border-width:0.3125rem;right:1.71875rem;margin-top:-0.15625rem}.dropdown.button.large::after,button.dropdown.large::after{border-color:#fff transparent transparent transparent}.dropdown.button.secondary:after,button.dropdown.secondary:after{border-color:#333 transparent transparent transparent}.split.button{position:relative;padding-right:5.0625rem}.split.button span{display:block;height:100%;position:absolute;right:0;top:0;border-left:solid 1px}.split.button span:after{position:absolute;content:"";width:0;height:0;display:block;border-style:inset;top:50%;left:50%}.split.button span:active{background-color:rgba(0,0,0,0.1)}.split.button span{border-left-color:rgba(255,255,255,0.5)}.split.button span{width:3.09375rem}.split.button span:after{border-top-style:solid;border-width:0.375rem;margin-left:-0.375rem;top:48%}.split.button span:after{border-color:#fff transparent transparent transparent}.split.button.secondary span{border-left-color:rgba(255,255,255,0.5)}.split.button.secondary span:after{border-color:#fff transparent transparent transparent}.split.button.alert span{border-left-color:rgba(255,255,255,0.5)}.split.button.success span{border-left-color:rgba(255,255,255,0.5)}.split.button.tiny{padding-right:3.75rem}.split.button.tiny span{width:2.25rem}.split.button.tiny span:after{border-top-style:solid;border-width:0.375rem;margin-left:-0.375rem;top:48%}.split.button.small{padding-right:4.375rem}.split.button.small span{width:2.625rem}.split.button.small span:after{border-top-style:solid;border-width:0.4375rem;margin-left:-0.375rem;top:48%}.split.button.large{padding-right:5.5rem}.split.button.large span{width:3.4375rem}.split.button.large span:after{border-top-style:solid;border-width:0.3125rem;margin-left:-0.375rem;top:48%}.split.button.expand{padding-left:2rem}.split.button.secondary span:after{border-color:#333 transparent transparent transparent}.split.button.radius span{-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}.split.button.round span{-webkit-border-bottom-right-radius:1000px;-webkit-border-top-right-radius:1000px;border-bottom-right-radius:1000px;border-top-right-radius:1000px}.split.button.no-pip span:before{border-style:none}.split.button.no-pip span:after{border-style:none}.split.button.no-pip span>i{display:block;left:50%;margin-left:-0.28889em;margin-top:-0.48889em;position:absolute;top:50%}table{background:#fff;border:solid 1px #ddd;margin-bottom:1.25rem;table-layout:auto}table caption{background:transparent;color:#222;font-size:1rem;font-weight:bold}table thead{background:#f5f5f5}table thead tr th,table thead tr td{color:#222;font-size:0.875rem;font-weight:bold;padding:0.5rem 0.625rem 0.625rem}table tfoot{background:#f5f5f5}table tfoot tr th,table tfoot tr td{color:#222;font-size:0.875rem;font-weight:bold;padding:0.5rem 0.625rem 0.625rem}table tr th,table tr td{color:#222;font-size:0.875rem;padding:0.5625rem 0.625rem;text-align:left}table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f9f9f9}table thead tr th,table tfoot tr th,table tfoot tr td,table tbody tr th,table tbody tr td,table tr td{display:table-cell;line-height:1.125rem}.text-left{text-align:left !important}.text-right{text-align:right !important}.text-center{text-align:center !important}.text-justify{text-align:justify !important}@media only screen and (max-width: 40em){.small-only-text-left{text-align:left !important}.small-only-text-right{text-align:right !important}.small-only-text-center{text-align:center !important}.small-only-text-justify{text-align:justify !important}}@media only screen{.small-text-left{text-align:left !important}.small-text-right{text-align:right !important}.small-text-center{text-align:center !important}.small-text-justify{text-align:justify !important}}@media only screen and (min-width: 40.0625em) and (max-width: 64em){.medium-only-text-left{text-align:left !important}.medium-only-text-right{text-align:right !important}.medium-only-text-center{text-align:center !important}.medium-only-text-justify{text-align:justify !important}}@media only screen and (min-width: 40.0625em){.medium-text-left{text-align:left !important}.medium-text-right{text-align:right !important}.medium-text-center{text-align:center !important}.medium-text-justify{text-align:justify !important}}@media only screen and (min-width: 64.0625em) and (max-width: 90em){.large-only-text-left{text-align:left !important}.large-only-text-right{text-align:right !important}.large-only-text-center{text-align:center !important}.large-only-text-justify{text-align:justify !important}}@media only screen and (min-width: 64.0625em){.large-text-left{text-align:left !important}.large-text-right{text-align:right !important}.large-text-center{text-align:center !important}.large-text-justify{text-align:justify !important}}@media only screen and (min-width: 90.0625em) and (max-width: 120em){.xlarge-only-text-left{text-align:left !important}.xlarge-only-text-right{text-align:right !important}.xlarge-only-text-center{text-align:center !important}.xlarge-only-text-justify{text-align:justify !important}}@media only screen and (min-width: 90.0625em){.xlarge-text-left{text-align:left !important}.xlarge-text-right{text-align:right !important}.xlarge-text-center{text-align:center !important}.xlarge-text-justify{text-align:justify !important}}@media only screen and (min-width: 120.0625em) and (max-width: 6249999.9375em){.xxlarge-only-text-left{text-align:left !important}.xxlarge-only-text-right{text-align:right !important}.xxlarge-only-text-center{text-align:center !important}.xxlarge-only-text-justify{text-align:justify !important}}@media only screen and (min-width: 120.0625em){.xxlarge-text-left{text-align:left !important}.xxlarge-text-right{text-align:right !important}.xxlarge-text-center{text-align:center !important}.xxlarge-text-justify{text-align:justify !important}}div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}a{color:#3fb1e5;line-height:inherit;text-decoration:none}a:hover,a:focus{color:#1ea1dd}a img{border:none}p{font-family:inherit;font-size:1rem;font-weight:normal;line-height:1.6;margin-bottom:1.25rem;text-rendering:optimizeLegibility}p.lead{font-size:1.21875rem;line-height:1.6}p aside{font-size:0.875rem;font-style:italic;line-height:1.35}h1,h2,h3,h4,h5,h6{color:#222;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:normal;line-height:1.4;margin-bottom:0.5rem;margin-top:0.2rem;text-rendering:optimizeLegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{color:#6f6f6f;font-size:60%;line-height:0}h1{font-size:2.125rem}h2{font-size:1.25rem}h3{font-size:1.375rem}h4{font-size:1.125rem}h5{font-size:1.125rem}h6{font-size:1rem}.subheader{line-height:1.4;color:#6f6f6f;font-weight:normal;margin-top:0.2rem;margin-bottom:0.5rem}hr{border:solid #ddd;border-width:1px 0 0;clear:both;height:0;margin:1.25rem 0 1.1875rem}em,i{font-style:italic;line-height:inherit}strong,b{font-weight:bold;line-height:inherit}small{font-size:60%;line-height:inherit}code{background-color:#f8f8f8;border-color:#dfdfdf;border-style:solid;border-width:1px;color:#333;font-family:Consolas,"Lucida Console",Monaco,monospace;font-weight:normal;padding:0.125rem 0.3125rem 0.0625rem}ul,ol,dl{font-family:inherit;font-size:1rem;line-height:1.6;list-style-position:outside;margin-bottom:1.25rem}ul{margin-left:1.1rem}ul li ul,ul li ol{margin-left:1.25rem;margin-bottom:0}ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}ul.square{list-style-type:square;margin-left:1.1rem}ul.circle{list-style-type:circle;margin-left:1.1rem}ul.disc{list-style-type:disc;margin-left:1.1rem}ol{margin-left:1.4rem}ol li ul,ol li ol{margin-left:1.25rem;margin-bottom:0}.no-bullet{list-style-type:none;margin-left:0}.no-bullet li ul,.no-bullet li ol{margin-left:1.25rem;margin-bottom:0;list-style:none}dl dt{margin-bottom:0.3rem;font-weight:bold}dl dd{margin-bottom:0.75rem}abbr,acronym{text-transform:uppercase;font-size:90%;color:#222;cursor:help}abbr{text-transform:none}abbr[title]{border-bottom:1px dotted #ddd}blockquote{margin:0 0 1.25rem;padding:0.5625rem 1.25rem 0 1.1875rem;border-left:1px solid #ddd}blockquote cite{display:block;font-size:0.8125rem;color:#555}blockquote cite:before{content:"\2014 \0020"}blockquote cite a,blockquote cite a:visited{color:#555}blockquote,blockquote p{line-height:1.6;color:#6f6f6f}.vcard{display:inline-block;margin:0 0 1.25rem 0;border:1px solid #ddd;padding:0.625rem 0.75rem}.vcard li{margin:0;display:block}.vcard .fn{font-weight:bold;font-size:0.9375rem}.vevent .summary{font-weight:bold}.vevent abbr{cursor:default;text-decoration:none;font-weight:bold;border:none;padding:0 0.0625rem}@media only screen and (min-width: 40.0625em){h1,h2,h3,h4,h5,h6{line-height:1.4}h1{font-size:2.75rem}h2{font-size:1.875rem}h3{font-size:1.6875rem}h4{font-size:1.4375rem}h5{font-size:1.125rem}h6{font-size:1rem}}@media print{*{background:transparent !important;color:#555 !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.34in}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}.off-canvas-wrap{-webkit-backface-visibility:hidden;position:relative;width:100%;overflow:hidden}.off-canvas-wrap.move-right,.off-canvas-wrap.move-left,.off-canvas-wrap.move-bottom,.off-canvas-wrap.move-top{min-height:100%;-webkit-overflow-scrolling:touch}.inner-wrap{position:relative;width:100%;-webkit-transition:-webkit-transform 500ms ease;-moz-transition:-moz-transform 500ms ease;-ms-transition:-ms-transform 500ms ease;-o-transition:-o-transform 500ms ease;transition:transform 500ms ease}.inner-wrap:before,.inner-wrap:after{content:" ";display:table}.inner-wrap:after{clear:both}.tab-bar{-webkit-backface-visibility:hidden;background:#333;color:#fff;height:2.8125rem;line-height:2.8125rem;position:relative}.tab-bar h1,.tab-bar h2,.tab-bar h3,.tab-bar h4,.tab-bar h5,.tab-bar h6{color:#fff;font-weight:bold;line-height:2.8125rem;margin:0}.tab-bar h1,.tab-bar h2,.tab-bar h3,.tab-bar h4{font-size:1.125rem}.left-small{height:2.8125rem;position:absolute;top:0;width:2.8125rem;border-right:solid 1px #1a1a1a;left:0}.right-small{height:2.8125rem;position:absolute;top:0;width:2.8125rem;border-left:solid 1px #1a1a1a;right:0}.tab-bar-section{height:2.8125rem;padding:0 0.625rem;position:absolute;text-align:center;top:0}.tab-bar-section.left{text-align:left}.tab-bar-section.right{text-align:right}.tab-bar-section.left{left:0;right:2.8125rem}.tab-bar-section.right{left:2.8125rem;right:0}.tab-bar-section.middle{left:2.8125rem;right:2.8125rem}.tab-bar .menu-icon{color:#fff;display:block;height:2.8125rem;padding:0;position:relative;text-indent:2.1875rem;transform:translate3d(0, 0, 0);width:2.8125rem}.tab-bar .menu-icon span::after{content:"";display:block;height:0;position:absolute;top:50%;margin-top:-0.5rem;left:0.90625rem;box-shadow:0 0 0 1px #fff,0 7px 0 1px #fff,0 14px 0 1px #fff;width:1rem}.tab-bar .menu-icon span:hover:after{box-shadow:0 0 0 1px #b3b3b3,0 7px 0 1px #b3b3b3,0 14px 0 1px #b3b3b3}.left-off-canvas-menu{-webkit-backface-visibility:hidden;background:#333;bottom:0;box-sizing:content-box;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;overflow-x:hidden;overflow-y:auto;position:absolute;transition:transform 500ms ease 0s;width:15.625rem;z-index:1001;-webkit-transform:translate3d(-100%, 0, 0);-moz-transform:translate3d(-100%, 0, 0);-ms-transform:translate(-100%, 0);-o-transform:translate3d(-100%, 0, 0);transform:translate3d(-100%, 0, 0);left:0;top:0}.left-off-canvas-menu *{-webkit-backface-visibility:hidden}.right-off-canvas-menu{-webkit-backface-visibility:hidden;background:#333;bottom:0;box-sizing:content-box;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;overflow-x:hidden;overflow-y:auto;position:absolute;transition:transform 500ms ease 0s;width:15.625rem;z-index:1001;-webkit-transform:translate3d(100%, 0, 0);-moz-transform:translate3d(100%, 0, 0);-ms-transform:translate(100%, 0);-o-transform:translate3d(100%, 0, 0);transform:translate3d(100%, 0, 0);right:0;top:0}.right-off-canvas-menu *{-webkit-backface-visibility:hidden}.top-off-canvas-menu{-webkit-backface-visibility:hidden;background:#333;bottom:0;box-sizing:content-box;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;overflow-x:hidden;overflow-y:auto;position:absolute;transition:transform 500ms ease 0s;width:15.625rem;z-index:1001;-webkit-transform:translate3d(0, -100%, 0);-moz-transform:translate3d(0, -100%, 0);-ms-transform:translate(0, -100%);-o-transform:translate3d(0, -100%, 0);transform:translate3d(0, -100%, 0);top:0;width:100%;height:18.75rem}.top-off-canvas-menu *{-webkit-backface-visibility:hidden}.bottom-off-canvas-menu{-webkit-backface-visibility:hidden;background:#333;bottom:0;box-sizing:content-box;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;overflow-x:hidden;overflow-y:auto;position:absolute;transition:transform 500ms ease 0s;width:15.625rem;z-index:1001;-webkit-transform:translate3d(0, 100%, 0);-moz-transform:translate3d(0, 100%, 0);-ms-transform:translate(0, 100%);-o-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0);bottom:0;width:100%;height:18.75rem}.bottom-off-canvas-menu *{-webkit-backface-visibility:hidden}ul.off-canvas-list{list-style-type:none;margin:0;padding:0}ul.off-canvas-list li label{background:#444;border-bottom:none;border-top:1px solid #5e5e5e;color:#999;display:block;font-size:0.75rem;font-weight:bold;margin:0;padding:0.3rem 0.9375rem;text-transform:uppercase}ul.off-canvas-list li a{border-bottom:1px solid #262626;color:rgba(255,255,255,0.7);display:block;padding:0.66667rem;transition:background 300ms ease}ul.off-canvas-list li a:hover{background:#242424}ul.off-canvas-list li a:active{background:#242424}.move-right>.inner-wrap{-webkit-transform:translate3d(15.625rem, 0, 0);-moz-transform:translate3d(15.625rem, 0, 0);-ms-transform:translate(15.625rem, 0);-o-transform:translate3d(15.625rem, 0, 0);transform:translate3d(15.625rem, 0, 0)}.move-right .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(85,85,85,0.5),4px 0 4px rgba(85,85,85,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.move-right .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}} +.move-left>.inner-wrap{-webkit-transform:translate3d(-15.625rem, 0, 0);-moz-transform:translate3d(-15.625rem, 0, 0);-ms-transform:translate(-15.625rem, 0);-o-transform:translate3d(-15.625rem, 0, 0);transform:translate3d(-15.625rem, 0, 0)}.move-left .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(85,85,85,0.5),4px 0 4px rgba(85,85,85,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.move-left .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}} +.move-top>.inner-wrap{-webkit-transform:translate3d(0, -18.75rem, 0);-moz-transform:translate3d(0, -18.75rem, 0);-ms-transform:translate(0, -18.75rem);-o-transform:translate3d(0, -18.75rem, 0);transform:translate3d(0, -18.75rem, 0)}.move-top .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(85,85,85,0.5),4px 0 4px rgba(85,85,85,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.move-top .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}} +.move-bottom>.inner-wrap{-webkit-transform:translate3d(0, 18.75rem, 0);-moz-transform:translate3d(0, 18.75rem, 0);-ms-transform:translate(0, 18.75rem);-o-transform:translate3d(0, 18.75rem, 0);transform:translate3d(0, 18.75rem, 0)}.move-bottom .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(85,85,85,0.5),4px 0 4px rgba(85,85,85,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.move-bottom .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}} +.offcanvas-overlap .left-off-canvas-menu,.offcanvas-overlap .right-off-canvas-menu,.offcanvas-overlap .top-off-canvas-menu,.offcanvas-overlap .bottom-off-canvas-menu{-ms-transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;transform:none;z-index:1003}.offcanvas-overlap .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(85,85,85,0.5),4px 0 4px rgba(85,85,85,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.offcanvas-overlap .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}} +.offcanvas-overlap-left .right-off-canvas-menu{-ms-transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;transform:none;z-index:1003}.offcanvas-overlap-left .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(85,85,85,0.5),4px 0 4px rgba(85,85,85,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.offcanvas-overlap-left .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}} +.offcanvas-overlap-right .left-off-canvas-menu{-ms-transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;transform:none;z-index:1003}.offcanvas-overlap-right .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(85,85,85,0.5),4px 0 4px rgba(85,85,85,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.offcanvas-overlap-right .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}} +.offcanvas-overlap-top .bottom-off-canvas-menu{-ms-transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;transform:none;z-index:1003}.offcanvas-overlap-top .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(85,85,85,0.5),4px 0 4px rgba(85,85,85,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.offcanvas-overlap-top .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}} +.offcanvas-overlap-bottom .top-off-canvas-menu{-ms-transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;transform:none;z-index:1003}.offcanvas-overlap-bottom .exit-off-canvas{-webkit-backface-visibility:hidden;box-shadow:-4px 0 4px rgba(85,85,85,0.5),4px 0 4px rgba(85,85,85,0.5);cursor:pointer;transition:background 300ms ease;-webkit-tap-highlight-color:transparent;background:rgba(255,255,255,0.2);bottom:0;display:block;left:0;position:absolute;right:0;top:0;z-index:1002}@media only screen and (min-width: 40.0625em){.offcanvas-overlap-bottom .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}} +.no-csstransforms .left-off-canvas-menu{left:-15.625rem}.no-csstransforms .right-off-canvas-menu{right:-15.625rem}.no-csstransforms .top-off-canvas-menu{top:-18.75rem}.no-csstransforms .bottom-off-canvas-menu{bottom:-18.75rem}.no-csstransforms .move-left>.inner-wrap{right:15.625rem}.no-csstransforms .move-right>.inner-wrap{left:15.625rem}.no-csstransforms .move-top>.inner-wrap{right:18.75rem}.no-csstransforms .move-bottom>.inner-wrap{left:18.75rem}.left-submenu{-webkit-backface-visibility:hidden;-webkit-overflow-scrolling:touch;background:#333;bottom:0;box-sizing:content-box;margin:0;overflow-x:hidden;overflow-y:auto;position:absolute;top:0;width:15.625rem;height:18.75rem;z-index:1002;-webkit-transform:translate3d(-100%, 0, 0);-moz-transform:translate3d(-100%, 0, 0);-ms-transform:translate(-100%, 0);-o-transform:translate3d(-100%, 0, 0);transform:translate3d(-100%, 0, 0);left:0;-webkit-transition:-webkit-transform 500ms ease;-moz-transition:-moz-transform 500ms ease;-ms-transition:-ms-transform 500ms ease;-o-transition:-o-transform 500ms ease;transition:transform 500ms ease}.left-submenu *{-webkit-backface-visibility:hidden}.left-submenu .back>a{background:#444;border-bottom:none;border-top:1px solid #5e5e5e;color:#999;font-weight:bold;padding:0.3rem 0.9375rem;text-transform:uppercase;margin:0}.left-submenu .back>a:hover{background:#303030;border-bottom:none;border-top:1px solid #5e5e5e}.left-submenu .back>a:before{content:"\AB";margin-right:.5rem;display:inline}.left-submenu.move-right,.left-submenu.offcanvas-overlap-right,.left-submenu.offcanvas-overlap{-webkit-transform:translate3d(0%, 0, 0);-moz-transform:translate3d(0%, 0, 0);-ms-transform:translate(0%, 0);-o-transform:translate3d(0%, 0, 0);transform:translate3d(0%, 0, 0)}.right-submenu{-webkit-backface-visibility:hidden;-webkit-overflow-scrolling:touch;background:#333;bottom:0;box-sizing:content-box;margin:0;overflow-x:hidden;overflow-y:auto;position:absolute;top:0;width:15.625rem;height:18.75rem;z-index:1002;-webkit-transform:translate3d(100%, 0, 0);-moz-transform:translate3d(100%, 0, 0);-ms-transform:translate(100%, 0);-o-transform:translate3d(100%, 0, 0);transform:translate3d(100%, 0, 0);right:0;-webkit-transition:-webkit-transform 500ms ease;-moz-transition:-moz-transform 500ms ease;-ms-transition:-ms-transform 500ms ease;-o-transition:-o-transform 500ms ease;transition:transform 500ms ease}.right-submenu *{-webkit-backface-visibility:hidden}.right-submenu .back>a{background:#444;border-bottom:none;border-top:1px solid #5e5e5e;color:#999;font-weight:bold;padding:0.3rem 0.9375rem;text-transform:uppercase;margin:0}.right-submenu .back>a:hover{background:#303030;border-bottom:none;border-top:1px solid #5e5e5e}.right-submenu .back>a:after{content:"\BB";margin-left:.5rem;display:inline}.right-submenu.move-left,.right-submenu.offcanvas-overlap-left,.right-submenu.offcanvas-overlap{-webkit-transform:translate3d(0%, 0, 0);-moz-transform:translate3d(0%, 0, 0);-ms-transform:translate(0%, 0);-o-transform:translate3d(0%, 0, 0);transform:translate3d(0%, 0, 0)}.top-submenu{-webkit-backface-visibility:hidden;-webkit-overflow-scrolling:touch;background:#333;bottom:0;box-sizing:content-box;margin:0;overflow-x:hidden;overflow-y:auto;position:absolute;top:0;width:15.625rem;height:18.75rem;z-index:1002;-webkit-transform:translate3d(0, -100%, 0);-moz-transform:translate3d(0, -100%, 0);-ms-transform:translate(0, -100%);-o-transform:translate3d(0, -100%, 0);transform:translate3d(0, -100%, 0);top:0;width:100%;-webkit-transition:-webkit-transform 500ms ease;-moz-transition:-moz-transform 500ms ease;-ms-transition:-ms-transform 500ms ease;-o-transition:-o-transform 500ms ease;transition:transform 500ms ease}.top-submenu *{-webkit-backface-visibility:hidden}.top-submenu .back>a{background:#444;border-bottom:none;border-top:1px solid #5e5e5e;color:#999;font-weight:bold;padding:0.3rem 0.9375rem;text-transform:uppercase;margin:0}.top-submenu .back>a:hover{background:#303030;border-bottom:none;border-top:1px solid #5e5e5e}.top-submenu.move-bottom,.top-submenu.offcanvas-overlap-bottom,.top-submenu.offcanvas-overlap{-webkit-transform:translate3d(0, 0%, 0);-moz-transform:translate3d(0, 0%, 0);-ms-transform:translate(0, 0%);-o-transform:translate3d(0, 0%, 0);transform:translate3d(0, 0%, 0)}.bottom-submenu{-webkit-backface-visibility:hidden;-webkit-overflow-scrolling:touch;background:#333;bottom:0;box-sizing:content-box;margin:0;overflow-x:hidden;overflow-y:auto;position:absolute;top:0;width:15.625rem;height:18.75rem;z-index:1002;-webkit-transform:translate3d(0, 100%, 0);-moz-transform:translate3d(0, 100%, 0);-ms-transform:translate(0, 100%);-o-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0);bottom:0;width:100%;-webkit-transition:-webkit-transform 500ms ease;-moz-transition:-moz-transform 500ms ease;-ms-transition:-ms-transform 500ms ease;-o-transition:-o-transform 500ms ease;transition:transform 500ms ease}.bottom-submenu *{-webkit-backface-visibility:hidden}.bottom-submenu .back>a{background:#444;border-bottom:none;border-top:1px solid #5e5e5e;color:#999;font-weight:bold;padding:0.3rem 0.9375rem;text-transform:uppercase;margin:0}.bottom-submenu .back>a:hover{background:#303030;border-bottom:none;border-top:1px solid #5e5e5e}.bottom-submenu.move-top,.bottom-submenu.offcanvas-overlap-top,.bottom-submenu.offcanvas-overlap{-webkit-transform:translate3d(0, 0%, 0);-moz-transform:translate3d(0, 0%, 0);-ms-transform:translate(0, 0%);-o-transform:translate3d(0, 0%, 0);transform:translate3d(0, 0%, 0)}.left-off-canvas-menu ul.off-canvas-list li.has-submenu>a:after{content:"\BB";margin-left:.5rem;display:inline}.right-off-canvas-menu ul.off-canvas-list li.has-submenu>a:before{content:"\AB";margin-right:.5rem;display:inline}@media only screen{.show-for-small-only,.show-for-small-up,.show-for-small,.show-for-small-down,.hide-for-medium-only,.hide-for-medium-up,.hide-for-medium,.show-for-medium-down,.hide-for-large-only,.hide-for-large-up,.hide-for-large,.show-for-large-down,.hide-for-xlarge-only,.hide-for-xlarge-up,.hide-for-xxlarge-only,.hide-for-xxlarge-up{display:inherit !important}.hide-for-small-only,.hide-for-small-up,.hide-for-small,.hide-for-small-down,.show-for-medium-only,.show-for-medium-up,.show-for-medium,.hide-for-medium-down,.show-for-large-only,.show-for-large-up,.show-for-large,.hide-for-large-down,.show-for-xlarge-only,.show-for-xlarge-up,.show-for-xxlarge-only,.show-for-xxlarge-up{display:none !important}.visible-for-small-only,.visible-for-small-up,.visible-for-small,.visible-for-small-down,.hidden-for-medium-only,.hidden-for-medium-up,.hidden-for-medium,.visible-for-medium-down,.hidden-for-large-only,.hidden-for-large-up,.hidden-for-large,.visible-for-large-down,.hidden-for-xlarge-only,.hidden-for-xlarge-up,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.hidden-for-small-only,.hidden-for-small-up,.hidden-for-small,.hidden-for-small-down,.visible-for-medium-only,.visible-for-medium-up,.visible-for-medium,.hidden-for-medium-down,.visible-for-large-only,.visible-for-large-up,.visible-for-large,.hidden-for-large-down,.visible-for-xlarge-only,.visible-for-xlarge-up,.visible-for-xxlarge-only,.visible-for-xxlarge-up{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}table.show-for-small-only,table.show-for-small-up,table.show-for-small,table.show-for-small-down,table.hide-for-medium-only,table.hide-for-medium-up,table.hide-for-medium,table.show-for-medium-down,table.hide-for-large-only,table.hide-for-large-up,table.hide-for-large,table.show-for-large-down,table.hide-for-xlarge-only,table.hide-for-xlarge-up,table.hide-for-xxlarge-only,table.hide-for-xxlarge-up{display:table !important}thead.show-for-small-only,thead.show-for-small-up,thead.show-for-small,thead.show-for-small-down,thead.hide-for-medium-only,thead.hide-for-medium-up,thead.hide-for-medium,thead.show-for-medium-down,thead.hide-for-large-only,thead.hide-for-large-up,thead.hide-for-large,thead.show-for-large-down,thead.hide-for-xlarge-only,thead.hide-for-xlarge-up,thead.hide-for-xxlarge-only,thead.hide-for-xxlarge-up{display:table-header-group !important}tbody.show-for-small-only,tbody.show-for-small-up,tbody.show-for-small,tbody.show-for-small-down,tbody.hide-for-medium-only,tbody.hide-for-medium-up,tbody.hide-for-medium,tbody.show-for-medium-down,tbody.hide-for-large-only,tbody.hide-for-large-up,tbody.hide-for-large,tbody.show-for-large-down,tbody.hide-for-xlarge-only,tbody.hide-for-xlarge-up,tbody.hide-for-xxlarge-only,tbody.hide-for-xxlarge-up{display:table-row-group !important}tr.show-for-small-only,tr.show-for-small-up,tr.show-for-small,tr.show-for-small-down,tr.hide-for-medium-only,tr.hide-for-medium-up,tr.hide-for-medium,tr.show-for-medium-down,tr.hide-for-large-only,tr.hide-for-large-up,tr.hide-for-large,tr.show-for-large-down,tr.hide-for-xlarge-only,tr.hide-for-xlarge-up,tr.hide-for-xxlarge-only,tr.hide-for-xxlarge-up{display:table-row}th.show-for-small-only,td.show-for-small-only,th.show-for-small-up,td.show-for-small-up,th.show-for-small,td.show-for-small,th.show-for-small-down,td.show-for-small-down,th.hide-for-medium-only,td.hide-for-medium-only,th.hide-for-medium-up,td.hide-for-medium-up,th.hide-for-medium,td.hide-for-medium,th.show-for-medium-down,td.show-for-medium-down,th.hide-for-large-only,td.hide-for-large-only,th.hide-for-large-up,td.hide-for-large-up,th.hide-for-large,td.hide-for-large,th.show-for-large-down,td.show-for-large-down,th.hide-for-xlarge-only,td.hide-for-xlarge-only,th.hide-for-xlarge-up,td.hide-for-xlarge-up,th.hide-for-xxlarge-only,td.hide-for-xxlarge-only,th.hide-for-xxlarge-up,td.hide-for-xxlarge-up{display:table-cell !important}}@media only screen and (min-width: 40.0625em){.hide-for-small-only,.show-for-small-up,.hide-for-small,.hide-for-small-down,.show-for-medium-only,.show-for-medium-up,.show-for-medium,.show-for-medium-down,.hide-for-large-only,.hide-for-large-up,.hide-for-large,.show-for-large-down,.hide-for-xlarge-only,.hide-for-xlarge-up,.hide-for-xxlarge-only,.hide-for-xxlarge-up{display:inherit !important}.show-for-small-only,.hide-for-small-up,.show-for-small,.show-for-small-down,.hide-for-medium-only,.hide-for-medium-up,.hide-for-medium,.hide-for-medium-down,.show-for-large-only,.show-for-large-up,.show-for-large,.hide-for-large-down,.show-for-xlarge-only,.show-for-xlarge-up,.show-for-xxlarge-only,.show-for-xxlarge-up{display:none !important}.hidden-for-small-only,.visible-for-small-up,.hidden-for-small,.hidden-for-small-down,.visible-for-medium-only,.visible-for-medium-up,.visible-for-medium,.visible-for-medium-down,.hidden-for-large-only,.hidden-for-large-up,.hidden-for-large,.visible-for-large-down,.hidden-for-xlarge-only,.hidden-for-xlarge-up,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.visible-for-small-only,.hidden-for-small-up,.visible-for-small,.visible-for-small-down,.hidden-for-medium-only,.hidden-for-medium-up,.hidden-for-medium,.hidden-for-medium-down,.visible-for-large-only,.visible-for-large-up,.visible-for-large,.hidden-for-large-down,.visible-for-xlarge-only,.visible-for-xlarge-up,.visible-for-xxlarge-only,.visible-for-xxlarge-up{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}table.hide-for-small-only,table.show-for-small-up,table.hide-for-small,table.hide-for-small-down,table.show-for-medium-only,table.show-for-medium-up,table.show-for-medium,table.show-for-medium-down,table.hide-for-large-only,table.hide-for-large-up,table.hide-for-large,table.show-for-large-down,table.hide-for-xlarge-only,table.hide-for-xlarge-up,table.hide-for-xxlarge-only,table.hide-for-xxlarge-up{display:table !important}thead.hide-for-small-only,thead.show-for-small-up,thead.hide-for-small,thead.hide-for-small-down,thead.show-for-medium-only,thead.show-for-medium-up,thead.show-for-medium,thead.show-for-medium-down,thead.hide-for-large-only,thead.hide-for-large-up,thead.hide-for-large,thead.show-for-large-down,thead.hide-for-xlarge-only,thead.hide-for-xlarge-up,thead.hide-for-xxlarge-only,thead.hide-for-xxlarge-up{display:table-header-group !important}tbody.hide-for-small-only,tbody.show-for-small-up,tbody.hide-for-small,tbody.hide-for-small-down,tbody.show-for-medium-only,tbody.show-for-medium-up,tbody.show-for-medium,tbody.show-for-medium-down,tbody.hide-for-large-only,tbody.hide-for-large-up,tbody.hide-for-large,tbody.show-for-large-down,tbody.hide-for-xlarge-only,tbody.hide-for-xlarge-up,tbody.hide-for-xxlarge-only,tbody.hide-for-xxlarge-up{display:table-row-group !important}tr.hide-for-small-only,tr.show-for-small-up,tr.hide-for-small,tr.hide-for-small-down,tr.show-for-medium-only,tr.show-for-medium-up,tr.show-for-medium,tr.show-for-medium-down,tr.hide-for-large-only,tr.hide-for-large-up,tr.hide-for-large,tr.show-for-large-down,tr.hide-for-xlarge-only,tr.hide-for-xlarge-up,tr.hide-for-xxlarge-only,tr.hide-for-xxlarge-up{display:table-row}th.hide-for-small-only,td.hide-for-small-only,th.show-for-small-up,td.show-for-small-up,th.hide-for-small,td.hide-for-small,th.hide-for-small-down,td.hide-for-small-down,th.show-for-medium-only,td.show-for-medium-only,th.show-for-medium-up,td.show-for-medium-up,th.show-for-medium,td.show-for-medium,th.show-for-medium-down,td.show-for-medium-down,th.hide-for-large-only,td.hide-for-large-only,th.hide-for-large-up,td.hide-for-large-up,th.hide-for-large,td.hide-for-large,th.show-for-large-down,td.show-for-large-down,th.hide-for-xlarge-only,td.hide-for-xlarge-only,th.hide-for-xlarge-up,td.hide-for-xlarge-up,th.hide-for-xxlarge-only,td.hide-for-xxlarge-only,th.hide-for-xxlarge-up,td.hide-for-xxlarge-up{display:table-cell !important}}@media only screen and (min-width: 64.0625em){.hide-for-small-only,.show-for-small-up,.hide-for-small,.hide-for-small-down,.hide-for-medium-only,.show-for-medium-up,.hide-for-medium,.hide-for-medium-down,.show-for-large-only,.show-for-large-up,.show-for-large,.show-for-large-down,.hide-for-xlarge-only,.hide-for-xlarge-up,.hide-for-xxlarge-only,.hide-for-xxlarge-up{display:inherit !important}.show-for-small-only,.hide-for-small-up,.show-for-small,.show-for-small-down,.show-for-medium-only,.hide-for-medium-up,.show-for-medium,.show-for-medium-down,.hide-for-large-only,.hide-for-large-up,.hide-for-large,.hide-for-large-down,.show-for-xlarge-only,.show-for-xlarge-up,.show-for-xxlarge-only,.show-for-xxlarge-up{display:none !important}.hidden-for-small-only,.visible-for-small-up,.hidden-for-small,.hidden-for-small-down,.hidden-for-medium-only,.visible-for-medium-up,.hidden-for-medium,.hidden-for-medium-down,.visible-for-large-only,.visible-for-large-up,.visible-for-large,.visible-for-large-down,.hidden-for-xlarge-only,.hidden-for-xlarge-up,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.visible-for-small-only,.hidden-for-small-up,.visible-for-small,.visible-for-small-down,.visible-for-medium-only,.hidden-for-medium-up,.visible-for-medium,.visible-for-medium-down,.hidden-for-large-only,.hidden-for-large-up,.hidden-for-large,.hidden-for-large-down,.visible-for-xlarge-only,.visible-for-xlarge-up,.visible-for-xxlarge-only,.visible-for-xxlarge-up{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}table.hide-for-small-only,table.show-for-small-up,table.hide-for-small,table.hide-for-small-down,table.hide-for-medium-only,table.show-for-medium-up,table.hide-for-medium,table.hide-for-medium-down,table.show-for-large-only,table.show-for-large-up,table.show-for-large,table.show-for-large-down,table.hide-for-xlarge-only,table.hide-for-xlarge-up,table.hide-for-xxlarge-only,table.hide-for-xxlarge-up{display:table !important}thead.hide-for-small-only,thead.show-for-small-up,thead.hide-for-small,thead.hide-for-small-down,thead.hide-for-medium-only,thead.show-for-medium-up,thead.hide-for-medium,thead.hide-for-medium-down,thead.show-for-large-only,thead.show-for-large-up,thead.show-for-large,thead.show-for-large-down,thead.hide-for-xlarge-only,thead.hide-for-xlarge-up,thead.hide-for-xxlarge-only,thead.hide-for-xxlarge-up{display:table-header-group !important}tbody.hide-for-small-only,tbody.show-for-small-up,tbody.hide-for-small,tbody.hide-for-small-down,tbody.hide-for-medium-only,tbody.show-for-medium-up,tbody.hide-for-medium,tbody.hide-for-medium-down,tbody.show-for-large-only,tbody.show-for-large-up,tbody.show-for-large,tbody.show-for-large-down,tbody.hide-for-xlarge-only,tbody.hide-for-xlarge-up,tbody.hide-for-xxlarge-only,tbody.hide-for-xxlarge-up{display:table-row-group !important}tr.hide-for-small-only,tr.show-for-small-up,tr.hide-for-small,tr.hide-for-small-down,tr.hide-for-medium-only,tr.show-for-medium-up,tr.hide-for-medium,tr.hide-for-medium-down,tr.show-for-large-only,tr.show-for-large-up,tr.show-for-large,tr.show-for-large-down,tr.hide-for-xlarge-only,tr.hide-for-xlarge-up,tr.hide-for-xxlarge-only,tr.hide-for-xxlarge-up{display:table-row}th.hide-for-small-only,td.hide-for-small-only,th.show-for-small-up,td.show-for-small-up,th.hide-for-small,td.hide-for-small,th.hide-for-small-down,td.hide-for-small-down,th.hide-for-medium-only,td.hide-for-medium-only,th.show-for-medium-up,td.show-for-medium-up,th.hide-for-medium,td.hide-for-medium,th.hide-for-medium-down,td.hide-for-medium-down,th.show-for-large-only,td.show-for-large-only,th.show-for-large-up,td.show-for-large-up,th.show-for-large,td.show-for-large,th.show-for-large-down,td.show-for-large-down,th.hide-for-xlarge-only,td.hide-for-xlarge-only,th.hide-for-xlarge-up,td.hide-for-xlarge-up,th.hide-for-xxlarge-only,td.hide-for-xxlarge-only,th.hide-for-xxlarge-up,td.hide-for-xxlarge-up{display:table-cell !important}}@media only screen and (min-width: 90.0625em){.hide-for-small-only,.show-for-small-up,.hide-for-small,.hide-for-small-down,.hide-for-medium-only,.show-for-medium-up,.hide-for-medium,.hide-for-medium-down,.hide-for-large-only,.show-for-large-up,.hide-for-large,.hide-for-large-down,.show-for-xlarge-only,.show-for-xlarge-up,.hide-for-xxlarge-only,.hide-for-xxlarge-up{display:inherit !important}.show-for-small-only,.hide-for-small-up,.show-for-small,.show-for-small-down,.show-for-medium-only,.hide-for-medium-up,.show-for-medium,.show-for-medium-down,.show-for-large-only,.hide-for-large-up,.show-for-large,.show-for-large-down,.hide-for-xlarge-only,.hide-for-xlarge-up,.show-for-xxlarge-only,.show-for-xxlarge-up{display:none !important}.hidden-for-small-only,.visible-for-small-up,.hidden-for-small,.hidden-for-small-down,.hidden-for-medium-only,.visible-for-medium-up,.hidden-for-medium,.hidden-for-medium-down,.hidden-for-large-only,.visible-for-large-up,.hidden-for-large,.hidden-for-large-down,.visible-for-xlarge-only,.visible-for-xlarge-up,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.visible-for-small-only,.hidden-for-small-up,.visible-for-small,.visible-for-small-down,.visible-for-medium-only,.hidden-for-medium-up,.visible-for-medium,.visible-for-medium-down,.visible-for-large-only,.hidden-for-large-up,.visible-for-large,.visible-for-large-down,.hidden-for-xlarge-only,.hidden-for-xlarge-up,.visible-for-xxlarge-only,.visible-for-xxlarge-up{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}table.hide-for-small-only,table.show-for-small-up,table.hide-for-small,table.hide-for-small-down,table.hide-for-medium-only,table.show-for-medium-up,table.hide-for-medium,table.hide-for-medium-down,table.hide-for-large-only,table.show-for-large-up,table.hide-for-large,table.hide-for-large-down,table.show-for-xlarge-only,table.show-for-xlarge-up,table.hide-for-xxlarge-only,table.hide-for-xxlarge-up{display:table !important}thead.hide-for-small-only,thead.show-for-small-up,thead.hide-for-small,thead.hide-for-small-down,thead.hide-for-medium-only,thead.show-for-medium-up,thead.hide-for-medium,thead.hide-for-medium-down,thead.hide-for-large-only,thead.show-for-large-up,thead.hide-for-large,thead.hide-for-large-down,thead.show-for-xlarge-only,thead.show-for-xlarge-up,thead.hide-for-xxlarge-only,thead.hide-for-xxlarge-up{display:table-header-group !important}tbody.hide-for-small-only,tbody.show-for-small-up,tbody.hide-for-small,tbody.hide-for-small-down,tbody.hide-for-medium-only,tbody.show-for-medium-up,tbody.hide-for-medium,tbody.hide-for-medium-down,tbody.hide-for-large-only,tbody.show-for-large-up,tbody.hide-for-large,tbody.hide-for-large-down,tbody.show-for-xlarge-only,tbody.show-for-xlarge-up,tbody.hide-for-xxlarge-only,tbody.hide-for-xxlarge-up{display:table-row-group !important}tr.hide-for-small-only,tr.show-for-small-up,tr.hide-for-small,tr.hide-for-small-down,tr.hide-for-medium-only,tr.show-for-medium-up,tr.hide-for-medium,tr.hide-for-medium-down,tr.hide-for-large-only,tr.show-for-large-up,tr.hide-for-large,tr.hide-for-large-down,tr.show-for-xlarge-only,tr.show-for-xlarge-up,tr.hide-for-xxlarge-only,tr.hide-for-xxlarge-up{display:table-row}th.hide-for-small-only,td.hide-for-small-only,th.show-for-small-up,td.show-for-small-up,th.hide-for-small,td.hide-for-small,th.hide-for-small-down,td.hide-for-small-down,th.hide-for-medium-only,td.hide-for-medium-only,th.show-for-medium-up,td.show-for-medium-up,th.hide-for-medium,td.hide-for-medium,th.hide-for-medium-down,td.hide-for-medium-down,th.hide-for-large-only,td.hide-for-large-only,th.show-for-large-up,td.show-for-large-up,th.hide-for-large,td.hide-for-large,th.hide-for-large-down,td.hide-for-large-down,th.show-for-xlarge-only,td.show-for-xlarge-only,th.show-for-xlarge-up,td.show-for-xlarge-up,th.hide-for-xxlarge-only,td.hide-for-xxlarge-only,th.hide-for-xxlarge-up,td.hide-for-xxlarge-up{display:table-cell !important}}@media only screen and (min-width: 120.0625em){.hide-for-small-only,.show-for-small-up,.hide-for-small,.hide-for-small-down,.hide-for-medium-only,.show-for-medium-up,.hide-for-medium,.hide-for-medium-down,.hide-for-large-only,.show-for-large-up,.hide-for-large,.hide-for-large-down,.hide-for-xlarge-only,.show-for-xlarge-up,.show-for-xxlarge-only,.show-for-xxlarge-up{display:inherit !important}.show-for-small-only,.hide-for-small-up,.show-for-small,.show-for-small-down,.show-for-medium-only,.hide-for-medium-up,.show-for-medium,.show-for-medium-down,.show-for-large-only,.hide-for-large-up,.show-for-large,.show-for-large-down,.show-for-xlarge-only,.hide-for-xlarge-up,.hide-for-xxlarge-only,.hide-for-xxlarge-up{display:none !important}.hidden-for-small-only,.visible-for-small-up,.hidden-for-small,.hidden-for-small-down,.hidden-for-medium-only,.visible-for-medium-up,.hidden-for-medium,.hidden-for-medium-down,.hidden-for-large-only,.visible-for-large-up,.hidden-for-large,.hidden-for-large-down,.hidden-for-xlarge-only,.visible-for-xlarge-up,.visible-for-xxlarge-only,.visible-for-xxlarge-up{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.visible-for-small-only,.hidden-for-small-up,.visible-for-small,.visible-for-small-down,.visible-for-medium-only,.hidden-for-medium-up,.visible-for-medium,.visible-for-medium-down,.visible-for-large-only,.hidden-for-large-up,.visible-for-large,.visible-for-large-down,.visible-for-xlarge-only,.hidden-for-xlarge-up,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}table.hide-for-small-only,table.show-for-small-up,table.hide-for-small,table.hide-for-small-down,table.hide-for-medium-only,table.show-for-medium-up,table.hide-for-medium,table.hide-for-medium-down,table.hide-for-large-only,table.show-for-large-up,table.hide-for-large,table.hide-for-large-down,table.hide-for-xlarge-only,table.show-for-xlarge-up,table.show-for-xxlarge-only,table.show-for-xxlarge-up{display:table !important}thead.hide-for-small-only,thead.show-for-small-up,thead.hide-for-small,thead.hide-for-small-down,thead.hide-for-medium-only,thead.show-for-medium-up,thead.hide-for-medium,thead.hide-for-medium-down,thead.hide-for-large-only,thead.show-for-large-up,thead.hide-for-large,thead.hide-for-large-down,thead.hide-for-xlarge-only,thead.show-for-xlarge-up,thead.show-for-xxlarge-only,thead.show-for-xxlarge-up{display:table-header-group !important}tbody.hide-for-small-only,tbody.show-for-small-up,tbody.hide-for-small,tbody.hide-for-small-down,tbody.hide-for-medium-only,tbody.show-for-medium-up,tbody.hide-for-medium,tbody.hide-for-medium-down,tbody.hide-for-large-only,tbody.show-for-large-up,tbody.hide-for-large,tbody.hide-for-large-down,tbody.hide-for-xlarge-only,tbody.show-for-xlarge-up,tbody.show-for-xxlarge-only,tbody.show-for-xxlarge-up{display:table-row-group !important}tr.hide-for-small-only,tr.show-for-small-up,tr.hide-for-small,tr.hide-for-small-down,tr.hide-for-medium-only,tr.show-for-medium-up,tr.hide-for-medium,tr.hide-for-medium-down,tr.hide-for-large-only,tr.show-for-large-up,tr.hide-for-large,tr.hide-for-large-down,tr.hide-for-xlarge-only,tr.show-for-xlarge-up,tr.show-for-xxlarge-only,tr.show-for-xxlarge-up{display:table-row}th.hide-for-small-only,td.hide-for-small-only,th.show-for-small-up,td.show-for-small-up,th.hide-for-small,td.hide-for-small,th.hide-for-small-down,td.hide-for-small-down,th.hide-for-medium-only,td.hide-for-medium-only,th.show-for-medium-up,td.show-for-medium-up,th.hide-for-medium,td.hide-for-medium,th.hide-for-medium-down,td.hide-for-medium-down,th.hide-for-large-only,td.hide-for-large-only,th.show-for-large-up,td.show-for-large-up,th.hide-for-large,td.hide-for-large,th.hide-for-large-down,td.hide-for-large-down,th.hide-for-xlarge-only,td.hide-for-xlarge-only,th.show-for-xlarge-up,td.show-for-xlarge-up,th.show-for-xxlarge-only,td.show-for-xxlarge-only,th.show-for-xxlarge-up,td.show-for-xxlarge-up{display:table-cell !important}}.show-for-landscape,.hide-for-portrait{display:inherit !important}.hide-for-landscape,.show-for-portrait{display:none !important}table.hide-for-landscape,table.show-for-portrait{display:table !important}thead.hide-for-landscape,thead.show-for-portrait{display:table-header-group !important}tbody.hide-for-landscape,tbody.show-for-portrait{display:table-row-group !important}tr.hide-for-landscape,tr.show-for-portrait{display:table-row !important}td.hide-for-landscape,td.show-for-portrait,th.hide-for-landscape,th.show-for-portrait{display:table-cell !important}@media only screen and (orientation: landscape){.show-for-landscape,.hide-for-portrait{display:inherit !important}.hide-for-landscape,.show-for-portrait{display:none !important}table.show-for-landscape,table.hide-for-portrait{display:table !important}thead.show-for-landscape,thead.hide-for-portrait{display:table-header-group !important}tbody.show-for-landscape,tbody.hide-for-portrait{display:table-row-group !important}tr.show-for-landscape,tr.hide-for-portrait{display:table-row !important}td.show-for-landscape,td.hide-for-portrait,th.show-for-landscape,th.hide-for-portrait{display:table-cell !important}}@media only screen and (orientation: portrait){.show-for-portrait,.hide-for-landscape{display:inherit !important}.hide-for-portrait,.show-for-landscape{display:none !important}table.show-for-portrait,table.hide-for-landscape{display:table !important}thead.show-for-portrait,thead.hide-for-landscape{display:table-header-group !important}tbody.show-for-portrait,tbody.hide-for-landscape{display:table-row-group !important}tr.show-for-portrait,tr.hide-for-landscape{display:table-row !important}td.show-for-portrait,td.hide-for-landscape,th.show-for-portrait,th.hide-for-landscape{display:table-cell !important}}.show-for-touch{display:none !important}.hide-for-touch{display:inherit !important}.touch .show-for-touch{display:inherit !important}.touch .hide-for-touch{display:none !important}table.hide-for-touch{display:table !important}.touch table.show-for-touch{display:table !important}thead.hide-for-touch{display:table-header-group !important}.touch thead.show-for-touch{display:table-header-group !important}tbody.hide-for-touch{display:table-row-group !important}.touch tbody.show-for-touch{display:table-row-group !important}tr.hide-for-touch{display:table-row !important}.touch tr.show-for-touch{display:table-row !important}td.hide-for-touch{display:table-cell !important}.touch td.show-for-touch{display:table-cell !important}th.hide-for-touch{display:table-cell !important}.touch th.show-for-touch{display:table-cell !important}.show-for-sr{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}.show-on-focus{clip:rect(1px, 1px, 1px, 1px);height:1px;overflow:hidden;position:absolute !important;width:1px}.show-on-focus:focus,.show-on-focus:active{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.print-only,.show-for-print{display:none !important}@media print{.print-only,.show-for-print{display:block !important}.hide-on-print,.hide-for-print{display:none !important}table.show-for-print{display:table !important}thead.show-for-print{display:table-header-group !important}tbody.show-for-print{display:table-row-group !important}tr.show-for-print{display:table-row !important}td.show-for-print{display:table-cell !important}th.show-for-print{display:table-cell !important}}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.7.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"),url("../fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:0.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}@font-face{font-family:'klinic';src:url("../fonts/klinicslabbook-webfont.eot");src:url("../fonts/klinicslabbook-webfont.eot?#iefix") format("embedded-opentype"),url("../fonts/klinicslabbook-webfont.woff2") format("woff2"),url("../fonts/klinicslabbook-webfont.woff") format("woff"),url("../fonts/klinicslabbook-webfont.ttf") format("truetype"),url("../fonts/klinicslabbook-webfont.svg#klinic_slabbook") format("svg");font-weight:400;font-style:normal}@font-face{font-family:'klinic';src:url("../fonts/klinicslabmedium-webfont.eot");src:url("../fonts/klinicslabmedium-webfont.eot?#iefix") format("embedded-opentype"),url("../fonts/klinicslabmedium-webfont.woff2") format("woff2"),url("../fonts/klinicslabmedium-webfont.woff") format("woff"),url("../fonts/klinicslabmedium-webfont.ttf") format("truetype"),url("../fonts/klinicslabmedium-webfont.svg#klinic_slabmedium") format("svg");font-weight:500;font-style:normal}h1{font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:500;letter-spacing:0.02em}h2,h3,h4,h5{font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:400;letter-spacing:0.0125em}a.button{color:white}a.button:hover{color:white}a.button.hollow{color:#4e4e4e}.button{transition:all 0.3s ease-in-out;background-color:#3fb1e5;color:white}.button:hover{background-color:#1d9bd4;color:white}.button.hollow{background-color:transparent;border:2px solid #dbdbdb}.button.hollow:hover,.button.hollow:active{background-color:transparent;border:2px solid #ff7590}.button.primary{background-color:#ff2a53;color:white}.button.primary:hover,.button.primary:active{background-color:#f6002f;color:white}.button.secondary{background-color:#3fb1e5;color:white}.button.secondary:hover,.button.secondary:active{background-color:#1d9bd4;color:white}.button .fa{font-size:0.875em;margin:0.25em 1.5em}.button .fa.left{margin-left:-0.7em}.button .fa.right{margin-right:-0.7em}.button .fa.fa-github{font-size:19px;margin:initial;padding-right:10px}.button .fa.fa-caret-up,.button .fa.fa-caret-down{margin:initial}.geo-shapes{padding-bottom:2em}.geo-shapes hr{border-width:5px 0 0;margin-top:-0.667em;margin-left:40%;margin-right:40%;opacity:0.13}.geo-shapes span{position:relative;z-index:650;margin:0 0 -2em}.shapes .row{display:block}.shapes .row span{display:inline-block;width:10%;padding-bottom:10%;height:0;overflow:hidden;float:left;position:relative}.shapes .row span em{transform:rotate(45deg);display:block;width:150%;padding-bottom:150%;position:absolute;right:-75%;top:-81.5%;height:0}.shapes .shape-row-6>span{width:16.666%;padding-bottom:16.666%}.shapes .shape-row-8>span{width:12.5%;padding-bottom:12.5%}.shapes .shape-row-12>span{width:8.3333%;padding-bottom:8.3333%}.shapes .s-p{background:#ff2a53}.shapes .s-b{background:#3fb1e5}.shapes .s-g{background:#38bb4c}.shapes .s-pl{background:#ff7590}.shapes .s-bl{background:#7fccf0}.shapes .s-gl{background:#68d478}.shapes .s-pd{background:#ef637e}.shapes .s-bd{background:#27759a}.shapes .s-gd{background:#44a653}.shapes .s-d1{background:#4e4e4e}.shapes .s-d2{background:#464646}.shapes .s-l1{background:#f4f4f4}.shapes .s-l2{background:#e4e4e4}.shapes .s-w{background:#fff}.shapes.shapes-animate .row{display:block}.shapes.shapes-animate .row span{transition:all 0.85s ease-in-out}.shapes.shapes-animate .row span:hover{transform:rotate(90deg)}.shape-position{width:100%}.shape-position .row{max-width:100%}.shape-position.shape-position-top{position:absolute;top:0%}.shape-position.shape-position-bottom{position:absolute;bottom:0%}.shape-position.shape-position-bottom .row span em{transform:rotate(45deg);left:-75%;right:auto;top:-81.5%}@media only screen and (max-width: 40.063em){.billboard-home section{width:100%;z-index:50}.billboard-home section h1{font-size:1.425em}.billboard-home section p{font-size:0.925em;margin:0 20% 2em}.billboard-home section .button{min-width:85%;margin:0.25em 7.5%;max-width:200px}.content-wrap{margin-bottom:-225px !important}footer{height:225px !important}.shape-position.shape-position-bottom{bottom:-3.5em;width:117.5%;z-index:150}.off-canvas-wrap.move-right,.off-canvas-wrap.move-left{height:100%}.off-canvas-wrap.move-right .inner-wrap,.off-canvas-wrap.move-right .content-wrap,.off-canvas-wrap.move-left .inner-wrap,.off-canvas-wrap.move-left .content-wrap{height:100%}.off-canvas-wrap.move-right .inner-wrap+footer,.off-canvas-wrap.move-right .content-wrap+footer,.off-canvas-wrap.move-left .inner-wrap+footer,.off-canvas-wrap.move-left .content-wrap+footer{display:none}aside.right-off-canvas-menu ul:first-child{height:100%;max-height:100%;overflow-y:scroll}aside.right-off-canvas-menu ul:first-child ul{height:auto;margin:0 0 1.25em 0}aside.right-off-canvas-menu ul:first-child ul li a{font-size:0.875em;padding-left:2.75rem;opacity:0.75}}.navbar{background:#fff;padding:15px 0;position:fixed;width:100%;z-index:10000;height:82px;transition:box-shadow 0.2s;transform-style:preserve-3d;height:82px;border-bottom:2px solid #f4f4f4;text-align:center}.navbar .row{max-width:100%}.navbar h1{margin:0;line-height:1;text-align:left}.navbar nav{height:1em;text-align:center}.navbar nav ul.inline-list{margin:1em auto 0;display:inline-block;width:auto;padding-right:2em}.navbar nav li{margin-left:0}.navbar nav li:last-child{margin-right:0}.navbar nav li a{font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:400;letter-spacing:0.0125em;position:relative;display:inline-block;text-align:center;transition:all 0.3s ease-in-out;font-size:1.125em;line-height:1;letter-spacing:0.035em;color:#ff2a53;margin-right:3em}.navbar nav li a::after{display:inline-block;content:"";background:#ff2a53;height:3px;width:10%;opacity:0;margin:-0.75em auto 0;transition:all 0.3s ease-in-out}.navbar nav li a:hover::after{width:100%;opacity:1}.navbar nav li a:hover{color:#ff2a53}.navbar nav li a.active{color:#ff2a53}.navbar nav li a.active::after{width:100%;opacity:1}.navbar nav li a.dropdown{display:block}.navbar nav li a.dropdown em{padding-left:0.75em;margin-left:0.425em;border-left:1px dotted #cbcbcb;display:inline-block}.navbar nav li a.dropdown .fa{font-size:0.75em;display:inline-block;transition:all 0.3s ease-in-out}.navbar nav li a.dropdown[aria-expanded=true] .fa{transform:rotate(180deg)}.navbar nav .button{margin:-1.25em 0 0;color:#ff2a53}.navbar nav .button:hover{border-color:#ff7590}.headroom{transition:transform 200ms linear;position:fixed;top:0;z-index:1000}.headroom.headroom--pinned{transform:translateY(0%);box-shadow:0 0 10px rgba(100,100,100,0.15)}.headroom.headroom--top{box-shadow:none}.headroom.headroom--unpinned{transform:translateY(-100%)}ul.f-dropdown{display:none !important}ul.f-open-dropdown{display:block !important;position:fixed !important;top:0px !important;left:0 !important;right:0 !important;padding:85px 8.25% 0;max-width:100% !important;width:100%;z-index:800 !important;box-shadow:none;background:white !important;border-bottom:2px solid #f4f4f4}ul.f-open-dropdown .fa-times{position:fixed;top:40px;right:40px;color:#818181;font-size:2em}ul.f-open-dropdown:before{display:none}ul.f-open-dropdown li{text-align:center;margin:0;display:inline-block}ul.f-open-dropdown li:hover{background:transparent}ul.f-open-dropdown li a{display:block;text-align:left;padding:0.333em 0.25em 0.333em 0;font-size:1.5em;background-color:transparent;min-height:75px;overflow:hidden;position:relative;transition:all 0.3s ease-in-out}ul.f-open-dropdown li a img{position:absolute;top:47.5%;transform:translateY(-47.5%);left:0;max-width:45px;margin:0 0.75em 0.5em 0}ul.f-open-dropdown li a h3,ul.f-open-dropdown li a p{margin:0 0 0 3.75rem;width:100%;display:block;text-align:left}ul.f-open-dropdown li a h3{font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:500;letter-spacing:0.02em;font-size:1em}ul.f-open-dropdown li a p{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:0.425em;color:#a3a3a3}ul.f-open-dropdown li a:after{display:block;content:" ";width:1%;height:4px;background:#ff2a53;position:absolute;bottom:4px;left:50%;margin:0 auto;opacity:0;transition:all 0.3s ease-in-out}ul.f-open-dropdown li a:hover{background-color:transparent !important}ul.f-open-dropdown li a:hover:after{width:100%;left:0;opacity:1}.right-off-canvas-toggle.fa{color:#e4e4e4;font-size:1.5em;padding:1em 0.5em;position:absolute;margin-top:-0.5em;top:0;right:0;z-index:1250;transition:all 0.3s ease-in-out}.right-off-canvas-toggle.fa:hover{background:#fdfdfd;color:#4e4e4e}aside.right-off-canvas-menu ul{margin:1.25em 0}aside.right-off-canvas-menu ul li{font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:400;letter-spacing:0.0125em}aside.right-off-canvas-menu ul li a{color:white;padding:0.5em 2em;display:block;line-height:1.2;transition:all 0.3s ease-in-out}aside.right-off-canvas-menu ul li a:hover{background:#bf1435}aside.right-off-canvas-menu .button{margin:2.5em 10% 1em;width:80%}footer{padding:0;z-index:1020;position:relative;height:335px;background:white;margin-left:290px}@media only screen and (max-width: 40em){footer{margin-left:0}}footer .logo{margin:0 0 2em}footer p.copyright{font-size:12px;line-height:1.6;color:#8e8e8e;max-width:220px;margin:0.75em 0 0}footer p.copyright .separator{opacity:0.5}footer p.copyright a{color:#8e8e8e}footer p.copyright a:hover{color:#3fb1e5}footer p.copyright img{margin:-3px 0.2em 0;max-height:15px}footer .panel-newsletter{padding:1.25em 0}@media only screen and (max-width: 40em){footer .panel-newsletter{padding:0.75em 0}}footer .panel-newsletter .subscribe #mc_embed_signup_scroll{position:relative}footer .panel-newsletter .subscribe label,footer .panel-newsletter .subscribe .button,footer .panel-newsletter .subscribe div.mce_inline_error{position:absolute;left:-999em}footer .panel-newsletter .subscribe input{background-color:#f4f4f4;border:none;outline:none;display:block;color:#3fb1e5;border-bottom:1px solid #3fb1e5;font-size:0.75em;padding:0;height:2.5em;margin:-0.5em 0 0;box-shadow:none;transition:all 0.3s ease-in-out;font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:500;letter-spacing:0.02em}footer .panel-newsletter .subscribe input#mce-EMAIL{width:100%}footer .panel-newsletter .subscribe input::-webkit-input-placeholder{color:#3fb1e5 !important}footer .panel-newsletter .subscribe input::-moz-placeholder,footer .panel-newsletter .subscribe input:-moz-placeholder{color:#3fb1e5 !important}footer .panel-newsletter .subscribe input::-ms-input-placeholder{color:#3fb1e5 !important}footer .panel-newsletter .subscribe input::placeholder-shown{color:#3fb1e5 !important}footer .panel-newsletter .subscribe:after{position:absolute;color:#4e4e4e;opacity:0.25;right:0.925em;top:0.125em;font-size:0.75em;font-family:'FontAwesome';display:inline-block;content:"\f054"}footer .panel-newsletter .social nav{white-space:nowrap;margin-right:5%}footer .panel-newsletter .social nav a{font-size:1.125em;margin:0 1.5em 0 0;color:#4e4e4e;opacity:0.425;transition:all 0.3s ease-in-out}footer .panel-newsletter .social nav a:hover{opacity:1;color:#3fb1e5}footer #mc_embed_signup #mce-error-response,footer #mc_embed_signup div.mce_inline_error{left:0;top:-1.2em;background-color:transparent;padding:0;color:#ff2a53;font-size:10px}footer #mc_embed_signup #mce-error-response{color:#38bb4c}footer #mc_embed_signup #mce-success-response{color:#38bb4c;font-size:11px;padding:0.2em 10% 0 0}footer .panel-links{padding-top:2.5em;background:white}@media only screen and (min-width: 40.063em){footer .panel-links{padding-bottom:0;font-size:1.25rem}}footer .panel-links dl{font-size:0.925em;float:left;margin:0.75em 0 2em 7.5%}@media only screen and (max-width: 40em){footer .panel-links dl{float:left;min-width:30%;margin:0 5%;line-height:1}}footer .panel-links dl dt{font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:500;letter-spacing:0.02em;font-size:0.875em}footer .panel-links dl dt a{color:#ff2a53;position:relative;display:inline-block;text-align:center;transition:all 0.3s ease-in-out;text-align:left;line-height:1}footer .panel-links dl dt a::after{display:inline-block;content:"";background:#ff2a53;height:3px;width:10%;opacity:0;margin:-0.75em auto 0;transition:all 0.3s ease-in-out}footer .panel-links dl dt a:hover::after{width:100%;opacity:1}footer .panel-links dl dd{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:bold;font-size:0.667em}@media only screen and (max-width: 40em){footer .panel-links dl dd{display:none}}footer .panel-links dl dd a{color:#4e4e4e;transition:all 0.3s ease-in-out}footer .panel-links dl dd a:hover{color:#3fb1e5}@media only screen and (max-width: 40em){.panel--newsletter{display:none}} +html,body{height:100%}.off-canvas-wrap,.inner-wrap{min-height:100%}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;overflow-x:hidden}body .row{max-width:75rem}body .row.fullwidth{max-width:100%;padding-left:1.25em;padding-right:1.25em}.content-wrap{position:relative;padding-left:320px;min-height:100%;margin-bottom:-335px}@media only screen and (max-width: 40em){.content-wrap{padding-left:5%;padding-right:5%}}@media only screen and (min-width: 40.0625em) and (max-width: 64em){.content-wrap{padding-left:5%;padding-right:5%}}.content-wrap:after{content:"";display:block;height:390px}.content-inner{width:auto;max-width:800px;margin-left:auto;margin-right:auto;padding-top:128px;padding-bottom:128px}.sidebar{width:290px;position:fixed;top:0;left:0;background:white;z-index:1010;height:100%;overflow-y:scroll;border-bottom:2px solid #f4f4f4}.alert-box.banner{background:#ff2a53;text-align:center;color:white;position:relative;z-index:10;display:block;margin-left:290px;padding:88px 0 8px;margin-bottom:-75px;font-size:0.925rem;letter-spacing:0.025em}.alert-box.banner a{color:white;border-bottom:1px dotted white}.sidebar .sidebar-inner{padding:120px 0 40px;max-width:320px;position:relative;z-index:50}.sidebar .sidebar-inner h1{margin:0 0 70px;padding:0;border-bottom:2px solid #f4f4f4;height:82px;width:290px;position:fixed;top:0}.sidebar .sidebar-inner h1:hover{border-color:#3fb1e5}.sidebar .sidebar-inner h1 a.logo{padding:0 0 0 0.825em;display:block;line-height:78px;background:white;border-right:2px solid #f4f4f4}.sidebar .sidebar-inner h1 a.logo img{margin-top:-10px}.sidebar .sidebar-inner:hover li a{color:#8f8f8f}.sidebar .sidebar-inner ul,.sidebar .sidebar-inner li{list-style:none;padding:0;margin:0}.sidebar .sidebar-inner li{font-size:1.125em}.sidebar .sidebar-inner li a{padding:0.333em 2.5em;display:inline-block;width:100%;color:#b7b7b7;font-size:0.825em;transition:all 0.3s ease-in-out}.sidebar .sidebar-inner li a[state=open],.sidebar .sidebar-inner li a.current{color:#ff2a53;font-weight:bold}.sidebar .sidebar-inner li a[state=open]+ul>li a,.sidebar .sidebar-inner li a.current+ul>li a{font-weight:normal !important;color:#4e4e4e}.sidebar .sidebar-inner li a[state=open]+ul>li a:before,.sidebar .sidebar-inner li a.current+ul>li a:before{content:" ";position:absolute;width:8px;height:8px;border-radius:4px;display:inline-block;border:4px solid #fff4f7;margin:0.5em 0 0 0;left:2.8em}.sidebar .sidebar-inner li a:hover{background:#f4f4f4}.sidebar .sidebar-inner li.toctree-l1.current ul{display:block !important}.sidebar .sidebar-inner ul{padding-bottom:1.5em}.sidebar .sidebar-inner li li a{padding-left:4em;font-size:0.75em}.sidebar .sidebar-bg{position:fixed;top:0;bottom:0;width:290px;border-right:2px solid #f4f4f4;z-index:10}.content-inner h1 .headerlink,.content-inner h2 .headerlink,.content-inner h3 .headerlink,.content-inner h4 .headerlink,.content-inner h5 .headerlink,.content-inner h6 .headerlink{opacity:0;margin:0 0 0 0.75em;font-size:0.75em;color:#8e8e8e;transition:all 0.3s ease-in-out}.content-inner *:hover>.headerlink{opacity:1}.content-inner a{background-color:#fefefe;color:#2fabe3;transition:all 0.3s ease-in-out}.content-inner a:hover{color:#7fccf0}.content-inner h1,.content-inner h2,.content-inner h3,.content-inner h4,.content-inner h5,.content-inner h6,.content-inner p,.content-inner li{padding-right:5%}.content-inner h1{color:#4e4e4e}.content-inner h1:not(:first-child){margin-top:1.5em}.content-inner h1+p{font-size:1.333em;margin-bottom:3.5em;padding-right:2.5%;line-height:1.75;font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:400;letter-spacing:0.0125em}.content-inner h1+p:not(:first-child){margin-bottom:1.5em}.content-inner h2{margin-top:2em;font-size:1.75em;color:#ff2a53}.content-inner p{margin-top:0.5em;line-height:1.925;margin-bottom:1.25em}.content-inner ol,.content-inner ul,.content-inner dl{line-height:1.5;margin-bottom:1.75em}.content-inner ol li,.content-inner ul li,.content-inner dl li{margin-bottom:0.5em}.content-inner pre,.content-inner code{font-family:Consolas,"Lucida Console",Monaco,monospace;border:none;background:#4e4e4e;color:white;border:4px solid transparent;font-size:0.825rem;transition:all 0.3s ease-in-out}.content-inner code{padding:0;box-shadow:0 0 0 1px #f4f4f4;background:#f4f4f4;color:#464646}.content-inner pre{line-height:1.636;padding:0.5em 0.75em;margin:1em 0 2em;display:inline-block;width:100%;background:#4e4e4e;color:white}.content-inner pre code{background:#4e4e4e;color:white;box-shadow:0 0 0 1px #4e4e4e;display:block}.content-inner pre:hover{background:#464646;border-left:4px solid #ff2a53}.content-inner pre:hover code{background:#464646;box-shadow:0 0 0 1px #464646}.content-inner .version-warning{padding:10px;margin-top:10px;border:solid 4px #ff2a53}.content-inner .version-warning .version-warning-title{font-size:18px;font-weight:bold;line-height:26px;text-indent:50px}.content-inner .version-warning .important .version-warning-title{background:url(../img/glyphs.png) no-repeat 0 -81px}.content-inner .version-warning a,.content-inner .version-warning a em,.content-inner .version-warning em{font-style:normal !important;color:#ff2a53 !important}.content-inner .admonition{padding:0.25em 1.5em;margin-bottom:1.5em;border:solid 4px #38bb4c}.content-inner .admonition .admonition-title{font-size:18px;font-weight:bold;line-height:26px;text-indent:50px}.content-inner .warning{border:solid 4px #ff2a53}.content-inner .warning .admonition-title{background:url(../img/glyphs.png) no-repeat}.content-inner .note .admonition-title{background:url(../img/glyphs.png) no-repeat 0 -25px}.content-inner .tip .admonition-title{background:url(../img/glyphs.png) no-repeat 0 -53px}.content-inner .important .admonition-title{background:url(../img/glyphs.png) no-repeat 0 -81px}.content-inner .hint .admonition-title{background:url(../img/glyphs.png) no-repeat 0 -108px}.content-inner .attention .admonition-title{background:url(../img/glyphs.png) no-repeat 0 -135px}.content-inner .caution .admonition-title{background:url(../img/glyphs.png) no-repeat 0 -160px}.content-inner .danger .admonition-title{background:url(../img/glyphs.png) no-repeat 0 -186px}.content-inner .error .admonition-title{background:url(../img/glyphs.png) no-repeat 0 -218px}@media only screen and (max-width: 40em){.content-wrap{padding-left:0px}.alert-box.banner{margin-left:0}.navbar h1{margin:0.1em 0 0.125em -0.75em}.content-inner{padding-top:105px;padding-left:1em;padding-right:1em}.content-inner h1,.content-inner h2,.content-inner h3,.content-inner h4,.content-inner h5,.content-inner h6,.content-inner p,.content-inner li{padding-right:0%}.content-inner h1{font-size:1.75em}.content-inner h1+p{font-size:1.25em;line-height:1.4}}.panel{font-size:21px;padding:40px 0;width:100%;position:relative}@media only screen and (max-width: 40em){.panel{padding:10px 0}}.panel.-blue{background-color:#3fb1e5;color:#fff}@media only screen and (min-width: 40.063em){.panel.-blue{padding-top:60px}}.panel.-blue h1,.panel.-blue h2,.panel.-blue p{color:#555}.panel.-gray{background-color:#f4f4f4}.geo-shapes-title{margin:0 auto}.geo-shapes-title.blue h2 hr.border{border-color:#3fb1e5}.geo-shapes-title.pink h2 hr.border{border-color:#ff2a53}.geo-shapes-title h2{display:inline-block;line-height:1;padding:0 1em;margin:0 0 1.5em;font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:500;letter-spacing:0.02em}.geo-shapes-title h2 hr.border{border-color:#38bb4c;border-width:0 0 5px;margin:0.575em -5% 1em}.geo-shapes-title h2 .geo-shapes{padding-bottom:0;font-size:21px;line-height:1.5}.geo-shapes-title h2 .geo-shapes hr{width:42.5%;margin-left:auto;margin-right:auto}.panel.panel--signoff{min-height:320px;overflow:hidden}.panel.panel--signoff.panel--signoff-how{min-height:570px}.panel.panel--signoff .text-center{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);margin-top:-5%;z-index:1200}.panel.panel--signoff .text-center .geo-shapes{padding-top:2em;padding-bottom:0.5em}.panel.panel--signoff .text-center h2{margin:0.5em 0}.panel.panel--signoff .text-center h4 a{position:relative;display:inline-block;text-align:center;transition:all 0.3s ease-in-out;line-height:1}.panel.panel--signoff .text-center h4 a::after{display:inline-block;content:"";background:#ff2a53;height:3px;width:10%;opacity:0;margin:-0.75em auto 0;transition:all 0.3s ease-in-out}.panel.panel--signoff .text-center h4 a:hover::after{width:100%;opacity:1}.panel.panel--signoff .text-center p:last-child{margin-bottom:0}.panel.panel--signoff .shape-position.shape-position-bottom{bottom:-10%}.intro{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);margin-top:50px}.intro .geo-shapes{padding-bottom:0.5em}.intro p{max-width:92%;font-size:0.875em;margin:0.5em auto 1.5em}.content .pink{color:#ff2a53;border-color:#ff2a53}.content .blue{color:#3fb1e5;border-color:#3fb1e5}.content .green{color:#38bb4c;border-color:#38bb4c}.content h2,.content h3,.content h4{color:#ff2a53;margin:1.5em 0;line-height:1.3}.content h2{margin:2em 0 0.5em}.content h2 .geo-shapes{padding:0}.content h3{margin:1em 0}.content .pics p{padding-right:0}.content .text-center p{padding-right:0}.content p{padding-right:5%;line-height:1.636;margin-bottom:1.5rem}@media only screen and (min-width: 40.063em){.content p:last-child{margin-bottom:1em}}.content p.lead{font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:400;letter-spacing:0.0125em;padding:0;font-size:0.925em}.content code,.content pre{font-family:Consolas,"Lucida Console",Monaco,monospace;background:#f0f0f0;border:none;color:#464646;line-height:1.8}.content table{border:2px solid #f4f4f4;margin:1.5em auto;width:100%}.content table th,.content table td{vertical-align:top;padding:0.825em 1.5em 1.25em 0.75em;line-height:1.333}.content table th{font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:500;letter-spacing:0.02em;color:white;font-size:1em;background:#4e4e4e;line-height:1.2}.content table .small{font-size:0.75em;line-height:1.7;max-width:50%}.content dl{margin:0 0 1.5em;font-size:1.25rem;line-height:1.5}.content dl dt,.content dl dd{font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:400;letter-spacing:0.0125em}.content dl dt{font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:500;letter-spacing:0.02em;color:#c4c4c4}.content dl.inline-list dt,.content dl.inline-list dd{float:left;display:inline-block;margin-right:1em}.content dl.inline-list dt{clear:left}.content address{font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:400;letter-spacing:0.0125em;font-size:1.25rem;margin:2em 0 1em;line-height:1.333}.content address em{font-family:"klinic",Consolas,"Andale Mono",Rockwell,Courier,sans-serif;font-weight:500;letter-spacing:0.02em;font-style:normal;color:#c4c4c4}.content hr.blank{color:white;border-color:white}.content .quote{font-size:0.875em;font-family:Georgia,Cambria,"Times New Roman",Times,serif;line-height:1.7;color:#8f8f8f;padding:0.5em 5%;margin-right:-3.333em;font-style:italic;letter-spacing:0.015em;position:relative}.content .quote:before{content:"\“";position:absolute;font-size:3em;left:-0.125em;top:-0.25em;width:1em;opacity:0.3;z-index:500}.content a.ripple{position:relative;display:inline-block;text-align:center;transition:all 0.3s ease-in-out;display:inline}.content a.ripple::after{display:inline-block;content:"";background:#ff2a53;height:3px;width:10%;opacity:0;margin:-0.75em auto 0;transition:all 0.3s ease-in-out}.content a.ripple:hover::after{width:100%;opacity:1}.content a.ripple:after{position:absolute;left:0;bottom:-0.2em}.content .breakout-cta-row{background:white;box-shadow:0 1px 3px #dedede;padding:1em 1.25em;margin-bottom:1.25em}.content .breakout-cta-row p.left{font-size:0.75em;padding:0.5em 0;margin:0;color:#787878}@media only screen and (max-width: 40em){.content .breakout-cta-row p.left,.content .breakout-cta-row button{float:none;text-align:center;margin:0 auto}}.content .centerer{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}.off-canvas-wrap.move-left{position:fixed}@media only screen and (max-width: 40em){.navbar.top-bar{top:0}} +#tos{padding-top:100px}@media only screen and (max-width: 40em){#tos{padding:80px 20px 20px 20px}} +/*# sourceMappingURL=styles.css.map */ diff --git a/static/css/styles.css.map b/static/css/styles.css.map new file mode 100644 index 000000000..794302360 --- /dev/null +++ b/static/css/styles.css.map @@ -0,0 +1,7 @@ +{ +"version": 3, +"mappings": "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", +"sources": ["../../bower_components/foundation/scss/normalize.scss","../scss/_custom-foundation-settings.scss","../../bower_components/foundation/scss/foundation/components/_global.scss","../../bower_components/foundation/scss/foundation/components/_grid.scss","../../bower_components/foundation/scss/foundation/components/_block-grid.scss","../../bower_components/foundation/scss/foundation/components/_inline-lists.scss","../../bower_components/foundation/scss/foundation/components/_alert-boxes.scss","../../bower_components/foundation/scss/foundation/components/_reveal.scss","../../bower_components/foundation/scss/foundation/components/_buttons.scss","../../bower_components/foundation/scss/foundation/_functions.scss","../../bower_components/foundation/scss/foundation/components/_dropdown-buttons.scss","../../bower_components/foundation/scss/foundation/components/_split-buttons.scss","../../bower_components/foundation/scss/foundation/components/_tables.scss","../../bower_components/foundation/scss/foundation/components/_type.scss","../../bower_components/foundation/scss/foundation/components/_offcanvas.scss","../../bower_components/foundation/scss/foundation/components/_visibility.scss","../../bower_components/font-awesome/scss/_path.scss","../../bower_components/font-awesome/scss/_core.scss","../../bower_components/font-awesome/scss/_larger.scss","../../bower_components/font-awesome/scss/_fixed-width.scss","../../bower_components/font-awesome/scss/_list.scss","../../bower_components/font-awesome/scss/_variables.scss","../../bower_components/font-awesome/scss/_bordered-pulled.scss","../../bower_components/font-awesome/scss/_animated.scss","../../bower_components/font-awesome/scss/_rotated-flipped.scss","../../bower_components/font-awesome/scss/_mixins.scss","../../bower_components/font-awesome/scss/_stacked.scss","../../bower_components/font-awesome/scss/_icons.scss","../../bower_components/font-awesome/scss/_screen-reader.scss","../scss/_typography.scss","../scss/_mixins.scss","../scss/_buttons.scss","../scss/_shapes.scss","../scss/_media.scss","../scss/_header.scss","../scss/_offcanvas.scss","../scss/_footer.scss","../scss/_doc-layout.scss","../scss/_doc-sidebar.scss","../scss/_doc-content.scss","../scss/_doc-responsive.scss","../scss/app.scss"], +"names": [], +"file": "styles.css" +} diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 000000000..fdc7e80cf Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/fonts/FontAwesome.otf b/static/fonts/FontAwesome.otf new file mode 100644 index 000000000..3ed7f8b48 Binary files /dev/null and b/static/fonts/FontAwesome.otf differ diff --git a/static/fonts/bootstrap/glyphicons-halflings-regular.eot b/static/fonts/bootstrap/glyphicons-halflings-regular.eot new file mode 100644 index 000000000..b93a4953f Binary files /dev/null and b/static/fonts/bootstrap/glyphicons-halflings-regular.eot differ diff --git a/static/fonts/bootstrap/glyphicons-halflings-regular.svg b/static/fonts/bootstrap/glyphicons-halflings-regular.svg new file mode 100644 index 000000000..94fb5490a --- /dev/null +++ b/static/fonts/bootstrap/glyphicons-halflings-regular.svg @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/fonts/bootstrap/glyphicons-halflings-regular.ttf b/static/fonts/bootstrap/glyphicons-halflings-regular.ttf new file mode 100644 index 000000000..1413fc609 Binary files /dev/null and b/static/fonts/bootstrap/glyphicons-halflings-regular.ttf differ diff --git a/static/fonts/bootstrap/glyphicons-halflings-regular.woff b/static/fonts/bootstrap/glyphicons-halflings-regular.woff new file mode 100644 index 000000000..9e612858f Binary files /dev/null and b/static/fonts/bootstrap/glyphicons-halflings-regular.woff differ diff --git a/static/fonts/bootstrap/glyphicons-halflings-regular.woff2 b/static/fonts/bootstrap/glyphicons-halflings-regular.woff2 new file mode 100644 index 000000000..64539b54c Binary files /dev/null and b/static/fonts/bootstrap/glyphicons-halflings-regular.woff2 differ diff --git a/static/fonts/fontawesome-webfont.eot b/static/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..9b6afaedc Binary files /dev/null and b/static/fonts/fontawesome-webfont.eot differ diff --git a/static/fonts/fontawesome-webfont.svg b/static/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..d05688e9e --- /dev/null +++ b/static/fonts/fontawesome-webfont.svg @@ -0,0 +1,655 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/fonts/fontawesome-webfont.ttf b/static/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..26dea7951 Binary files /dev/null and b/static/fonts/fontawesome-webfont.ttf differ diff --git a/static/fonts/fontawesome-webfont.woff b/static/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..dc35ce3c2 Binary files /dev/null and b/static/fonts/fontawesome-webfont.woff differ diff --git a/static/fonts/fontawesome-webfont.woff2 b/static/fonts/fontawesome-webfont.woff2 new file mode 100644 index 000000000..500e51725 Binary files /dev/null and b/static/fonts/fontawesome-webfont.woff2 differ diff --git a/static/fonts/klinicslabbook-webfont.eot b/static/fonts/klinicslabbook-webfont.eot new file mode 100644 index 000000000..1907bfdc7 Binary files /dev/null and b/static/fonts/klinicslabbook-webfont.eot differ diff --git a/static/fonts/klinicslabbook-webfont.svg b/static/fonts/klinicslabbook-webfont.svg new file mode 100644 index 000000000..7924220bd --- /dev/null +++ b/static/fonts/klinicslabbook-webfont.svg @@ -0,0 +1,1900 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/fonts/klinicslabbook-webfont.ttf b/static/fonts/klinicslabbook-webfont.ttf new file mode 100644 index 000000000..acd4f27e4 Binary files /dev/null and b/static/fonts/klinicslabbook-webfont.ttf differ diff --git a/static/fonts/klinicslabbook-webfont.woff b/static/fonts/klinicslabbook-webfont.woff new file mode 100644 index 000000000..822179bd1 Binary files /dev/null and b/static/fonts/klinicslabbook-webfont.woff differ diff --git a/static/fonts/klinicslabbook-webfont.woff2 b/static/fonts/klinicslabbook-webfont.woff2 new file mode 100644 index 000000000..c18bf5e6e Binary files /dev/null and b/static/fonts/klinicslabbook-webfont.woff2 differ diff --git a/static/fonts/klinicslabmedium-webfont.eot b/static/fonts/klinicslabmedium-webfont.eot new file mode 100644 index 000000000..d2bc3bfd8 Binary files /dev/null and b/static/fonts/klinicslabmedium-webfont.eot differ diff --git a/static/fonts/klinicslabmedium-webfont.svg b/static/fonts/klinicslabmedium-webfont.svg new file mode 100644 index 000000000..b1e553fb7 --- /dev/null +++ b/static/fonts/klinicslabmedium-webfont.svg @@ -0,0 +1,1884 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/fonts/klinicslabmedium-webfont.ttf b/static/fonts/klinicslabmedium-webfont.ttf new file mode 100644 index 000000000..994071b3c Binary files /dev/null and b/static/fonts/klinicslabmedium-webfont.ttf differ diff --git a/static/fonts/klinicslabmedium-webfont.woff b/static/fonts/klinicslabmedium-webfont.woff new file mode 100644 index 000000000..643977673 Binary files /dev/null and b/static/fonts/klinicslabmedium-webfont.woff differ diff --git a/static/fonts/klinicslabmedium-webfont.woff2 b/static/fonts/klinicslabmedium-webfont.woff2 new file mode 100644 index 000000000..55651e0b5 Binary files /dev/null and b/static/fonts/klinicslabmedium-webfont.woff2 differ diff --git a/static/img/404.png b/static/img/404.png new file mode 100644 index 000000000..ca2492b2b Binary files /dev/null and b/static/img/404.png differ diff --git a/static/img/aws-ec2.png b/static/img/aws-ec2.png new file mode 100644 index 000000000..1d27b8396 Binary files /dev/null and b/static/img/aws-ec2.png differ diff --git a/static/img/blog-social.png b/static/img/blog-social.png new file mode 100644 index 000000000..a379db88a Binary files /dev/null and b/static/img/blog-social.png differ diff --git a/static/img/cover-image.png b/static/img/cover-image.png new file mode 100644 index 000000000..83b7a0a64 Binary files /dev/null and b/static/img/cover-image.png differ diff --git a/static/img/drycc-graphic.png b/static/img/drycc-graphic.png new file mode 100644 index 000000000..7a42f13aa Binary files /dev/null and b/static/img/drycc-graphic.png differ diff --git a/static/img/drycc-logo.png b/static/img/drycc-logo.png new file mode 100644 index 000000000..28d8d8ca0 Binary files /dev/null and b/static/img/drycc-logo.png differ diff --git a/static/img/drycc_builder.png b/static/img/drycc_builder.png new file mode 100644 index 000000000..d25c059af Binary files /dev/null and b/static/img/drycc_builder.png differ diff --git a/static/img/drycc_logo.png b/static/img/drycc_logo.png new file mode 100644 index 000000000..8059bc9bd Binary files /dev/null and b/static/img/drycc_logo.png differ diff --git a/static/img/favicon.ico b/static/img/favicon.ico new file mode 100644 index 000000000..04f26d64e Binary files /dev/null and b/static/img/favicon.ico differ diff --git a/static/img/favicon.png b/static/img/favicon.png new file mode 100644 index 000000000..fa63faffc Binary files /dev/null and b/static/img/favicon.png differ diff --git a/static/img/footer-engine-yard.png b/static/img/footer-engine-yard.png new file mode 100644 index 000000000..9ff301f53 Binary files /dev/null and b/static/img/footer-engine-yard.png differ diff --git a/static/img/footer-logo.png b/static/img/footer-logo.png new file mode 100644 index 000000000..135120afc Binary files /dev/null and b/static/img/footer-logo.png differ diff --git a/static/img/fork.png b/static/img/fork.png new file mode 100644 index 000000000..427caa6ff Binary files /dev/null and b/static/img/fork.png differ diff --git a/static/img/glyphs.png b/static/img/glyphs.png new file mode 100644 index 000000000..5f046512e Binary files /dev/null and b/static/img/glyphs.png differ diff --git a/static/img/large-social.png b/static/img/large-social.png new file mode 100644 index 000000000..e95428419 Binary files /dev/null and b/static/img/large-social.png differ diff --git a/static/img/logo.png b/static/img/logo.png new file mode 100644 index 000000000..8d6c479f3 Binary files /dev/null and b/static/img/logo.png differ diff --git a/static/img/mag_glass.png b/static/img/mag_glass.png new file mode 100644 index 000000000..511274ef0 Binary files /dev/null and b/static/img/mag_glass.png differ diff --git a/static/img/menu-logo.png b/static/img/menu-logo.png new file mode 100644 index 000000000..cd3b7786b Binary files /dev/null and b/static/img/menu-logo.png differ diff --git a/static/img/social.png b/static/img/social.png new file mode 100644 index 000000000..c25e10014 Binary files /dev/null and b/static/img/social.png differ diff --git a/static/img/svg/circle.svg b/static/img/svg/circle.svg new file mode 100644 index 000000000..5cb1439e8 --- /dev/null +++ b/static/img/svg/circle.svg @@ -0,0 +1,10 @@ + + + + Fill 31 + Created with Sketch. + + + + + \ No newline at end of file diff --git a/static/img/svg/footer-engine-yard.svg b/static/img/svg/footer-engine-yard.svg new file mode 100644 index 000000000..559fbe51f --- /dev/null +++ b/static/img/svg/footer-engine-yard.svg @@ -0,0 +1,27 @@ + + + + EY logo + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/static/img/svg/footer-logo.svg b/static/img/svg/footer-logo.svg new file mode 100644 index 000000000..120e8a4f5 --- /dev/null +++ b/static/img/svg/footer-logo.svg @@ -0,0 +1,20 @@ + + + + Group + Created with Sketch. + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/img/svg/helm-logo.svg b/static/img/svg/helm-logo.svg new file mode 100644 index 000000000..af15bda3a --- /dev/null +++ b/static/img/svg/helm-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/svg/logo.svg b/static/img/svg/logo.svg new file mode 100644 index 000000000..db269bf62 --- /dev/null +++ b/static/img/svg/logo.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/img/svg/square.svg b/static/img/svg/square.svg new file mode 100644 index 000000000..d6b63ed99 --- /dev/null +++ b/static/img/svg/square.svg @@ -0,0 +1,10 @@ + + + + Fill 26 + Created with Sketch. + + + + + \ No newline at end of file diff --git a/static/img/svg/svc-cat-logo.svg b/static/img/svg/svc-cat-logo.svg new file mode 100644 index 000000000..b62d989d3 --- /dev/null +++ b/static/img/svg/svc-cat-logo.svg @@ -0,0 +1,11 @@ + + + + helm + Created with Sketch. + + + + + + diff --git a/static/img/svg/triangle.svg b/static/img/svg/triangle.svg new file mode 100644 index 000000000..e2917d456 --- /dev/null +++ b/static/img/svg/triangle.svg @@ -0,0 +1,10 @@ + + + + Fill 21 + Created with Sketch. + + + + + \ No newline at end of file diff --git a/static/img/svg/workflow-logo.svg b/static/img/svg/workflow-logo.svg new file mode 100644 index 000000000..bdbf92676 --- /dev/null +++ b/static/img/svg/workflow-logo.svg @@ -0,0 +1 @@ +Logo Box \ No newline at end of file diff --git a/static/js/adjustments.js b/static/js/adjustments.js new file mode 100644 index 000000000..eae8d6731 --- /dev/null +++ b/static/js/adjustments.js @@ -0,0 +1,54 @@ +$(document).ready(function() { + + // init foundation for offcanvas menu + $(document).foundation(); + + + // custom theme js for sidebar links + var allClosed; + + // close all accordions, besides the menu containing the page that you've clicked on. + $('.toctree-l1').each(function(){ + if($(this).children('a').attr('state') == 'open') { + $(this).children('ul').show(); + allClosed = false; + return false; + } else { + allClosed = true; + } + }); + + if (allClosed == true) { } + + // if menu is closed when clicked, expand it + $('.toctree-l1 > a').click(function() { + + //Make the titles of open accordions dead links + if ($(this).attr('state') == 'open') {return false;} + + //Clicking on a title of a closed accordion + if($(this).attr('state') != 'open' && $(this).siblings().size() > 0) { + $('.toctree-l1 > ul').hide(); + $('.toctree-l1 > a').attr('state', ''); + $(this).attr('state', 'open'); + $(this).next().slideDown(function(){}); + return false; + } + }); +}); + + +// use headroom.js for sticky topbar +(function() { + var searchBar = document.querySelector(".top-bar"); + new Headroom(searchBar, { + offset: 50, + classes: { + "initial": "headroom", + "pinned": "headroom--pinned", + "unpinned": "headroom--unpinned", + "top" : "headroom--top", + "notTop" : "headroom--not-top" + } + }).init(); +}()); diff --git a/static/js/foundation.dropdown.js b/static/js/foundation.dropdown.js new file mode 100644 index 000000000..5db3dea6d --- /dev/null +++ b/static/js/foundation.dropdown.js @@ -0,0 +1,468 @@ +;(function ($, window, document, undefined) { + 'use strict'; + + Foundation.libs.dropdown = { + name : 'dropdown', + + version : '5.5.3', + + settings : { + active_class : 'open', + disabled_class : 'disabled', + mega_class : 'mega', + align : 'bottom', + is_hover : false, + hover_timeout : 150, + opened : function () {}, + closed : function () {} + }, + + init : function (scope, method, options) { + Foundation.inherit(this, 'throttle'); + + $.extend(true, this.settings, method, options); + this.bindings(method, options); + }, + + events : function (scope) { + var self = this, + S = self.S; + + S(this.scope) + .off('.dropdown') + .on('click.fndtn.dropdown', '[' + this.attr_name() + ']', function (e) { + var settings = S(this).data(self.attr_name(true) + '-init') || self.settings; + if (!settings.is_hover || Modernizr.touch) { + e.preventDefault(); + if (S(this).parent('[data-reveal-id]').length) { + e.stopPropagation(); + } + self.toggle($(this)); + } + }) + .on('mouseenter.fndtn.dropdown', '[' + this.attr_name() + '], [' + this.attr_name() + '-content]', function (e) { + var $this = S(this), + dropdown, + target; + + clearTimeout(self.timeout); + + if ($this.data(self.data_attr())) { + dropdown = S('#' + $this.data(self.data_attr())); + target = $this; + } else { + dropdown = $this; + target = S('[' + self.attr_name() + '="' + dropdown.attr('id') + '"]'); + } + + var settings = target.data(self.attr_name(true) + '-init') || self.settings; + + if (S(e.currentTarget).data(self.data_attr()) && settings.is_hover) { + self.closeall.call(self); + } + + if (settings.is_hover) { + self.open.apply(self, [dropdown, target]); + } + }) + .on('mouseleave.fndtn.dropdown', '[' + this.attr_name() + '], [' + this.attr_name() + '-content]', function (e) { + var $this = S(this); + var settings; + + if ($this.data(self.data_attr())) { + settings = $this.data(self.data_attr(true) + '-init') || self.settings; + } else { + var target = S('[' + self.attr_name() + '="' + S(this).attr('id') + '"]'), + settings = target.data(self.attr_name(true) + '-init') || self.settings; + } + + self.timeout = setTimeout(function () { + if ($this.data(self.data_attr())) { + if (settings.is_hover) { + self.close.call(self, S('#' + $this.data(self.data_attr()))); + } + } else { + if (settings.is_hover) { + self.close.call(self, $this); + } + } + }.bind(this), settings.hover_timeout); + }) + .on('click.fndtn.dropdown', function (e) { + var parent = S(e.target).closest('[' + self.attr_name() + '-content]'); + var links = parent.find('a'); + + if (links.length > 0 && parent.attr('aria-autoclose') !== 'false') { + self.close.call(self, S('[' + self.attr_name() + '-content]')); + } + + if (e.target !== document && !$.contains(document.documentElement, e.target)) { + return; + } + + if (S(e.target).closest('[' + self.attr_name() + ']').length > 0) { + return; + } + + if (!(S(e.target).data('revealId')) && + (parent.length > 0 && (S(e.target).is('[' + self.attr_name() + '-content]') || + $.contains(parent.first()[0], e.target)))) { + e.stopPropagation(); + return; + } + + self.close.call(self, S('[' + self.attr_name() + '-content]')); + }) + .on('opened.fndtn.dropdown', '[' + self.attr_name() + '-content]', function () { + self.settings.opened.call(this); + }) + .on('closed.fndtn.dropdown', '[' + self.attr_name() + '-content]', function () { + self.settings.closed.call(this); + }); + + S(window) + .off('.dropdown') + .on('resize.fndtn.dropdown', self.throttle(function () { + self.resize.call(self); + }, 50)); + + this.resize(); + }, + + close : function (dropdown) { + var self = this; + dropdown.each(function (idx) { + var original_target = $('[' + self.attr_name() + '=' + dropdown[idx].id + ']') || $('aria-controls=' + dropdown[idx].id + ']'); + original_target.attr('aria-expanded', 'false'); + if (self.S(this).hasClass(self.settings.active_class)) { + self.S(this) + .css(Foundation.rtl ? 'right' : 'left', '-99999px') + .attr('aria-hidden', 'true') + .removeClass(self.settings.active_class) + .prev('[' + self.attr_name() + ']') + .removeClass(self.settings.active_class) + .removeData('target'); + + self.S(this).trigger('closed.fndtn.dropdown', [dropdown]); + } + }); + dropdown.removeClass('f-open-' + this.attr_name(true)); + }, + + closeall : function () { + var self = this; + $.each(self.S('.f-open-' + this.attr_name(true)), function () { + self.close.call(self, self.S(this)); + }); + }, + + open : function (dropdown, target) { + this + .css(dropdown + .addClass(this.settings.active_class), target); + dropdown.prev('[' + this.attr_name() + ']').addClass(this.settings.active_class); + dropdown.data('target', target.get(0)).trigger('opened.fndtn.dropdown', [dropdown, target]); + dropdown.attr('aria-hidden', 'false'); + target.attr('aria-expanded', 'true'); + dropdown.focus(); + dropdown.addClass('f-open-' + this.attr_name(true)); + }, + + data_attr : function () { + if (this.namespace.length > 0) { + return this.namespace + '-' + this.name; + } + + return this.name; + }, + + toggle : function (target) { + if (target.hasClass(this.settings.disabled_class)) { + return; + } + var dropdown = this.S('#' + target.data(this.data_attr())); + if (dropdown.length === 0) { + // No dropdown found, not continuing + return; + } + + this.close.call(this, this.S('[' + this.attr_name() + '-content]').not(dropdown)); + + if (dropdown.hasClass(this.settings.active_class)) { + this.close.call(this, dropdown); + if (dropdown.data('target') !== target.get(0)) { + this.open.call(this, dropdown, target); + } + } else { + this.open.call(this, dropdown, target); + } + }, + + resize : function () { + var dropdown = this.S('[' + this.attr_name() + '-content].open'); + var target = $(dropdown.data("target")); + + if (dropdown.length && target.length) { + this.css(dropdown, target); + } + }, + + css : function (dropdown, target) { + var left_offset = Math.max((target.width() - dropdown.width()) / 2, 8), + settings = target.data(this.attr_name(true) + '-init') || this.settings, + parentOverflow = dropdown.parent().css('overflow-y') || dropdown.parent().css('overflow'); + + this.clear_idx(); + + + + if (this.small()) { + var p = this.dirs.bottom.call(dropdown, target, settings); + + dropdown.attr('style', '').removeClass('drop-left drop-right drop-top').css({ + position : 'absolute', + width : '95%', + 'max-width' : 'none', + top : p.top + }); + + dropdown.css(Foundation.rtl ? 'right' : 'left', left_offset); + } + // detect if dropdown is in an overflow container + else if (parentOverflow !== 'visible') { + var offset = target[0].offsetTop + target[0].offsetHeight; + + dropdown.attr('style', '').css({ + position : 'absolute', + top : offset + }); + + dropdown.css(Foundation.rtl ? 'right' : 'left', left_offset); + } + else { + + this.style(dropdown, target, settings); + } + + return dropdown; + }, + + style : function (dropdown, target, settings) { + var css = $.extend({position : 'absolute'}, + this.dirs[settings.align].call(dropdown, target, settings)); + + dropdown.attr('style', '').css(css); + }, + + // return CSS property object + // `this` is the dropdown + dirs : { + // Calculate target offset + _base : function (t, s) { + var o_p = this.offsetParent(), + o = o_p.offset(), + p = t.offset(); + + p.top -= o.top; + p.left -= o.left; + + //set some flags on the p object to pass along + p.missRight = false; + p.missTop = false; + p.missLeft = false; + p.leftRightFlag = false; + + //lets see if the panel will be off the screen + //get the actual width of the page and store it + var actualBodyWidth; + var windowWidth = window.innerWidth; + + if (document.getElementsByClassName('row')[0]) { + actualBodyWidth = document.getElementsByClassName('row')[0].clientWidth; + } else { + actualBodyWidth = windowWidth; + } + + var actualMarginWidth = (windowWidth - actualBodyWidth) / 2; + var actualBoundary = actualBodyWidth; + + if (!this.hasClass('mega') && !s.ignore_repositioning) { + var outerWidth = this.outerWidth(); + var o_left = t.offset().left; + + //miss top + if (t.offset().top <= this.outerHeight()) { + p.missTop = true; + actualBoundary = windowWidth - actualMarginWidth; + p.leftRightFlag = true; + } + + //miss right + if (o_left + outerWidth > o_left + actualMarginWidth && o_left - actualMarginWidth > outerWidth) { + p.missRight = true; + p.missLeft = false; + } + + //miss left + if (o_left - outerWidth <= 0) { + p.missLeft = true; + p.missRight = false; + } + } + + return p; + }, + + top : function (t, s) { + var self = Foundation.libs.dropdown, + p = self.dirs._base.call(this, t, s); + + this.addClass('drop-top'); + + if (p.missTop == true) { + p.top = p.top + t.outerHeight() + this.outerHeight(); + this.removeClass('drop-top'); + } + + if (p.missRight == true) { + p.left = p.left - this.outerWidth() + t.outerWidth(); + } + + if (t.outerWidth() < this.outerWidth() || self.small() || this.hasClass(s.mega_menu)) { + self.adjust_pip(this, t, s, p); + } + + if (Foundation.rtl) { + return {left : p.left - this.outerWidth() + t.outerWidth(), + top : p.top - this.outerHeight()}; + } + + return {left : p.left, top : p.top - this.outerHeight()}; + }, + + bottom : function (t, s) { + var self = Foundation.libs.dropdown, + p = self.dirs._base.call(this, t, s); + + if (p.missRight == true) { + p.left = p.left - this.outerWidth() + t.outerWidth(); + } + + if (t.outerWidth() < this.outerWidth() || self.small() || this.hasClass(s.mega_menu)) { + self.adjust_pip(this, t, s, p); + } + + if (self.rtl) { + return {left : p.left - this.outerWidth() + t.outerWidth(), top : p.top + t.outerHeight()}; + } + + return {left : p.left, top : p.top + t.outerHeight()}; + }, + + left : function (t, s) { + var p = Foundation.libs.dropdown.dirs._base.call(this, t, s); + + this.addClass('drop-left'); + + if (p.missLeft == true) { + p.left = p.left + this.outerWidth(); + p.top = p.top + t.outerHeight(); + this.removeClass('drop-left'); + } + + return {left : p.left - this.outerWidth(), top : p.top}; + }, + + right : function (t, s) { + var p = Foundation.libs.dropdown.dirs._base.call(this, t, s); + + this.addClass('drop-right'); + + if (p.missRight == true) { + p.left = p.left - this.outerWidth(); + p.top = p.top + t.outerHeight(); + this.removeClass('drop-right'); + } else { + p.triggeredRight = true; + } + + var self = Foundation.libs.dropdown; + + if (t.outerWidth() < this.outerWidth() || self.small() || this.hasClass(s.mega_menu)) { + self.adjust_pip(this, t, s, p); + } + + return {left : p.left + t.outerWidth(), top : p.top}; + } + }, + + // Insert rule to style psuedo elements + adjust_pip : function (dropdown, target, settings, position) { + var sheet = Foundation.stylesheet, + pip_offset_base = 8; + + if (dropdown.hasClass(settings.mega_class)) { + pip_offset_base = position.left + (target.outerWidth() / 2) - 8; + } else if (this.small()) { + pip_offset_base += position.left - 8; + } + + this.rule_idx = sheet.cssRules.length; + + //default + var sel_before = '.f-dropdown.open:before', + sel_after = '.f-dropdown.open:after', + css_before = 'left: ' + pip_offset_base + 'px;', + css_after = 'left: ' + (pip_offset_base - 1) + 'px;'; + + if (position.missRight == true) { + pip_offset_base = dropdown.outerWidth() - 23; + sel_before = '.f-dropdown.open:before', + sel_after = '.f-dropdown.open:after', + css_before = 'left: ' + pip_offset_base + 'px;', + css_after = 'left: ' + (pip_offset_base - 1) + 'px;'; + } + + //just a case where right is fired, but its not missing right + if (position.triggeredRight == true) { + sel_before = '.f-dropdown.open:before', + sel_after = '.f-dropdown.open:after', + css_before = 'left:-12px;', + css_after = 'left:-14px;'; + } + + if (sheet.insertRule) { + sheet.insertRule([sel_before, '{', css_before, '}'].join(' '), this.rule_idx); + sheet.insertRule([sel_after, '{', css_after, '}'].join(' '), this.rule_idx + 1); + } else { + sheet.addRule(sel_before, css_before, this.rule_idx); + sheet.addRule(sel_after, css_after, this.rule_idx + 1); + } + }, + + // Remove old dropdown rule index + clear_idx : function () { + var sheet = Foundation.stylesheet; + + if (typeof this.rule_idx !== 'undefined') { + sheet.deleteRule(this.rule_idx); + sheet.deleteRule(this.rule_idx); + delete this.rule_idx; + } + }, + + small : function () { + return matchMedia(Foundation.media_queries.small).matches && + !matchMedia(Foundation.media_queries.medium).matches; + }, + + off : function () { + this.S(this.scope).off('.fndtn.dropdown'); + this.S('html, body').off('.fndtn.dropdown'); + this.S(window).off('.fndtn.dropdown'); + this.S('[data-dropdown-content]').off('.fndtn.dropdown'); + }, + + reflow : function () {} + }; +}(jQuery, window, window.document)); diff --git a/static/js/foundation.js b/static/js/foundation.js new file mode 100644 index 000000000..c5a359d3b --- /dev/null +++ b/static/js/foundation.js @@ -0,0 +1,732 @@ +/* + * Foundation Responsive Library + * http://foundation.zurb.com + * Copyright 2015, ZURB + * Free to use under the MIT license. + * http://www.opensource.org/licenses/mit-license.php +*/ + +(function ($, window, document, undefined) { + 'use strict'; + + var header_helpers = function (class_array) { + var head = $('head'); + head.prepend($.map(class_array, function (class_name) { + if (head.has('.' + class_name).length === 0) { + return ''; + } + })); + }; + + header_helpers([ + 'foundation-mq-small', + 'foundation-mq-small-only', + 'foundation-mq-medium', + 'foundation-mq-medium-only', + 'foundation-mq-large', + 'foundation-mq-large-only', + 'foundation-mq-xlarge', + 'foundation-mq-xlarge-only', + 'foundation-mq-xxlarge', + 'foundation-data-attribute-namespace']); + + // Enable FastClick if present + + $(function () { + if (typeof FastClick !== 'undefined') { + // Don't attach to body if undefined + if (typeof document.body !== 'undefined') { + FastClick.attach(document.body); + } + } + }); + + // private Fast Selector wrapper, + // returns jQuery object. Only use where + // getElementById is not available. + var S = function (selector, context) { + if (typeof selector === 'string') { + if (context) { + var cont; + if (context.jquery) { + cont = context[0]; + if (!cont) { + return context; + } + } else { + cont = context; + } + return $(cont.querySelectorAll(selector)); + } + + return $(document.querySelectorAll(selector)); + } + + return $(selector, context); + }; + + // Namespace functions. + + var attr_name = function (init) { + var arr = []; + if (!init) { + arr.push('data'); + } + if (this.namespace.length > 0) { + arr.push(this.namespace); + } + arr.push(this.name); + + return arr.join('-'); + }; + + var add_namespace = function (str) { + var parts = str.split('-'), + i = parts.length, + arr = []; + + while (i--) { + if (i !== 0) { + arr.push(parts[i]); + } else { + if (this.namespace.length > 0) { + arr.push(this.namespace, parts[i]); + } else { + arr.push(parts[i]); + } + } + } + + return arr.reverse().join('-'); + }; + + // Event binding and data-options updating. + + var bindings = function (method, options) { + var self = this, + bind = function(){ + var $this = S(this), + should_bind_events = !$this.data(self.attr_name(true) + '-init'); + $this.data(self.attr_name(true) + '-init', $.extend({}, self.settings, (options || method), self.data_options($this))); + + if (should_bind_events) { + self.events(this); + } + }; + + if (S(this.scope).is('[' + this.attr_name() +']')) { + bind.call(this.scope); + } else { + S('[' + this.attr_name() +']', this.scope).each(bind); + } + // # Patch to fix #5043 to move this *after* the if/else clause in order for Backbone and similar frameworks to have improved control over event binding and data-options updating. + if (typeof method === 'string') { + return this[method].call(this, options); + } + + }; + + var single_image_loaded = function (image, callback) { + function loaded () { + callback(image[0]); + } + + function bindLoad () { + this.one('load', loaded); + + if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) { + var src = this.attr( 'src' ), + param = src.match( /\?/ ) ? '&' : '?'; + + param += 'random=' + (new Date()).getTime(); + this.attr('src', src + param); + } + } + + if (!image.attr('src')) { + loaded(); + return; + } + + if (image[0].complete || image[0].readyState === 4) { + loaded(); + } else { + bindLoad.call(image); + } + }; + + /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */ + + window.matchMedia || (window.matchMedia = function() { + "use strict"; + + // For browsers that support matchMedium api such as IE 9 and webkit + var styleMedia = (window.styleMedia || window.media); + + // For those that don't support matchMedium + if (!styleMedia) { + var style = document.createElement('style'), + script = document.getElementsByTagName('script')[0], + info = null; + + style.type = 'text/css'; + style.id = 'matchmediajs-test'; + + script.parentNode.insertBefore(style, script); + + // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers + info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle; + + styleMedia = { + matchMedium: function(media) { + var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }'; + + // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers + if (style.styleSheet) { + style.styleSheet.cssText = text; + } else { + style.textContent = text; + } + + // Test if media query is true or false + return info.width === '1px'; + } + }; + } + + return function(media) { + return { + matches: styleMedia.matchMedium(media || 'all'), + media: media || 'all' + }; + }; + }()); + + /* + * jquery.requestAnimationFrame + * https://github.com/gnarf37/jquery-requestAnimationFrame + * Requires jQuery 1.8+ + * + * Copyright (c) 2012 Corey Frang + * Licensed under the MIT license. + */ + + (function(jQuery) { + + + // requestAnimationFrame polyfill adapted from Erik Möller + // fixes from Paul Irish and Tino Zijdel + // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating + + var animating, + lastTime = 0, + vendors = ['webkit', 'moz'], + requestAnimationFrame = window.requestAnimationFrame, + cancelAnimationFrame = window.cancelAnimationFrame, + jqueryFxAvailable = 'undefined' !== typeof jQuery.fx; + + for (; lastTime < vendors.length && !requestAnimationFrame; lastTime++) { + requestAnimationFrame = window[ vendors[lastTime] + 'RequestAnimationFrame' ]; + cancelAnimationFrame = cancelAnimationFrame || + window[ vendors[lastTime] + 'CancelAnimationFrame' ] || + window[ vendors[lastTime] + 'CancelRequestAnimationFrame' ]; + } + + function raf() { + if (animating) { + requestAnimationFrame(raf); + + if (jqueryFxAvailable) { + jQuery.fx.tick(); + } + } + } + + if (requestAnimationFrame) { + // use rAF + window.requestAnimationFrame = requestAnimationFrame; + window.cancelAnimationFrame = cancelAnimationFrame; + + if (jqueryFxAvailable) { + jQuery.fx.timer = function (timer) { + if (timer() && jQuery.timers.push(timer) && !animating) { + animating = true; + raf(); + } + }; + + jQuery.fx.stop = function () { + animating = false; + }; + } + } else { + // polyfill + window.requestAnimationFrame = function (callback) { + var currTime = new Date().getTime(), + timeToCall = Math.max(0, 16 - (currTime - lastTime)), + id = window.setTimeout(function () { + callback(currTime + timeToCall); + }, timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; + + } + + }( $ )); + + function removeQuotes (string) { + if (typeof string === 'string' || string instanceof String) { + string = string.replace(/^['\\/"]+|(;\s?})+|['\\/"]+$/g, ''); + } + + return string; + } + + function MediaQuery(selector) { + this.selector = selector; + this.query = ''; + } + + MediaQuery.prototype.toString = function () { + return this.query || (this.query = S(this.selector).css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, '')); + }; + + window.Foundation = { + name : 'Foundation', + + version : '5.5.3', + + media_queries : { + 'small' : new MediaQuery('.foundation-mq-small'), + 'small-only' : new MediaQuery('.foundation-mq-small-only'), + 'medium' : new MediaQuery('.foundation-mq-medium'), + 'medium-only' : new MediaQuery('.foundation-mq-medium-only'), + 'large' : new MediaQuery('.foundation-mq-large'), + 'large-only' : new MediaQuery('.foundation-mq-large-only'), + 'xlarge' : new MediaQuery('.foundation-mq-xlarge'), + 'xlarge-only' : new MediaQuery('.foundation-mq-xlarge-only'), + 'xxlarge' : new MediaQuery('.foundation-mq-xxlarge') + }, + + stylesheet : $('').appendTo('head')[0].sheet, + + global : { + namespace : undefined + }, + + init : function (scope, libraries, method, options, response) { + var args = [scope, method, options, response], + responses = []; + + // check RTL + this.rtl = /rtl/i.test(S('html').attr('dir')); + + // set foundation global scope + this.scope = scope || this.scope; + + this.set_namespace(); + + if (libraries && typeof libraries === 'string' && !/reflow/i.test(libraries)) { + if (this.libs.hasOwnProperty(libraries)) { + responses.push(this.init_lib(libraries, args)); + } + } else { + for (var lib in this.libs) { + responses.push(this.init_lib(lib, libraries)); + } + } + + S(window).load(function () { + S(window) + .trigger('resize.fndtn.clearing') + .trigger('resize.fndtn.dropdown') + .trigger('resize.fndtn.equalizer') + .trigger('resize.fndtn.interchange') + .trigger('resize.fndtn.joyride') + .trigger('resize.fndtn.magellan') + .trigger('resize.fndtn.topbar') + .trigger('resize.fndtn.slider'); + }); + + return scope; + }, + + init_lib : function (lib, args) { + if (this.libs.hasOwnProperty(lib)) { + this.patch(this.libs[lib]); + + if (args && args.hasOwnProperty(lib)) { + if (typeof this.libs[lib].settings !== 'undefined') { + $.extend(true, this.libs[lib].settings, args[lib]); + } else if (typeof this.libs[lib].defaults !== 'undefined') { + $.extend(true, this.libs[lib].defaults, args[lib]); + } + return this.libs[lib].init.apply(this.libs[lib], [this.scope, args[lib]]); + } + + args = args instanceof Array ? args : new Array(args); + return this.libs[lib].init.apply(this.libs[lib], args); + } + + return function () {}; + }, + + patch : function (lib) { + lib.scope = this.scope; + lib.namespace = this.global.namespace; + lib.rtl = this.rtl; + lib['data_options'] = this.utils.data_options; + lib['attr_name'] = attr_name; + lib['add_namespace'] = add_namespace; + lib['bindings'] = bindings; + lib['S'] = this.utils.S; + }, + + inherit : function (scope, methods) { + var methods_arr = methods.split(' '), + i = methods_arr.length; + + while (i--) { + if (this.utils.hasOwnProperty(methods_arr[i])) { + scope[methods_arr[i]] = this.utils[methods_arr[i]]; + } + } + }, + + set_namespace : function () { + + // Description: + // Don't bother reading the namespace out of the meta tag + // if the namespace has been set globally in javascript + // + // Example: + // Foundation.global.namespace = 'my-namespace'; + // or make it an empty string: + // Foundation.global.namespace = ''; + // + // + + // If the namespace has not been set (is undefined), try to read it out of the meta element. + // Otherwise use the globally defined namespace, even if it's empty ('') + var namespace = ( this.global.namespace === undefined ) ? $('.foundation-data-attribute-namespace').css('font-family') : this.global.namespace; + + // Finally, if the namsepace is either undefined or false, set it to an empty string. + // Otherwise use the namespace value. + this.global.namespace = ( namespace === undefined || /false/i.test(namespace) ) ? '' : namespace; + }, + + libs : {}, + + // methods that can be inherited in libraries + utils : { + + // Description: + // Fast Selector wrapper returns jQuery object. Only use where getElementById + // is not available. + // + // Arguments: + // Selector (String): CSS selector describing the element(s) to be + // returned as a jQuery object. + // + // Scope (String): CSS selector describing the area to be searched. Default + // is document. + // + // Returns: + // Element (jQuery Object): jQuery object containing elements matching the + // selector within the scope. + S : S, + + // Description: + // Executes a function a max of once every n milliseconds + // + // Arguments: + // Func (Function): Function to be throttled. + // + // Delay (Integer): Function execution threshold in milliseconds. + // + // Returns: + // Lazy_function (Function): Function with throttling applied. + throttle : function (func, delay) { + var timer = null; + + return function () { + var context = this, args = arguments; + + if (timer == null) { + timer = setTimeout(function () { + func.apply(context, args); + timer = null; + }, delay); + } + }; + }, + + // Description: + // Executes a function when it stops being invoked for n seconds + // Modified version of _.debounce() http://underscorejs.org + // + // Arguments: + // Func (Function): Function to be debounced. + // + // Delay (Integer): Function execution threshold in milliseconds. + // + // Immediate (Bool): Whether the function should be called at the beginning + // of the delay instead of the end. Default is false. + // + // Returns: + // Lazy_function (Function): Function with debouncing applied. + debounce : function (func, delay, immediate) { + var timeout, result; + return function () { + var context = this, args = arguments; + var later = function () { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + } + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, delay); + if (callNow) { + result = func.apply(context, args); + } + return result; + }; + }, + + // Description: + // Parses data-options attribute + // + // Arguments: + // El (jQuery Object): Element to be parsed. + // + // Returns: + // Options (Javascript Object): Contents of the element's data-options + // attribute. + data_options : function (el, data_attr_name) { + data_attr_name = data_attr_name || 'options'; + var opts = {}, ii, p, opts_arr, + data_options = function (el) { + var namespace = Foundation.global.namespace; + + if (namespace.length > 0) { + return el.data(namespace + '-' + data_attr_name); + } + + return el.data(data_attr_name); + }; + + var cached_options = data_options(el); + + if (typeof cached_options === 'object') { + return cached_options; + } + + opts_arr = (cached_options || ':').split(';'); + ii = opts_arr.length; + + function isNumber (o) { + return !isNaN (o - 0) && o !== null && o !== '' && o !== false && o !== true; + } + + function trim (str) { + if (typeof str === 'string') { + return $.trim(str); + } + return str; + } + + while (ii--) { + p = opts_arr[ii].split(':'); + p = [p[0], p.slice(1).join(':')]; + + if (/true/i.test(p[1])) { + p[1] = true; + } + if (/false/i.test(p[1])) { + p[1] = false; + } + if (isNumber(p[1])) { + if (p[1].indexOf('.') === -1) { + p[1] = parseInt(p[1], 10); + } else { + p[1] = parseFloat(p[1]); + } + } + + if (p.length === 2 && p[0].length > 0) { + opts[trim(p[0])] = trim(p[1]); + } + } + + return opts; + }, + + // Description: + // Adds JS-recognizable media queries + // + // Arguments: + // Media (String): Key string for the media query to be stored as in + // Foundation.media_queries + // + // Class (String): Class name for the generated tag + register_media : function (media, media_class) { + if (Foundation.media_queries[media] === undefined) { + $('head').append(''); + Foundation.media_queries[media] = removeQuotes($('.' + media_class).css('font-family')); + } + }, + + // Description: + // Add custom CSS within a JS-defined media query + // + // Arguments: + // Rule (String): CSS rule to be appended to the document. + // + // Media (String): Optional media query string for the CSS rule to be + // nested under. + add_custom_rule : function (rule, media) { + if (media === undefined && Foundation.stylesheet) { + Foundation.stylesheet.insertRule(rule, Foundation.stylesheet.cssRules.length); + } else { + var query = Foundation.media_queries[media]; + + if (query !== undefined) { + Foundation.stylesheet.insertRule('@media ' + + Foundation.media_queries[media] + '{ ' + rule + ' }', Foundation.stylesheet.cssRules.length); + } + } + }, + + // Description: + // Performs a callback function when an image is fully loaded + // + // Arguments: + // Image (jQuery Object): Image(s) to check if loaded. + // + // Callback (Function): Function to execute when image is fully loaded. + image_loaded : function (images, callback) { + var self = this, + unloaded = images.length; + + function pictures_has_height(images) { + var pictures_number = images.length; + + for (var i = pictures_number - 1; i >= 0; i--) { + if(images.attr('height') === undefined) { + return false; + }; + }; + + return true; + } + + if (unloaded === 0 || pictures_has_height(images)) { + callback(images); + } + + images.each(function () { + single_image_loaded(self.S(this), function () { + unloaded -= 1; + if (unloaded === 0) { + callback(images); + } + }); + }); + }, + + // Description: + // Returns a random, alphanumeric string + // + // Arguments: + // Length (Integer): Length of string to be generated. Defaults to random + // integer. + // + // Returns: + // Rand (String): Pseudo-random, alphanumeric string. + random_str : function () { + if (!this.fidx) { + this.fidx = 0; + } + this.prefix = this.prefix || [(this.name || 'F'), (+new Date).toString(36)].join('-'); + + return this.prefix + (this.fidx++).toString(36); + }, + + // Description: + // Helper for window.matchMedia + // + // Arguments: + // mq (String): Media query + // + // Returns: + // (Boolean): Whether the media query passes or not + match : function (mq) { + return window.matchMedia(mq).matches; + }, + + // Description: + // Helpers for checking Foundation default media queries with JS + // + // Returns: + // (Boolean): Whether the media query passes or not + + is_small_up : function () { + return this.match(Foundation.media_queries.small); + }, + + is_medium_up : function () { + return this.match(Foundation.media_queries.medium); + }, + + is_large_up : function () { + return this.match(Foundation.media_queries.large); + }, + + is_xlarge_up : function () { + return this.match(Foundation.media_queries.xlarge); + }, + + is_xxlarge_up : function () { + return this.match(Foundation.media_queries.xxlarge); + }, + + is_small_only : function () { + return !this.is_medium_up() && !this.is_large_up() && !this.is_xlarge_up() && !this.is_xxlarge_up(); + }, + + is_medium_only : function () { + return this.is_medium_up() && !this.is_large_up() && !this.is_xlarge_up() && !this.is_xxlarge_up(); + }, + + is_large_only : function () { + return this.is_medium_up() && this.is_large_up() && !this.is_xlarge_up() && !this.is_xxlarge_up(); + }, + + is_xlarge_only : function () { + return this.is_medium_up() && this.is_large_up() && this.is_xlarge_up() && !this.is_xxlarge_up(); + }, + + is_xxlarge_only : function () { + return this.is_medium_up() && this.is_large_up() && this.is_xlarge_up() && this.is_xxlarge_up(); + } + } + }; + + $.fn.foundation = function () { + var args = Array.prototype.slice.call(arguments, 0); + + return this.each(function () { + Foundation.init.apply(Foundation, [this].concat(args)); + return this; + }); + }; + +}(jQuery, window, window.document)); diff --git a/static/js/foundation.offcanvas.js b/static/js/foundation.offcanvas.js new file mode 100644 index 000000000..685e9a03a --- /dev/null +++ b/static/js/foundation.offcanvas.js @@ -0,0 +1,225 @@ +;(function ($, window, document, undefined) { + 'use strict'; + + Foundation.libs.offcanvas = { + name : 'offcanvas', + + version : '5.5.3', + + settings : { + open_method : 'move', + close_on_click : false + }, + + init : function (scope, method, options) { + this.bindings(method, options); + }, + + events : function () { + var self = this, + S = self.S, + move_class = '', + right_postfix = '', + left_postfix = '', + top_postfix = '', + bottom_postfix = ''; + + if (this.settings.open_method === 'move') { + move_class = 'move-'; + right_postfix = 'right'; + left_postfix = 'left'; + top_postfix = 'top'; + bottom_postfix = 'bottom'; + } else if (this.settings.open_method === 'overlap_single') { + move_class = 'offcanvas-overlap-'; + right_postfix = 'right'; + left_postfix = 'left'; + top_postfix = 'top'; + bottom_postfix = 'bottom'; + } else if (this.settings.open_method === 'overlap') { + move_class = 'offcanvas-overlap'; + } + + S(this.scope).off('.offcanvas') + .on('click.fndtn.offcanvas', '.left-off-canvas-toggle', function (e) { + self.click_toggle_class(e, move_class + right_postfix); + if (self.settings.open_method !== 'overlap') { + S('.left-submenu').removeClass(move_class + right_postfix); + } + $('.left-off-canvas-toggle').attr('aria-expanded', 'true'); + }) + .on('click.fndtn.offcanvas', '.left-off-canvas-menu a', function (e) { + var settings = self.get_settings(e); + var parent = S(this).parent(); + + if (settings.close_on_click && !parent.hasClass('has-submenu') && !parent.hasClass('back')) { + self.hide.call(self, move_class + right_postfix, self.get_wrapper(e)); + parent.parent().removeClass(move_class + right_postfix); + } else if (S(this).parent().hasClass('has-submenu')) { + e.preventDefault(); + S(this).siblings('.left-submenu').toggleClass(move_class + right_postfix); + } else if (parent.hasClass('back')) { + e.preventDefault(); + parent.parent().removeClass(move_class + right_postfix); + } + $('.left-off-canvas-toggle').attr('aria-expanded', 'true'); + }) + //end of left canvas + .on('click.fndtn.offcanvas', '.right-off-canvas-toggle', function (e) { + self.click_toggle_class(e, move_class + left_postfix); + if (self.settings.open_method !== 'overlap') { + S('.right-submenu').removeClass(move_class + left_postfix); + } + $('.right-off-canvas-toggle').attr('aria-expanded', 'true'); + }) + .on('click.fndtn.offcanvas', '.right-off-canvas-menu a', function (e) { + var settings = self.get_settings(e); + var parent = S(this).parent(); + + if (settings.close_on_click && !parent.hasClass('has-submenu') && !parent.hasClass('back')) { + self.hide.call(self, move_class + left_postfix, self.get_wrapper(e)); + parent.parent().removeClass(move_class + left_postfix); + } else if (S(this).parent().hasClass('has-submenu')) { + e.preventDefault(); + S(this).siblings('.right-submenu').toggleClass(move_class + left_postfix); + } else if (parent.hasClass('back')) { + e.preventDefault(); + parent.parent().removeClass(move_class + left_postfix); + } + $('.right-off-canvas-toggle').attr('aria-expanded', 'true'); + }) + //end of right canvas + .on('click.fndtn.offcanvas', '.top-off-canvas-toggle', function (e) { + self.click_toggle_class(e, move_class + bottom_postfix); + if (self.settings.open_method !== 'overlap') { + S('.top-submenu').removeClass(move_class + bottom_postfix); + } + $('.top-off-canvas-toggle').attr('aria-expanded', 'true'); + }) + .on('click.fndtn.offcanvas', '.top-off-canvas-menu a', function (e) { + var settings = self.get_settings(e); + var parent = S(this).parent(); + + if (settings.close_on_click && !parent.hasClass('has-submenu') && !parent.hasClass('back')) { + self.hide.call(self, move_class + bottom_postfix, self.get_wrapper(e)); + parent.parent().removeClass(move_class + bottom_postfix); + } else if (S(this).parent().hasClass('has-submenu')) { + e.preventDefault(); + S(this).siblings('.top-submenu').toggleClass(move_class + bottom_postfix); + } else if (parent.hasClass('back')) { + e.preventDefault(); + parent.parent().removeClass(move_class + bottom_postfix); + } + $('.top-off-canvas-toggle').attr('aria-expanded', 'true'); + }) + //end of top canvas + .on('click.fndtn.offcanvas', '.bottom-off-canvas-toggle', function (e) { + self.click_toggle_class(e, move_class + top_postfix); + if (self.settings.open_method !== 'overlap') { + S('.bottom-submenu').removeClass(move_class + top_postfix); + } + $('.bottom-off-canvas-toggle').attr('aria-expanded', 'true'); + }) + .on('click.fndtn.offcanvas', '.bottom-off-canvas-menu a', function (e) { + var settings = self.get_settings(e); + var parent = S(this).parent(); + + if (settings.close_on_click && !parent.hasClass('has-submenu') && !parent.hasClass('back')) { + self.hide.call(self, move_class + top_postfix, self.get_wrapper(e)); + parent.parent().removeClass(move_class + top_postfix); + } else if (S(this).parent().hasClass('has-submenu')) { + e.preventDefault(); + S(this).siblings('.bottom-submenu').toggleClass(move_class + top_postfix); + } else if (parent.hasClass('back')) { + e.preventDefault(); + parent.parent().removeClass(move_class + top_postfix); + } + $('.bottom-off-canvas-toggle').attr('aria-expanded', 'true'); + }) + //end of bottom + .on('click.fndtn.offcanvas', '.exit-off-canvas', function (e) { + self.click_remove_class(e, move_class + left_postfix); + S('.right-submenu').removeClass(move_class + left_postfix); + if (right_postfix) { + self.click_remove_class(e, move_class + right_postfix); + S('.left-submenu').removeClass(move_class + left_postfix); + } + $('.right-off-canvas-toggle').attr('aria-expanded', 'true'); + }) + .on('click.fndtn.offcanvas', '.exit-off-canvas', function (e) { + self.click_remove_class(e, move_class + left_postfix); + $('.left-off-canvas-toggle').attr('aria-expanded', 'false'); + if (right_postfix) { + self.click_remove_class(e, move_class + right_postfix); + $('.right-off-canvas-toggle').attr('aria-expanded', 'false'); + } + }) + .on('click.fndtn.offcanvas', '.exit-off-canvas', function (e) { + self.click_remove_class(e, move_class + top_postfix); + S('.bottom-submenu').removeClass(move_class + top_postfix); + if (bottom_postfix) { + self.click_remove_class(e, move_class + bottom_postfix); + S('.top-submenu').removeClass(move_class + top_postfix); + } + $('.bottom-off-canvas-toggle').attr('aria-expanded', 'true'); + }) + .on('click.fndtn.offcanvas', '.exit-off-canvas', function (e) { + self.click_remove_class(e, move_class + top_postfix); + $('.top-off-canvas-toggle').attr('aria-expanded', 'false'); + if (bottom_postfix) { + self.click_remove_class(e, move_class + bottom_postfix); + $('.bottom-off-canvas-toggle').attr('aria-expanded', 'false'); + } + }); + }, + + toggle : function (class_name, $off_canvas) { + $off_canvas = $off_canvas || this.get_wrapper(); + if ($off_canvas.is('.' + class_name)) { + this.hide(class_name, $off_canvas); + } else { + this.show(class_name, $off_canvas); + } + }, + + show : function (class_name, $off_canvas) { + $off_canvas = $off_canvas || this.get_wrapper(); + $off_canvas.trigger('open.fndtn.offcanvas'); + $off_canvas.addClass(class_name); + }, + + hide : function (class_name, $off_canvas) { + $off_canvas = $off_canvas || this.get_wrapper(); + $off_canvas.trigger('close.fndtn.offcanvas'); + $off_canvas.removeClass(class_name); + }, + + click_toggle_class : function (e, class_name) { + e.preventDefault(); + var $off_canvas = this.get_wrapper(e); + this.toggle(class_name, $off_canvas); + }, + + click_remove_class : function (e, class_name) { + e.preventDefault(); + var $off_canvas = this.get_wrapper(e); + this.hide(class_name, $off_canvas); + }, + + get_settings : function (e) { + var offcanvas = this.S(e.target).closest('[' + this.attr_name() + ']'); + return offcanvas.data(this.attr_name(true) + '-init') || this.settings; + }, + + get_wrapper : function (e) { + var $off_canvas = this.S(e ? e.target : this.scope).closest('.off-canvas-wrap'); + + if ($off_canvas.length === 0) { + $off_canvas = this.S('.off-canvas-wrap'); + } + return $off_canvas; + }, + + reflow : function () {} + }; +}(jQuery, window, window.document)); diff --git a/static/js/headroom.min.js b/static/js/headroom.min.js new file mode 100644 index 000000000..fcf9c18b2 --- /dev/null +++ b/static/js/headroom.min.js @@ -0,0 +1,7 @@ +/*! + * headroom.js v0.7.0 - Give your page some headroom. Hide your header until you need it + * Copyright (c) 2014 Nick Williams - http://wicky.nillia.ms/headroom.js + * License: MIT + */ + +!function(a,b){"use strict";function c(a){this.callback=a,this.ticking=!1}function d(b){return b&&"undefined"!=typeof a&&(b===a||b.nodeType)}function e(a){if(arguments.length<=0)throw new Error("Missing arguments in extend function");var b,c,f=a||{};for(c=1;ca,c=a+this.getViewportHeight()>this.getScrollerHeight();return b||c},toleranceExceeded:function(a,b){return Math.abs(a-this.lastKnownScrollY)>=this.tolerance[b]},shouldUnpin:function(a,b){var c=a>this.lastKnownScrollY,d=a>=this.offset;return c&&d&&b},shouldPin:function(a,b){var c=athis.lastKnownScrollY?"down":"up",c=this.toleranceExceeded(a,b);this.isOutOfBounds(a)||(a<=this.offset?this.top():this.notTop(),this.shouldUnpin(a,c)?this.unpin():this.shouldPin(a,c)&&this.pin(),this.lastKnownScrollY=a)}},g.options={tolerance:{up:0,down:0},offset:0,scroller:a,classes:{pinned:"headroom--pinned",unpinned:"headroom--unpinned",top:"headroom--top",notTop:"headroom--not-top",initial:"headroom"}},g.cutsTheMustard="undefined"!=typeof h&&h.rAF&&h.bind&&h.classList,a.Headroom=g}(window,document); \ No newline at end of file diff --git a/static/js/jquery-1.12.4.min.js b/static/js/jquery-1.12.4.min.js new file mode 100644 index 000000000..e83647587 --- /dev/null +++ b/static/js/jquery-1.12.4.min.js @@ -0,0 +1,5 @@ +/*! jQuery v1.12.4 | (c) jQuery Foundation | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="1.12.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.addEventListener?(d.removeEventListener("DOMContentLoaded",K),a.removeEventListener("load",K)):(d.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(d.addEventListener||"load"===a.event.type||"complete"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener("DOMContentLoaded",K),a.addEventListener("load",K);else{d.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll("left")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst="0"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName("body")[0],c&&c.style&&(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement("div");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b},N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0; +}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),"object"!=typeof b&&"function"!=typeof b||(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\w:-]+)/,_=/^$|\/(?:java|ecma)script/i,aa=/^\s+/,ba="abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video";function ca(a){var b=ba.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement("div"),b=d.createDocumentFragment(),c=d.createElement("input");a.innerHTML="
a",l.leadingWhitespace=3===a.firstChild.nodeType,l.tbody=!a.getElementsByTagName("tbody").length,l.htmlSerialize=!!a.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==d.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,b.appendChild(c),l.appendChecked=c.checked,a.innerHTML="",l.noCloneChecked=!!a.cloneNode(!0).lastChild.defaultValue,b.appendChild(a),c=d.createElement("input"),c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),a.appendChild(c),l.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!!a.addEventListener,a[n.expando]=1,l.attributes=!a.getAttribute(n.expando)}();var da={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:l.htmlSerialize?[0,"",""]:[1,"X
","
"]};da.optgroup=da.option,da.tbody=da.tfoot=da.colgroup=da.caption=da.thead,da.th=da.td;function ea(a,b){var c,d,e=0,f="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,ea(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function fa(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}var ga=/<|&#?\w+;/,ha=/r;r++)if(g=a[r],g||0===g)if("object"===n.type(g))n.merge(q,g.nodeType?[g]:g);else if(ga.test(g)){i=i||p.appendChild(b.createElement("div")),j=($.exec(g)||["",""])[1].toLowerCase(),m=da[j]||da._default,i.innerHTML=m[1]+n.htmlPrefilter(g)+m[2],f=m[0];while(f--)i=i.lastChild;if(!l.leadingWhitespace&&aa.test(g)&&q.push(b.createTextNode(aa.exec(g)[0])),!l.tbody){g="table"!==j||ha.test(g)?""!==m[1]||ha.test(g)?0:i:i.firstChild,f=g&&g.childNodes.length;while(f--)n.nodeName(k=g.childNodes[f],"tbody")&&!k.childNodes.length&&g.removeChild(k)}n.merge(q,i.childNodes),i.textContent="";while(i.firstChild)i.removeChild(i.firstChild);i=p.lastChild}else q.push(b.createTextNode(g));i&&p.removeChild(i),l.appendChecked||n.grep(ea(q,"input"),ia),r=0;while(g=q[r++])if(d&&n.inArray(g,d)>-1)e&&e.push(g);else if(h=n.contains(g.ownerDocument,g),i=ea(p.appendChild(g),"script"),h&&fa(i),c){f=0;while(g=i[f++])_.test(g.type||"")&&c.push(g)}return i=null,p}!function(){var b,c,e=d.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b]=c in a)||(e.setAttribute(c,"t"),l[b]=e.attributes[c].expando===!1);e=null}();var ka=/^(?:input|select|textarea)$/i,la=/^key/,ma=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,na=/^(?:focusinfocus|focusoutblur)$/,oa=/^([^.]*)(?:\.(.+)|)/;function pa(){return!0}function qa(){return!1}function ra(){try{return d.activeElement}catch(a){}}function sa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)sa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=qa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return"undefined"==typeof n||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(G)||[""],h=b.length;while(h--)f=oa.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=oa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(i=m=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!na.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),h=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),l=n.event.special[q]||{},f||!l.trigger||l.trigger.apply(e,c)!==!1)){if(!f&&!l.noBubble&&!n.isWindow(e)){for(j=l.delegateType||q,na.test(j+q)||(i=i.parentNode);i;i=i.parentNode)p.push(i),m=i;m===(e.ownerDocument||d)&&p.push(m.defaultView||m.parentWindow||a)}o=0;while((i=p[o++])&&!b.isPropagationStopped())b.type=o>1?j:l.bindType||q,g=(n._data(i,"events")||{})[b.type]&&n._data(i,"handle"),g&&g.apply(i,c),g=h&&i[h],g&&g.apply&&M(i)&&(b.result=g.apply(i,c),b.result===!1&&b.preventDefault());if(b.type=q,!f&&!b.isDefaultPrevented()&&(!l._default||l._default.apply(p.pop(),c)===!1)&&M(e)&&h&&e[q]&&!n.isWindow(e)){m=e[h],m&&(e[h]=null),n.event.triggered=q;try{e[q]()}catch(s){}n.event.triggered=void 0,m&&(e[h]=m)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]","i"),va=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,wa=/\s*$/g,Aa=ca(d),Ba=Aa.appendChild(d.createElement("div"));function Ca(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function Da(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function Ea(a){var b=ya.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Fa(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Ga(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(Da(b).text=a.text,Ea(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&Z.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}}function Ha(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&xa.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(o&&(k=ja(b,a[0].ownerDocument,!1,a,d),e=k.firstChild,1===k.childNodes.length&&(k=e),e||d)){for(i=n.map(ea(k,"script"),Da),h=i.length;o>m;m++)g=k,m!==p&&(g=n.clone(g,!0,!0),h&&n.merge(i,ea(g,"script"))),c.call(a[m],g,m);if(h)for(j=i[i.length-1].ownerDocument,n.map(i,Ea),m=0;h>m;m++)g=i[m],_.test(g.type||"")&&!n._data(g,"globalEval")&&n.contains(j,g)&&(g.src?n._evalUrl&&n._evalUrl(g.src):n.globalEval((g.text||g.textContent||g.innerHTML||"").replace(za,"")));k=e=null}return a}function Ia(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(ea(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&fa(ea(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(va,"<$1>")},clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!ua.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(Ba.innerHTML=a.outerHTML,Ba.removeChild(f=Ba.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=ea(f),h=ea(a),g=0;null!=(e=h[g]);++g)d[g]&&Ga(e,d[g]);if(b)if(c)for(h=h||ea(a),d=d||ea(f),g=0;null!=(e=h[g]);g++)Fa(e,d[g]);else Fa(a,f);return d=ea(f,"script"),d.length>0&&fa(d,!i&&ea(a,"script")),d=h=e=null,f},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.attributes,m=n.event.special;null!=(d=a[h]);h++)if((b||M(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k||"undefined"==typeof d.removeAttribute?d[i]=void 0:d.removeAttribute(i),c.push(f))}}}),n.fn.extend({domManip:Ha,detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return Y(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||d).createTextNode(a))},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(ea(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return Y(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(ta,""):void 0;if("string"==typeof a&&!wa.test(a)&&(l.htmlSerialize||!ua.test(a))&&(l.leadingWhitespace||!aa.test(a))&&!da[($.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ea(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(ea(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],f=n(a),h=f.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(f[d])[b](c),g.apply(e,c.get());return this.pushStack(e)}});var Ja,Ka={HTML:"block",BODY:"block"};function La(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function Ma(a){var b=d,c=Ka[a];return c||(c=La(a,b),"none"!==c&&c||(Ja=(Ja||n("