Skip to content

Commit d6aaf55

Browse files
authored
Merge pull request #8 from nebula-orchestrator/2.0.0a
2.0.0a
2 parents 8bd1215 + ea7366b commit d6aaf55

File tree

7 files changed

+373
-34
lines changed

7 files changed

+373
-34
lines changed

.travis.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
language: python
2+
python:
3+
- "2.7"
4+
install:
5+
- pip install -r requirements.txt
6+
script:
7+
- python -m unittest discover

CONTRIBUTING

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Nebula is designed with the following philosophy in mind, any feature\pull reque
1919
* Reliability is more important then shiny new features.
2020
* No vendor\cloud lock-in, if it's only available in one cloud it will not be used.
2121
* No latency sensitivity, assume workers to have a below average internet access and are in the other side of the world.
22-
* Fully stateless, all data is to be saved in the backend DB & all communication between components is to be passed through the massage queue.
22+
* Fully stateless, all data is to be saved in the backend DB.
2323

2424
### Documentation
2525

NebulaPythonSDK/sdk.py

Lines changed: 94 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,96 +5,160 @@ class Nebula:
55

66
# the nebula class init module serves as the login against the nebula API as it's the only shared thing among the
77
# class functions
8-
def __init__(self, username, password, host, port=80, protocol="http", request_timeout=60):
8+
def __init__(self, username=None, password=None, host="127.0.0.1", port=80, protocol="http", request_timeout=60):
99
self.request_timeout = request_timeout
1010
self.username = username
1111
self.password = password
1212
self.protocol = protocol
13-
self.protocol = port
13+
self.port = port
1414
self.host = protocol + "://" + host + ":" + str(port)
15-
self.basic_auth = base64.b64encode(username + ":" + password)
1615
self.headers = {
17-
'authorization': "Basic " + self.basic_auth,
1816
'content-type': "application/json",
1917
'cache-control': "no-cache"
2018
}
19+
if username is not None and password is not None:
20+
self.basic_auth = base64.b64encode(username + ":" + password)
21+
self.headers["authorization"] = "Basic " + self.basic_auth
22+
self.API_VERSION = "v2"
2123

2224
# create a new nebula app, requires the app name to create and a complete dict of the config values for it
2325
def create_app(self, app, config):
24-
url = self.host + "/api/apps/" + app
26+
url = self.host + "/api/" + self.API_VERSION + "/apps/" + app
2527
payload = json.dumps(config)
2628
headers = self.headers
2729
response = requests.request("POST", url, data=payload, headers=headers, timeout=self.request_timeout)
28-
return response
30+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
31+
return filtered_response
2932

3033
# delete an existing nebula app, no confirmation required in SDK so be careful
3134
def delete_app(self, app):
32-
url = self.host + "/api/apps/" + app
35+
url = self.host + "/api/" + self.API_VERSION + "/apps/" + app
3336
headers = self.headers
3437
response = requests.request("DELETE", url, headers=headers, timeout=self.request_timeout)
35-
return response
38+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
39+
return filtered_response
3640

3741
# list all of the apps managed by nebula
3842
def list_apps(self):
39-
url = self.host + "/api/apps"
43+
url = self.host + "/api/" + self.API_VERSION + "/apps"
4044
headers = self.headers
4145
response = requests.request("GET", url, headers=headers, timeout=self.request_timeout)
42-
return response
46+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
47+
return filtered_response
4348

4449
# list the config of a nebula app, only requires the app name
4550
def list_app_info(self, app):
46-
url = self.host + "/api/apps/" + app
51+
url = self.host + "/api/" + self.API_VERSION + "/apps/" + app
4752
headers = self.headers
4853
response = requests.request("GET", url, headers=headers, timeout=self.request_timeout)
49-
return response
54+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
55+
return filtered_response
5056

5157
# stop a nebula app, only requires the app name
5258
def stop_app(self, app):
53-
url = self.host + "/api/apps/" + app + "/stop"
59+
url = self.host + "/api/" + self.API_VERSION + "/apps/" + app + "/stop"
5460
headers = self.headers
5561
response = requests.request("POST", url, headers=headers, timeout=self.request_timeout)
56-
return response
62+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
63+
return filtered_response
5764

5865
# start a nebula app, only requires the app name
5966
def start_app(self, app):
60-
url = self.host + "/api/apps/" + app + "/start"
67+
url = self.host + "/api/" + self.API_VERSION + "/apps/" + app + "/start"
6168
headers = self.headers
6269
response = requests.request("POST", url, headers=headers, timeout=self.request_timeout)
63-
return response
70+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
71+
return filtered_response
6472

6573
# restart a nebula app, only requires the app name
6674
def restart_app(self, app):
67-
url = self.host + "/api/apps/" + app + "/restart"
75+
url = self.host + "/api/" + self.API_VERSION + "/apps/" + app + "/restart"
6876
headers = self.headers
6977
response = requests.request("POST", url, headers=headers, timeout=self.request_timeout)
70-
return response
78+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
79+
return filtered_response
7180

7281
# update a nebula app, requires the app name and a dict of the config values you want to change, any combination of
7382
# config values is accepted as it keeps the rest unchanged
7483
def update_app(self, app, config):
75-
url = self.host + "/api/apps/" + app + "/update"
84+
url = self.host + "/api/" + self.API_VERSION + "/apps/" + app + "/update"
7685
payload = json.dumps(config)
7786
headers = self.headers
7887
response = requests.request("PUT", url, data=payload, headers=headers, timeout=self.request_timeout)
79-
return response
88+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
89+
return filtered_response
8090

81-
# rolling restart an app, only requires the app name
82-
def roll_app(self, app):
83-
url = self.host + "/api/apps/" + app + "/roll"
91+
# prune unused images on all devices
92+
def prune_images(self):
93+
url = self.host + "/api/" + self.API_VERSION + "/prune"
8494
headers = self.headers
8595
response = requests.request("POST", url, headers=headers, timeout=self.request_timeout)
86-
return response
96+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
97+
return filtered_response
8798

88-
# prune unused images on all devices running app on them
89-
def prune_images(self, app):
90-
url = self.host + "/api/apps/" + app + "/prune"
99+
# prune unused images on all devices that are part of the device_group given
100+
def prune__device_group_images(self, device_groups):
101+
url = self.host + "/api/" + self.API_VERSION + "/device_groups/" + device_groups + "/prune"
91102
headers = self.headers
92103
response = requests.request("POST", url, headers=headers, timeout=self.request_timeout)
93-
return response
104+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
105+
return filtered_response
94106

95107
# check that the contacted api is responding as expected
96108
def check_api(self):
97-
url = self.host + "/api/status"
109+
url = self.host + "/api/" + self.API_VERSION + "/status"
98110
headers = self.headers
99111
response = requests.request("GET", url, headers=headers, timeout=self.request_timeout)
100-
return response
112+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
113+
return filtered_response
114+
115+
# list the info of all apps and all data of a given device_group
116+
def list_device_group_info(self, device_group):
117+
url = self.host + "/api/" + self.API_VERSION + "/device_groups/" + device_group + "/info"
118+
headers = self.headers
119+
response = requests.request("GET", url, headers=headers, timeout=self.request_timeout)
120+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
121+
return filtered_response
122+
123+
# list all device_groups
124+
def list_device_groups(self):
125+
url = self.host + "/api/" + self.API_VERSION + "/device_groups"
126+
headers = self.headers
127+
response = requests.request("GET", url, headers=headers, timeout=self.request_timeout)
128+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
129+
return filtered_response
130+
131+
# list device_group configuration
132+
def list_device_group(self, device_group):
133+
url = self.host + "/api/" + self.API_VERSION + "/device_groups/" + device_group
134+
headers = self.headers
135+
response = requests.request("GET", url, headers=headers, timeout=self.request_timeout)
136+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
137+
return filtered_response
138+
139+
# create a new nebula delete_device_group, requires the app name to create and a complete dict of the config values
140+
# for it
141+
def create_device_group(self, device_group, config):
142+
url = self.host + "/api/" + self.API_VERSION + "/device_groups/" + device_group
143+
payload = json.dumps(config)
144+
headers = self.headers
145+
response = requests.request("POST", url, data=payload, headers=headers, timeout=self.request_timeout)
146+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
147+
return filtered_response
148+
149+
# delete an existing nebula delete_device_group, no confirmation required in SDK so be careful
150+
def delete_device_group(self, device_group):
151+
url = self.host + "/api/" + self.API_VERSION + "/device_groups/" + device_group
152+
headers = self.headers
153+
response = requests.request("DELETE", url, headers=headers, timeout=self.request_timeout)
154+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
155+
return filtered_response
156+
157+
# update apps in a device group
158+
def update_device_group(self, device_group, config):
159+
url = self.host + "/api/" + self.API_VERSION + "/device_groups/" + device_group + "/update"
160+
payload = json.dumps(config)
161+
headers = self.headers
162+
response = requests.request("POST", url, data=payload, headers=headers, timeout=self.request_timeout)
163+
filtered_response = {"status_code": response.status_code, "reply": response.json()}
164+
return filtered_response

README.md

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ An SDK for managing [nebula](https://nebula-orchestrator.github.io/) via python.
33

44
translates all of Nebula [API](http://nebula.readthedocs.io/en/latest/api/) calls to something more pythonic.
55

6+
Source code is available at [github](https://github.com/nebula-orchestrator/nebula-python-sdk)
7+
68
# How To Use
79
first get NebulaPythonSDK onto your machine
810
```bash
@@ -35,6 +37,7 @@ app_conf = {
3537
"docker_ulimits": [],
3638
"networks": ["nebula"],
3739
"running": True,
40+
"rolling_restart": False,
3841
"volumes": ["/tmp:/tmp/1", "/var/tmp/:/var/tmp/1:ro"],
3942
"containers_per": {
4043
"cpu": 6
@@ -50,6 +53,44 @@ app_conf = {
5053
}
5154
connection.create_app("app_name", app_conf)
5255

53-
```
56+
# create device group
57+
device_group_config = {"apps": ["app_name"]}
58+
connection.create_device_group("device_group_name", device_group_config)
59+
60+
# list device group
61+
connection.list_device_group("device_group_name")
62+
63+
# list device group info
64+
connection.list_device_group_info("device_group_name")
65+
66+
# ping api
67+
connection.check_api()
68+
69+
# delete app
70+
connection.delete_app("app_name")
71+
72+
# stop app
73+
connection.stop_app("app_name")
74+
75+
# start app
76+
connection.start_app("app_name")
5477

55-
Note that the response returned is a requests formatted response.
78+
# restart app
79+
connection.restart_app("app_name")
80+
81+
# update app
82+
connection.update_app("app_name", app_conf)
83+
84+
# prune images on all device groups
85+
connection.prune_images()
86+
87+
# delete device_group
88+
connection.delete_device_group("device_group_name")
89+
90+
# prune images on a selected device groups
91+
connection.prune__device_group_images("device_group_name")
92+
93+
# update device group
94+
connection.update_device_group("device_group_name", device_group_config)
95+
96+
```

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
__author__ = 'Naor Livne'
22
__author_email__ = 'naorlivne@gmail.com'
3-
__version__ = '1.6.0'
3+
__version__ = '2.0.0a1'
44

55
from setuptools import setup, find_packages
66

test/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)