-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathbind-service.html.md.erb
147 lines (108 loc) · 5.28 KB
/
bind-service.html.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
---
title: Bind a Service to Your App
owner: Tobias Fuhrimann
---
<strong><%= modified_date %></strong>
The <a href="../service-offerings/index.html" target="_blank">service marketplace</a> has a large number of data stores, from Redis and MongoDB, to MariaDB (fork of MySQL) and RabbitMQ. You can run `cf marketplace` to get an overview. In this step you will add a small MongoDB database to your app.
Create the database:
<pre class="terminal">
$ cf create-service mongodb small my-mongodb
Creating service instance my-mongodb in org MyOrg / space MySpace as [email protected]...
OK
Create in progress. Use 'cf services' or 'cf service my-mongodb' to check operation status.
Attention: The plan `small` of service `mongodb` is not free. The instance `my-mongodb` will incur a cost. Contact your administrator if you think this is in error.
</pre>
This creates a small MongoDB database for you which we now have to bind to our application. Binding means that the credentials and URL of the service will be written dynamically into the environment variables of the app as `VCAP_SERVICES` and can hence be used directly from there.
Let's bind the new service to our existing application:
<pre class="terminal">
$ cf bind-service my-python-app my-mongodb
Binding service my-mongodb to app my-python-app in org MyOrg / space MySpace as [email protected]...
OK
TIP: Use 'cf restage my-python-app' to ensure your env variable changes take effect
</pre>
<p class="note">
<strong>Note</strong>: If you are getting <code>Server error, status code: 409</code>, please try again after a couple of minutes. It takes a while to spin up that MongoDB for you.
</p>
After that we restage the application as suggested so that it includes the new credentials in its environment variables:
<pre class="terminal">
$ cf restage my-python-app
Restaging app my-app in org MyOrg / space MySpace as [email protected]...
-----> Downloaded app package (8.0K)
-------> Buildpack version 1.5.4
-----> Creating runtime environment
...
</pre>
Now we want to consume our new MongoDB from within our application. To do so, add the `Flask-MongoEngine` module to your dependencies in `requirements.txt`:
```txt
Flask>=0.11
Flask-MongoEngine>=0.8
```
Then use pip to install our newly added dependencies:
<pre class="terminal">
$ pip install -r requirements.txt
</pre>
Now edit your `app.py` file to use this module and other native ones to connect to the database specified in your `VCAP_SERVICES` environment variable. We do this by importing the `MongoEngine` module and the native `json` module and by adding a route for the `/db` endpoint which returns the `kittens` collection of our MongoDB:
```python
# import dependencies
import os
import json
from flask import Flask
from flask import request
from flask_mongoengine import MongoEngine
# bootstrap the app
app = Flask(__name__)
# check if running in the cloud and set MongoDB settings accordingly
if 'VCAP_SERVICES' in os.environ:
vcap_services = json.loads(os.environ['VCAP_SERVICES'])
mongo_credentials = vcap_services['mongodb'][0]['credentials']
mongo_uri = mongo_credentials['uri']
else:
mongo_uri = 'mongodb://localhost/db'
app.config['MONGODB_SETTINGS'] = {
'host': mongo_uri
}
# bootstrap our app
db = MongoEngine(app)
# create the Kitten class which serves as a model for kittens stored in MongoDB
class Kitten(db.Document):
name = db.StringField(required=True)
# set the port dynamically with a default of 3000 for local development
port = int(os.getenv('PORT', '3000'))
# our base route which just returns a string
@app.route('/')
def hello_world():
return 'Congratulations! Welcome to the Swisscom Application Cloud.'
# endpoint to create a new kitten (e.g. /create-kitten?name=garfield)
@app.route('/create-kitten', methods=['POST'])
def add_kitten():
kitten_name = request.args.get('name')
kitten = Kitten(name=kitten_name)
kitten.save()
return 'Kitten %s added' % (kitten_name)
# endpoint to return all kittens
@app.route('/db')
def get_kittens():
kittens = Kitten.objects.to_json()
return kittens
# start the app
if __name__ == '__main__':
app.run(host='0.0.0.0', port=port)
```
This ensures that when you access your app using the `/db` route, it will return all the kittens stored in your database. Currently there are no kittens so it will return an empty array. Sad...
But you can create new kittens by POST-ing to the `/create-kitten` endpoint with the kitten's name as a URL query parameter. You can do so using curl or any similar tool:
<pre class="terminal">
$ curl -X POST "http://localhost:3000/create-kitten?name=garfield"
</pre>
and then retrieve your new kitten at the `/db` endpoint.
The line
```python
if 'VCAP_SERVICES' in os.environ:
```
checks if the app is running in the cloud. If not, it falls back to the default local MongoDB url. This allows you to run your app locally as well as in the cloud without having to configure anything differently. So let's push it to the cloud using
<pre class="terminal">
$ cf push my-python-app
</pre>
You can access other services like Redis or MariaDB in a similar matter, simply by binding them to your app and accessing them through the environment variables.
<div style="text-align:center;padding:3em;">
<a href="./manifest.html" class="btn btn-primary">I've bound a service to my App</a>
</div>