Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Greenhost
Cloud API
Commits
f7dd7ce3
Unverified
Commit
f7dd7ce3
authored
Nov 29, 2019
by
Maarten de Waard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
copy improvements from openappstack/cosmos.py to this repo
parent
b9adfa6a
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
62 additions
and
51 deletions
+62
-51
greenhost_cloud/cosmos.py
greenhost_cloud/cosmos.py
+62
-51
No files found.
greenhost_cloud/cosmos.py
View file @
f7dd7ce3
...
...
@@ -14,6 +14,7 @@ import requests
from
tabulate
import
tabulate
from
pytz
import
timezone
# Helper functions
def
request_api
(
resource
:
str
,
request_type
:
str
=
'GET'
,
data
:
str
=
''
):
...
...
@@ -51,11 +52,9 @@ def request_api(resource: str, request_type: str = 'GET',
if
response
.
content
:
log
.
debug
(
'Response: %s
\n
'
,
response
.
json
())
return
json
.
loads
(
response
.
content
.
decode
(
'utf-8'
))
else
:
return
None
else
:
raise
requests
.
HTTPError
(
'WARNING: Got response code '
,
response
.
status_code
,
response
.
text
)
return
None
raise
requests
.
HTTPError
(
'WARNING: Got response code '
,
response
.
status_code
,
response
.
text
)
# API calls
...
...
@@ -92,7 +91,7 @@ def create_domain_record(domain: str, name: str, data: str,
return
response
[
'domain_record'
]
def
create_droplet
(
name
:
str
,
ssh_key_id
:
int
,
region
:
str
=
'ams1'
,
def
create_droplet
(
name
:
str
,
ssh_key_id
:
int
,
region
:
str
=
'ams1'
,
# pylint: disable=too-many-arguments
size
:
int
=
2048
,
disk
:
int
=
20
,
image
:
int
=
18
):
"""Create a droplet.
...
...
@@ -120,36 +119,37 @@ def create_droplet(name: str, ssh_key_id: int, region: str = 'ams1',
return
response
def
delete_domain_record
(
domain
:
str
,
id
:
int
):
def
delete_domain_record
(
domain
:
str
,
record_
id
:
int
):
"""Delete a domain record."""
log
.
info
(
'Deleting domain record %s'
,
id
)
response
=
request_api
(
'domains/{0}/records/{1}'
.
format
(
domain
,
id
),
log
.
info
(
'Deleting domain record %s'
,
record_
id
)
response
=
request_api
(
'domains/{0}/records/{1}'
.
format
(
domain
,
record_
id
),
'DELETE'
)
return
response
def
delete_domain_records_by_name
(
domain
:
str
,
name_regex
:
str
):
"""Delete all domain records in a given domain matching a regex.
r
"""Delete all domain records in a given domain matching a regex.
Examples:
delete_domain_records_by_name('openappstack.net', '^\*.ci-')
delete_domain_records_by_name('openappstack.net', '^ci-')
"""
all
=
get_domain_records_by_name
(
domain
,
name_regex
)
for
record
in
all
:
all
_records
=
get_domain_records_by_name
(
domain
,
name_regex
)
for
record
in
all
_records
:
delete_domain_record
(
domain
,
record
[
'id'
])
def
delete_droplet
(
id
:
int
):
def
delete_droplet
(
droplet_
id
:
int
):
"""Delete a droplet. Droplet needs to be stopped first."""
log
.
info
(
'Deleting %s'
,
id
)
response
=
request_api
(
'droplets/{0}'
.
format
(
id
),
'DELETE'
)
log
.
info
(
'Deleting %s'
,
droplet_
id
)
response
=
request_api
(
'droplets/{0}'
.
format
(
droplet_
id
),
'DELETE'
)
return
response
def
get_domain_record
(
domain
:
str
,
id
:
int
):
def
get_domain_record
(
domain
:
str
,
droplet_
id
:
int
):
"""Get details for given domain record."""
response
=
request_api
(
'domains/{0}/records/{1}'
.
format
(
domain
,
id
))
response
=
request_api
(
'domains/{0}/records/{1}'
.
format
(
domain
,
droplet_
id
))
return
response
[
'domain_record'
]
...
...
@@ -206,14 +206,15 @@ def get_droplets_by_name(name_regex: str):
get_droplets_by_name(name_regex='^ci\d+')
"""
all_droplets
=
get_droplets
()
log
.
debug
(
all_droplets
)
matching
=
[
droplet
for
droplet
in
all_droplets
if
re
.
match
(
'^ci+'
,
droplet
[
'name'
])]
if
re
.
match
(
name_regex
,
droplet
[
'name'
])]
return
matching
def
get_droplet
(
id
:
int
):
def
get_droplet
(
droplet_
id
:
int
):
"""Get information about specified droplet."""
response
=
request_api
(
'droplets/{0}'
.
format
(
id
))
response
=
request_api
(
'droplets/{0}'
.
format
(
droplet_
id
))
return
response
[
'droplet'
]
...
...
@@ -223,11 +224,13 @@ def list_domain_records(domain: str):
log
.
debug
(
json
.
dumps
(
records
,
sort_keys
=
True
,
indent
=
2
))
table_records
=
[[
record
[
'id'
],
record
[
'name'
],
record
[
'type'
],
record
[
'data'
]]
for
record
in
records
]
table_records
=
[
[
record
[
'id'
],
record
[
'name'
],
record
[
'type'
],
record
[
'data'
]
]
for
record
in
records
]
log
.
info
(
tabulate
(
table_records
,
headers
=
[
'ID'
,
'Name'
,
'Type'
,
'Data'
]))
headers
=
[
'ID'
,
'Name'
,
'Type'
,
'Data'
]))
def
list_droplets
():
...
...
@@ -249,79 +252,87 @@ def list_droplets():
headers
=
[
'ID'
,
'Name'
,
'IPv4'
,
'Status'
]))
def
shutdown_droplet
(
id
:
int
):
def
shutdown_droplet
(
droplet_
id
:
int
):
"""Shut down specified droplet (through a power_off call)."""
log
.
info
(
'Shutting down %s'
,
id
)
log
.
info
(
'Shutting down %s'
,
droplet_
id
)
data
=
{
"type"
:
"power_off"
}
response
=
request_api
(
'droplets/{0}/actions'
.
format
(
id
),
'POST'
,
data
)
response
=
request_api
(
'droplets/{0}/actions'
.
format
(
droplet_
id
),
'POST'
,
data
)
return
response
def
status_droplet
(
id
:
int
):
def
status_droplet
(
droplet_
id
:
int
):
"""Get status of specified droplet."""
response
=
get_droplet
(
id
)
response
=
get_droplet
(
droplet_
id
)
return
response
[
'status'
]
def
terminate_droplet
(
id
:
int
):
def
terminate_droplet
(
droplet_
id
:
int
):
"""Terminate a droplet by powering it down and deleting it."""
shutdown_droplet
(
id
)
wait_for_state
(
id
,
'stopped'
)
delete_droplet
(
id
)
shutdown_droplet
(
droplet_
id
)
wait_for_state
(
droplet_
id
,
'stopped'
)
delete_droplet
(
droplet_
id
)
def
terminate_droplets_by_name
(
name_regex
:
str
,
ndays
:
int
=
0
,
domain
:
str
=
'openappstack.net'
):
def
terminate_droplets_by_name
(
name_regex
:
str
,
ndays
:
int
=
0
,
domain
:
str
=
'openappstack.net'
):
r
"""
Terminate droplets matching a regex and for x days older than current day.
Droplets defined on the env variable NO_TERMINATE_DROPLETS will not be delated
Terminate droplets matching a regex and for x days older than current day.
Droplets defined on the env variable NO_TERMINATE_DROPLETS will not be
delated
Example how to terminate all CI instances:
terminate_old_droplets(name_regex='^ci\d+', ndays=5)
will match i.e 'ci1234' , 'ci1', with a creation time older than 5 days
"""
threshold_time
=
(
datetime
.
now
(
tz
=
timezone
(
'Europe/Stockholm'
))
-
timedelta
(
days
=
ndays
)).
strftime
(
"%Y-%m-%dT%H:%M:%S+00:00"
)
all
=
get_droplets
()
threshold_time
=
(
datetime
.
now
(
tz
=
timezone
(
'Europe/Stockholm'
))
-
timedelta
(
days
=
ndays
)).
\
strftime
(
"%Y-%m-%dT%H:%M:%S+00:00"
)
all_droplets
=
get_droplets
()
noterminate_droplets
=
[]
if
'NO_TERMINATE_DROPLETS'
in
os
.
environ
:
noterminate_droplets
=
os
.
environ
[
'NO_TERMINATE_DROPLETS'
].
split
(
','
)
for
droplet
in
all
:
for
droplet
in
all
_droplets
:
if
droplet
[
'name'
]
not
in
noterminate_droplets
:
if
re
.
match
(
name_regex
,
droplet
[
'name'
]):
if
droplet
[
'created_at'
]
<
threshold_time
:
delete_domain_records_by_name
(
domain
,
'^\*.'
+
droplet
[
'name'
])
delete_domain_records_by_name
(
domain
,
r
'^\*.'
+
droplet
[
'name'
])
delete_domain_records_by_name
(
domain
,
'^'
+
droplet
[
'name'
])
terminate_droplet
(
droplet
[
'id'
])
def
wait_for_ssh
(
ip
:
str
):
def
wait_for_ssh
(
droplet_ip
:
str
):
"""Wait for ssh to be reachable on port 22."""
log
.
info
(
'Waiting for ssh to become available on ip %s'
,
ip
)
log
.
info
(
'Waiting for ssh to become available on ip %s'
,
droplet_
ip
)
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
while
sock
.
connect_ex
((
ip
,
22
))
!=
0
:
while
sock
.
connect_ex
((
droplet_
ip
,
22
))
!=
0
:
sleep
(
1
)
log
.
info
(
'SSH became available on ip %s'
,
droplet_ip
)
def
wait_for_state
(
id
:
int
,
state
):
def
wait_for_state
(
droplet_
id
:
int
,
state
):
"""Wait for a droplet to reach a certain state."""
log
.
info
(
'Waiting for droplet %s to reach %s state...'
,
id
,
state
)
status
=
status_droplet
(
id
)
log
.
info
(
'Waiting for droplet %s to reach %s state...'
,
droplet_
id
,
state
)
status
=
status_droplet
(
droplet_
id
)
log
.
debug
(
status
)
while
status
!=
state
:
sleep
(
1
)
status
=
status_droplet
(
id
)
status
=
status_droplet
(
droplet_
id
)
# When called from from ipython, setup
# logging to console
try
:
__IPYTHON__
log
=
logging
.
getLogger
()
__IPYTHON__
# pylint: disable=pointless-statement
log
=
logging
.
getLogger
()
# pylint: disable=invalid-name
log
.
addHandler
(
logging
.
StreamHandler
())
log
.
setLevel
(
logging
.
INFO
)
except
NameError
:
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
# pylint: disable=invalid-name
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment