The terms REST and RESTful spark in the mind varying definitions for everyone who reads them. The following definitions are provided to avoid confusion. These definitions may, or may not, comport with the canonical definition of REST, let alone even begin to argue what that concept is. The purpose served here is to remove any uncertainty for users of this particular API.
The only goal is to achieve consistent use within the protocol definition here. To aid in this consistency, especially with regard to related projects, this API supports the resource operation definitions described in the Kubernetes API Specification.
This simple approach uses a functional mapping between the standard Create, Read, Update, and Delete (CRUD) operations and HTTP methods. The functional mapping of resource operations to HTTP verbs is defined as follows:
- Create - POST
- Read - GET
- Update - PUT (replace in whole) or PATCH (update in part)
- Delete - DELETE
In addition, the API supports all the standard protocol conventions with respect to the idempotency of actions related to HTTP Requests and caching of HTTP Responses.
The API Specification for the project's master branch is available here: Swagger.io Editor
IMPORTANT NOTE: The only authoritative definition of the resources and endpoints defined for any instance of the API, as well as the methods that are supported for a given resource, is the OpenAPI (aka Swagger 2.0) definition generated by the running API Server itself. The API Specification link above is provided for convenience, but it is the representation of the API design that is accessible on the master branch of this online repository only.
In an effort to keep this project as DRY as possible, the following is minimalist description of the resources defined for the interface.
The following are the major categories of resources administered by the API.
- OpenAPI - The OpenAPI (Swagger 2.0) specification for this interface
- Swagger - The Swagger 2.0 (OpenAPI) specification for this interface
- Projects Collection - The primary unit of isolation for users, tennant, teams, etc...
- Namespaces Collection - The project's namespace(s), e.g. "proj-dev", "prog-test", "prog-prod"
- Applications Collection - The namespace's installed applications
- Cluster - The namespace's Kraken orchestrated Kubernetes cluster resources object
There are two restriction on the ordering of operations for the API.
-
The
namespace
resource must be created (POST) before acluster
resource can be created. Any attempt to perform an operation on thecluster
endpoint when nonamespace
endpoint is defined will return an error response code. -
The
cluster
resource must be created (POST) before anapplication
resource can be created. Any attempt to perform an operation on theapplication
endpoint when nocluster
endpoint is defined will return an error response code. While not strictly necessary, it is preferable to read the status of thecluster
endpoint and check that the cluster resources are in an "active" state, as shown below before performing additional operations. If the cluster resources are not ready when an application is deployed, then the create request will still be accepted however the application deployment may timeout (faile) and subsequently need to be resubmitted.
Status: 200 (Ok)
{
"type": "cluster",
"id": "de2760b1",
"nodePoolSize": 3,
"state": "create_requested"
"created_at": "1988-11-12T15:18:46-08:00",
}
The following example uses the commonly available curl
command to create and retrieve objects from the API. Note that in all the following examples the JSON output has been run through a formatter for improved readability. The JSON pretty printing process is not shown here.
- Create (POST) an initial project, then read (GET) it back
$ curl -XPOST -H "Content-Type: application/json" \
-d '{"name":"acme"}' http://localhost:8080/v1/projects
{
"created_at": "2017-08-11T22:03:46.021222713-07:00",
"id": "d1226f6a",
"name": "acme",
"namespaces": null,
"type": "project"
}
# GET the projects collection
$ curl http://localhost:8080/v1/projects
[{
"created_at": "2017-08-11T22:03:46.021222713-07:00",
"id": "d1226f6a",
"name": "acme",
"namespaces": null,
"type": "project"
}]
# Alternately - GET just the single project
$ curl http://localhost:8080/v1/projects/a0b4574a
{
"created_at": "2017-08-11T22:03:46.021222713-07:00",
"id": "d1226f6a",
"name": "acme",
"namespaces": null,
"type": "project"
}
- Create (POST) a namespace in the newly created project, and read (GET) it back.
$ curl -XPOST -H "Content-Type: application/json" \
-d '{"name":"acme-prod"}' http://localhost:8080/v1/projects/d1226f6a/namespaces
{
"applications": null,
"created_at": "2017-08-11T22:04:48.613174018-07:00",
"id": "20b5bac8",
"name": "acme-prod",
"resources": null,
"type": "namespace"
}
# GET the namespaces collection
$ curl http://localhost:8080/v1/projects/d1226f6a/namespaces
[{
"applications": null,
"created_at": "2017-08-11T22:04:48.613174018-07:00",
"id": "20b5bac8",
"name": "acme-prod",
"resources": null,
"type": "namespace"
}]
# Alternately - GET just the single namespace
$ curl http://localhost:8080/v1/projects/d1226f6a/namespaces/20b5bac8
{
"applications": null,
"created_at": "2017-08-11T22:04:48.613174018-07:00",
"id": "20b5bac8",
"name": "acme-prod",
"resources": null,
"type": "namespace"
}
- Create (POST) a cluster resources specification in the newly created namespace, and read (GET) it back.
$ curl -XPOST -H "Content-Type: application/json" \
-d '{"namespace_id":"20b5bac8", "nodePoolSize": 7}' \
http://localhost:8080/v1/projects/d1226f6a/cluster
{
"created_at": "0001-01-01T00:00:00Z",
"id": "c7454a66",
"namespace_id": "20b5bac8",
"nodePoolSize": 7,
"state": "create_requested",
"type": "Resource"
}
# GET the cluster resources specification
$ curl http://localhost:8080/v1/projects/d1226f6a/cluster/c7454a66
{
"created_at": "0001-01-01T00:00:00Z",
"id": "c7454a66",
"namespace_id": "20b5bac8",
"nodePoolSize": 7,
"state": "create_requested",
"type": "Resource"
}
- Create (POST) an application in to the namespace in the project, and read (GET) it back.
$ curl -XPOST -H "Content-Type: application/json" \
-d '{"name": "AcmeWidgetPipeline", "version": "v1.0.0-alpha.2", "namespace_id":"20b5bac8"}' \
http://localhost:8080/v1/projects/d1226f6a/applications
{
"id": "99bf7a79",
"name": "AcmeWidgetPipeline",
"namespace_id": "20b5bac8",
"status": null,
"type": "application",
"version": "v1.0.0-alpha.2"
}
# GET the applications collection for the namespace
$ curl -XGET -H "Content-Type: application/json" \
-d '{"namespaceid":"20b5bac8"}' http://localhost:8080/v1/projects/d1226f6a/applications
[{
"id": "99bf7a79",
"name": "AcmeWidgetPipeline",
"namespace_id": "20b5bac8",
"status": null,
"type": "application",
"version": "v1.0.0-alpha.2"
}]
# Alternately - GET just the single application
$ curl http://localhost:8080/v1/projects/d1226f6a/applications/99bf7a79
{
"id": "99bf7a79",
"name": "AcmeWidgetPipeline",
"namespace_id": "20b5bac8",
"status": null,
"type": "application",
"version": "v1.0.0-alpha.2"
}
- Note that, as we've been creating objects in the API that have relationships with existing objects, those existing objects have been incrementally updated with references to the newly created elements.
# Repeat the GET on the project object
$ curl http://localhost:8080/v1/projects/d1226f6a
{
"created_at": "2017-08-11T22:03:46.021222713-07:00",
"id": "d1226f6a",
"name": "acme",
"namespaces": [{
"oid": "20b5bac8",
"url": "/v1/projects/d1226f6a/namespaces/20b5bac8"
}],
"type": "project"
}
# Repeat the GET on the namespace object
$ curl http://localhost:8080/v1/projects/d1226f6a/namespaces/20b5bac8
{
"applications": [{
"oid": "99bf7a79",
"url": "/v1/projects/d1226f6a/applications/99bf7a79"
}],
"created_at": "2017-08-11T22:04:48.613174018-07:00",
"id": "20b5bac8",
"name": "acme-prod",
"resources": {
"oid": "c7454a66",
"url": "/v1/projects/d1226f6a/cluster/c7454a66"
},
"type": "namespace"
}
The following example also uses curl
commands to create and retrieve objects from the API. This example doesn't try to demonstrate all of the functionality of various endpoints. Rather, the goal here is to illustrate what might be a typical workflow for creating a couple of projects, their related resources, an application, and then taking down some (or all) of those resources.
Using a cluster named "Meteor", we'll create some constellation related projects.
- Initial Conditions Show the running version of the API and the current state of the cluster's deployed resources (should be empty at this stage).
$ curl -i http://10.37.145.20:8080/v1/healthz
HTTP/1.1 200 OK
Content-Type: text/plain
Date: Tue, 26 Sep 2017 05:06:12 GMT
Content-Length: 121
Health OK: 2017-09-26 05:06:12.545093892 +0000 UTC, semVer: 0.3.33-beta+git.sha.2b88072289849a3dc3d5e735b67fd6fbda655870
$ curl -i http://10.37.145.20:8080/v1/projects
HTTP/1.1 200 OK
Content-Type: application/project+json; type=collection
Date: Tue, 26 Sep 2017 05:06:14 GMT
Content-Length: 3
[]
- Next are three preparatory steps shown to create a project, namespace, and node pool.
- Create the project
neptune
- Create a namespace for the project,
neptune-test
- Create the cluster resources associated with this project/namespaces.
- Create the project
# 1.1 Create the project
$ curl -i -XPOST -H "Content-Type: application/json" -d '{"name":"neptune"}' http://10.37.145.20:8080/v1/projects
HTTP/1.1 201 Created
Content-Type: application/project+json
Date: Tue, 26 Sep 2017 05:08:07 GMT
Content-Length: 116
{
"created_at": "2017-09-26T05:08:07.332657843Z",
"id": "88fe3382",
"name": "neptune",
"namespaces": null,
"type": "project"
}
# 1.2 Create the first namespace for the project
$ curl -i -XPOST -H "Content-Type: application/json" -d '{"name":"neptune-test"}' http://10.37.145.20:8080/v1/projects
/88fe3382/namespaces
HTTP/1.1 201 Created
Content-Type: application/namespace+json
Date: Tue, 26 Sep 2017 05:09:50 GMT
Content-Length: 142
{
"applications": null,
"created_at": "2017-09-26T05:09:50.708529306Z",
"id": "114eaa29",
"name": "neptune-test",
"resources": null,
"type": "namespace"
}
# 1.3 Create the cluster resources (node pool) for the project/namespace
$ curl -i -XPOST -H "Content-Type: application/json" -d '{"namespace_id":"114eaa29", "nodePoolSize": 4}' http://10.37.
145.20:8080/v1/projects/88fe3382/cluster
HTTP/1.1 202 Accepted
Content-Type: application/cluster+json
Date: Tue, 26 Sep 2017 05:11:37 GMT
Content-Length: 188
{
"created_at": "2017-09-26T05:11:37.978446011Z",
"id": "931479e5",
"namespace_id": "114eaa29",
"nodePoolSize": 4,
"state": "create_requested",
"type": "Resource",
"updated_at": "0001-01-01T00:00:00Z"
}
- This final step can take a significant amount of time. It's not unusual for this to take anywhere from 5 to 15 minutes, sometimes less, almost never more. As such, it is necessary to poll the newly created endpoint periodically to see it make the transition from either
"state": "create_requested"
or"state": "starting"
to the desired ready"state": "active"
- shown below.
$ curl -i http://10.37.145.20:8080/v1/projects/88fe3382/cluster/931479e5
HTTP/1.1 200 OK
Content-Type: application/cluster+json
Date: Tue, 26 Sep 2017 05:12:27 GMT
Content-Length: 190
{
"created_at": "2017-09-26T05:11:37.978446011Z",
"id": "931479e5",
"namespace_id": "114eaa29",
"nodePoolSize": 4,
"state": "starting",
"type": "Resource",
"updated_at": "2017-09-26T05:11:38.038143732Z"
}
We repeat the polling process until a state change is observed:
$ curl -i http://10.37.145.20:8080/v1/projects/88fe3382/cluster/931479e5
HTTP/1.1 200 OK
Content-Type: application/cluster+json
Date: Tue, 26 Sep 2017 05:19:24 GMT
Content-Length: 188
{
"created_at": "2017-09-26T05:11:37.978446011Z",
"id": "931479e5",
"namespace_id": "114eaa29",
"nodePoolSize": 4,
"state": "active",
"type": "Resource",
"updated_at": "2017-09-26T05:19:11.720229417Z"
}
Important Note: Normally we would like to see the state reach the value, "state": "active"
(as in this case). However, sometimes the state of the cluster has reached the point where we can continue, but with a transient error. When the node state has reaches the value "state": "error_starting"
, it is possible continue with the understanding that a transient error may have occurred. Alternatively, we could delete the cluster resource and reattempt the create method in the hopes that the second attempt will come up clean. Normally, we choose to push forward with the current state, reasonably confident that the errors were likely do to slow cloud provider resource initializations.
From the API servers log output we see that this operation took about 7 1/2 minutes to complete, also noted in the difference between the crated and updated timestamps in the object itself.
I0926 05:19:11.720265 1 runner.go:422] Queued task delted: type: AddProject, name: neptune, namespace: neptune-test, queueing duration: 7m33.740821987s, running duration 7m33.68208599s
Everytime a physical change to the infrastructure of the cluster is requested, the persistent state of the cluster is reflected in both the clusters config.yaml
file and the terraform manifest associated with the cluster. For example, after running the sequence above successfully, the config file shows the delta between the current and backup versions of the file.
$ diff config.yaml config.yaml.1506375409
--- config.yaml
+++ config.yaml.1506375409
@@ -548,18 +548,6 @@
nodeConfig: *gitlabAwsC4xlarge
keyPair: *colonybeadKeyPair
# |--> NODE_POOL_MARKER <--|--> DO NOT REMOVE: REQUIRED FOR FOR CONFIG AUTOMATION <--|
- - name: neptuneNodes
- count: 4
- kubeConfig: *colonybeadKube
- containerConfig: *defaultDocker
- osConfig: *defaultCoreOs
- nodeConfig:
- << : *defaultAwsClusterNode
- taints:
- - key: customer
- value: neptune
- effect: NoSchedule
- keyPair: *colonybeadKeyPair
Finally we can view the cluster resources directly.
$ kubectl get nodes -l nodepool=neptuneNodes
NAME STATUS AGE VERSION
ip-10-0-13-106.us-west-2.compute.internal Ready 3m v1.6.4
ip-10-0-236-3.us-west-2.compute.internal Ready 2m v1.6.4
ip-10-0-47-202.us-west-2.compute.internal Ready 3m v1.6.4
ip-10-0-70-230.us-west-2.compute.internal Ready 2m v1.6.4
- Next we bring up a MongoDB Application using the newly created resources.
Note: unescaped line breaks are added for readability only
$ curl -i -XPOST -H "Content-Type: application/json"
-d '{ "deployment_name": "neptune-mongodb", "server": "quay.io",
"registry": "samsung_cnct", "name": "mongodb-replicaset",
"version": "latest", "channel": "stable", "namespace_id": "114eaa29"}'
http://10.37.145.20:8080/v1/projects/88fe3382/applications
HTTP/1.1 202 Accepted
Content-Type: application/application+json
Date: Tue, 26 Sep 2017 05:20:43 GMT
Content-Length: 413
{
"channel": "stable",
"config": "",
"created_at": "2017-09-26T05:20:43.592429728Z",
"deployment_name": "neptune-mongodb",
"id": "e14a6b25",
"json_values": "",
"name": "mongodb-replicaset",
"namespace_id": "114eaa29",
"registry": "samsung_cnct",
"server": "quay.io",
"status": {
"deployed_at": "0001-01-01T00:00:00Z",
"state": "UNKNOWN"
},
"type": "application",
"updated_at": "2017-09-26T05:20:43.594109357Z",
"username": "",
"version": "latest"
}
A short while later, we query that state of the application to determine if the deployment succeeded.
$ curl -i http://10.37.145.20:8080/v1/projects/88fe3382/applications/e14a6b25
HTTP/1.1 200 OK
Content-Type: application/application+json
Date: Tue, 26 Sep 2017 05:21:24 GMT
Content-Length: 424
{
"channel": "stable",
"config": "",
"created_at": "2017-09-26T05:20:43.592429728Z",
"deployment_name": "neptune-mongodb",
"id": "e14a6b25",
"json_values": "",
"name": "mongodb-replicaset",
"namespace_id": "114eaa29",
"registry": "samsung_cnct",
"server": "quay.io",
"status": {
"deployed_at": "2017-09-26T05:20:47.930774281Z",
"state": "DEPLOYED"
},
"type": "application",
"updated_at": "2017-09-26T05:20:47.930774962Z",
"username": "",
"version": "latest"
}
As validation we check the deployment externally through helm
.
$ helm list --namespace neptune-test
NAME REVISION UPDATED STATUS CHART NAMESPACE
neptune-mongodb 1 Mon Sep 25 22:20:47 2017 DEPLOYED mongodb-replicaset-1.2.0-0 neptune-test
$ helm status neptune-mongodb
LAST DEPLOYED: Mon Sep 25 22:20:47 2017
NAMESPACE: neptune-test
STATUS: DEPLOYED
RESOURCES:
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
neptune-mongodb-mongodb-replicaset None <none> 27017/TCP 1m
==> v1beta1/StatefulSet
NAME DESIRED CURRENT AGE
neptune-mongodb-mongodb-replicaset 3 1 1m
==> v1/ConfigMap
NAME DATA AGE
neptune-mongodb-mongodb-replicaset 1 1m
neptune-mongodb-mongodb-replicaset-tests 1 1m
And we can check the Kubernetes resources associated with the deployment.
$ kubectl get statefulset,svc,ep,pods -n neptune-test
NAME DESIRED CURRENT AGE
statefulsets/neptune-mongodb-mongodb-replicaset 3 3 2m
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/neptune-mongodb-mongodb-replicaset None <none> 27017/TCP 2m
NAME ENDPOINTS AGE
ep/neptune-mongodb-mongodb-replicaset 10.128.54.2:27017,10.128.55.2:27017,10.128.56.2:27017 2m
NAME READY STATUS RESTARTS AGE
po/neptune-mongodb-mongodb-replicaset-0 1/1 Running 0 2m
po/neptune-mongodb-mongodb-replicaset-1 1/1 Running 0 2m
po/neptune-mongodb-mongodb-replicaset-2 1/1 Running 0 1m
- Now that we have a running instance of MongoDB, let's deploy an application that uses it. The application deployment is pulled from a private repository, so we provide a JSON object that specifies the credentials we use to access the application repository (the actual credentials are redacted in the example).
$ curl -i -XPOST -H "Content-Type: application/json" -d '@./post_body.json' http://10.37.145.20:8080/v1/projects/88fe3
382/applications
HTTP/1.1 202 Accepted
Content-Type: application/application+json
Date: Tue, 26 Sep 2017 05:26:00 GMT
Content-Length: 639
{
"channel": "stable",
"config": "",
"created_at": "2017-09-26T05:26:00.928058318Z",
"deployment_name": "neptune-reaction",
"id": "fbc82965",
"json_values": "{\"ingress\":{\"defaultHost\":{\"hostname\":\"neptune.getreaction.io\"}},\"app\":{\"envVars\":[{\"key\":\"ROOT_URL\",\"value\":\"https://neptune.getreaction.io\"}]},\"mongo\":{\"deploymentName\":\"neptune-mongodb\"}}",
"name": "reactioncommerce",
"namespace_id": "114eaa29",
"registry": "reactioncommerce",
"server": "quay.io",
"status": {
"deployed_at": "0001-01-01T00:00:00Z",
"state": "UNKNOWN"
},
"type": "application",
"updated_at": "2017-09-26T05:26:00.928097784Z",
"username": "sostheim",
"version": "0.5.0"
}
The curl command above passes in a local file as the --data
argument. The contents of the file are shown below with redactions.
$ cat post_body.json
{
"password": "-----------------------------------",
"username": "sostheim",
"deployment_name": "neptune-reaction",
"server": "quay.io",
"registry": "reactioncommerce",
"name": "reactioncommerce",
"version": "0.5.0",
"channel": "stable",
"namespace_id": "114eaa29",
"json_values": "{\"ingress\":{\"defaultHost\":{\"hostname\":\"neptune.getreaction.io\"}},\"app\":{\"envVars\":[{\"key\":\"ROOT_URL\",\"value\":\"https://neptune.getreaction.io\"}]},\"mongo\":{\"deploymentName\":\"neptune-mongodb\"}}"
}
As before, a short while later, we query that state of the application to determine if the deployment succeeded.
$ curl -i http://10.37.145.20:8080/v1/projects/88fe3382/applications/fbc82965
HTTP/1.1 200 OK
Content-Type: application/application+json
Date: Tue, 26 Sep 2017 05:26:50 GMT
Content-Length: 650
{
"channel": "stable",
"config": "",
"created_at": "2017-09-26T05:26:00.928058318Z",
"deployment_name": "neptune-reaction",
"id": "fbc82965",
"json_values": "{\"ingress\":{\"defaultHost\":{\"hostname\":\"neptune.getreaction.io\"}},\"app\":{\"envVars\":[{\"key\":\"ROOT_URL\",\"value\":\"https://neptune.getreaction.io\"}]},\"mongo\":{\"deploymentName\":\"neptune-mongodb\"}}",
"name": "reactioncommerce",
"namespace_id": "114eaa29",
"registry": "reactioncommerce",
"server": "quay.io",
"status": {
"deployed_at": "2017-09-26T05:26:07.729224972Z",
"state": "DEPLOYED"
},
"type": "application",
"updated_at": "2017-09-26T05:26:07.729225563Z",
"username": "sostheim",
"version": "0.5.0"
}
As we have previously, we externally check the created elements.
$ helm list --namespace neptune-test
NAME REVISION UPDATED STATUS CHART NAMESPACE
neptune-mongodb 1 Mon Sep 25 22:20:47 2017 DEPLOYED mongodb-replicaset-1.2.0-0 neptune-test
neptune-reaction 1 Mon Sep 25 22:26:06 2017 DEPLOYED reactioncommerce-0.5.1 neptune-test
$ kubectl get statefulset,deploy,rs,svc,ep,pods -n neptune-test
NAME DESIRED CURRENT AGE
statefulsets/neptune-mongodb-mongodb-replicaset 3 3 7m
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deploy/neptune-reaction-reactioncommerce 1 1 1 1 1m
NAME DESIRED CURRENT READY AGE
rs/neptune-reaction-reactioncommerce-1212697681 1 1 1 1m
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/neptune-mongodb-mongodb-replicaset None <none> 27017/TCP 7m
svc/neptune-reaction-reactioncommerce 10.39.15.26 <none> 80/TCP 1m
NAME ENDPOINTS AGE
ep/neptune-mongodb-mongodb-replicaset 10.128.54.2:27017,10.128.55.2:27017,10.128.56.2:27017 7m
ep/neptune-reaction-reactioncommerce 10.128.52.3:3000 1m
NAME READY STATUS RESTARTS AGE
po/neptune-mongodb-mongodb-replicaset-0 1/1 Running 0 7m
po/neptune-mongodb-mongodb-replicaset-1 1/1 Running 0 6m
po/neptune-mongodb-mongodb-replicaset-2 1/1 Running 0 5m
po/neptune-reaction-reactioncommerce-1212697681-0lb5d 1/1 Running 0 1m
- After sometime, we decide that Neptune Test resources need to be removed them from the cluster.
# We check the resources one last time before beginning to remove them
$ curl -i http://10.37.145.20:8080/v1/projects/88fe3382/namespaces/114eaa29
HTTP/1.1 200 OK
Content-Type: application/namespace+json
Date: Tue, 26 Sep 2017 05:47:05 GMT
Content-Length: 342
{
"applications": [{
"oid": "e14a6b25",
"url": "/v1/projects/88fe3382/applications/e14a6b25"
}, {
"oid": "fbc82965",
"url": "/v1/projects/88fe3382/applications/fbc82965"
}],
"created_at": "2017-09-26T05:09:50.708529306Z",
"id": "114eaa29",
"name": "neptune-test",
"resources": {
"oid": "931479e5",
"url": "/v1/projects/88fe3382/cluster/931479e5"
},
"type": "namespace"
}
$ curl -i http://10.37.145.20:8080/v1/projects/88fe3382/applications/fbc82965
HTTP/1.1 200 OK
Content-Type: application/application+json
Date: Tue, 26 Sep 2017 05:47:29 GMT
Content-Length: 650
{
"channel": "stable",
"config": "",
"created_at": "2017-09-26T05:26:00.928058318Z",
"deployment_name": "neptune-reaction",
"id": "fbc82965",
"json_values": "{\"ingress\":{\"defaultHost\":{\"hostname\":\"neptune.getreaction.io\"}},\"app\":{\"envVars\":[{\"key\":\"ROOT_URL\",\"value\":\"https://neptune.getreaction.io\"}]},\"mongo\":{\"deploymentName\":\"neptune-mongodb\"}}",
"name": "reactioncommerce",
"namespace_id": "114eaa29",
"registry": "reactioncommerce",
"server": "quay.io",
"status": {
"deployed_at": "2017-09-26T05:26:07.729224972Z",
"state": "DEPLOYED"
},
"type": "application",
"updated_at": "2017-09-26T05:26:07.729225563Z",
"username": "sostheim",
"version": "0.5.0"
}
As a first step, we delete just one object, last application that was deployed.
$ curl -i -XDELETE http://10.37.145.20:8080/v1/projects/88fe3382/applications/fbc82965
HTTP/1.1 204 No Content
Date: Tue, 26 Sep 2017 05:48:25 GMT
$ curl -i http://10.37.145.20:8080/v1/projects/88fe3382/applications/fbc82965
HTTP/1.1 404 Not Found
Date: Tue, 26 Sep 2017 05:48:44 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8
$ curl -i http://10.37.145.20:8080/v1/projects/88fe3382/namespaces/114eaa29
HTTP/1.1 200 OK
Content-Type: application/namespace+json
Date: Tue, 26 Sep 2017 05:49:02 GMT
Content-Length: 271
{
"applications": [{
"oid": "e14a6b25",
"url": "/v1/projects/88fe3382/applications/e14a6b25"
}],
"created_at": "2017-09-26T05:09:50.708529306Z",
"id": "114eaa29",
"name": "neptune-test",
"resources": {
"oid": "931479e5",
"url": "/v1/projects/88fe3382/cluster/931479e5"
},
"type": "namespace"
}
Note: Much as the resource creation process has state transitions, so does releasing resources. Although the deletion process above took place to quickly to show them, the resources go from "active"
to "deleting"
and finally to "deleted"
.
As one last point of validation, we check that the application has been deleted from helm
.
$ helm list --namespace neptune-test
NAME REVISION UPDATED STATUS CHART NAMESPACE
neptune-mongodb 1 Mon Sep 25 22:20:47 2017 DEPLOYED mongodb-replicaset-1.2.0-0 neptune-test
After deleting a single object, we decide instead to use a cascading delete of the entire project. Applying a DELETE operation to any endpoint with aggregate objects causes all of the aggregated objects to be deleted in an appropriate sequence.
# One last check of the project state.
$ curl -i http://10.37.145.20:8080/v1/projects/88fe3382
HTTP/1.1 200 OK
Content-Type: application/project+json
Date: Tue, 26 Sep 2017 05:54:49 GMT
Content-Length: 182
{
"created_at": "2017-09-26T05:08:07.332657843Z",
"id": "88fe3382",
"name": "neptune",
"namespaces": [{
"oid": "114eaa29",
"url": "/v1/projects/88fe3382/namespaces/114eaa29"
}],
"type": "project"
}
# And now we delete it.
$ curl -i -XDELETE http://10.37.145.20:8080/v1/projects/88fe3382
HTTP/1.1 204 No Content
Date: Tue, 26 Sep 2017 05:56:27 GMT
$ curl -i http://10.37.145.20:8080/v1/projects
HTTP/1.1 200 OK
Content-Type: application/project+json; type=collection
Date: Tue, 26 Sep 2017 05:56:50 GMT
Content-Length: 3
[]
Typically the applications are able to be removed very quickly so we see them disappear almost right away. Very much like the creation process, removing the nodes from our cloud provider takes considerably more time. After a brief period, 3-5 minutes, we check all the cluster elements and see that everything has been successfully removed.
$ helm list --namespace neptune-test
$ kubectl get replicaset,deploy,rs,svc,ep,pods -n neptune-test
No resources found.
$ kubectl get nodes -l nodepool=neptuneNodes
No resources found.