Skip to content

Commit 3c6d0da

Browse files
committed
Added Azure provider
1 parent 9b6d3b4 commit 3c6d0da

File tree

3 files changed

+146
-1
lines changed

3 files changed

+146
-1
lines changed

app/server.py

+48
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@
3232
except ImportError:
3333
HAS_GOOGLE_LIBRARIES = False
3434

35+
try:
36+
from azure.mgmt.automation import AutomationClient
37+
import azure.mgmt.automation.models as AutomationModel
38+
39+
HAS_AZURE_LIBRARIES = True
40+
except ImportError:
41+
HAS_AZURE_LIBRARIES = False
42+
3543
routes = web.RouteTableDef()
3644
PROJECT_ROOT = dirname(dirname(__file__))
3745
pool = None
@@ -253,6 +261,46 @@ async def check_scaleway_config(_):
253261
return web.json_response({"has_secret": 'SCW_TOKEN' in os.environ})
254262

255263

264+
@routes.get('/hetzner_config')
265+
async def check_hetzner_config(_):
266+
return web.json_response({"has_secret": 'HCLOUD_TOKEN' in os.environ})
267+
268+
269+
@routes.post('/hetzner_regions')
270+
async def hetzner_regions(request):
271+
data = await request.json()
272+
token = data.get('token', os.environ.get('HCLOUD_TOKEN'))
273+
if not token:
274+
return web.json_response({'error': 'no token provided'}, status=400)
275+
276+
headers = {
277+
'Content-Type': 'application/json',
278+
'Authorization': 'Bearer {0}'.format(token),
279+
}
280+
async with ClientSession(headers=headers) as session:
281+
async with session.get('https://api.hetzner.cloud/v1/datacenters') as r:
282+
json_body = await r.json()
283+
return web.json_response(json_body)
284+
285+
286+
@routes.get('/azure_config')
287+
async def azure_config(_):
288+
if not HAS_REQUESTS:
289+
return web.json_response({'error': 'missing_requests'}, status=400)
290+
if not HAS_AZURE_LIBRARIES:
291+
return web.json_response({'error': 'missing_azure'}, status=400)
292+
response = {'status': 'ok'}
293+
return web.json_response(response)
294+
295+
296+
@routes.get('/azure_regions')
297+
async def azure_regions(_):
298+
with open(join(PROJECT_ROOT, 'roles', 'cloud-azure', 'defaults', 'main.yml'), 'r') as f:
299+
regions_json = yaml.safe_load(f.read())
300+
regions = json.loads(regions_json['_azure_regions'])
301+
return web.json_response(regions)
302+
303+
256304
app = web.Application()
257305
app.router.add_routes(routes)
258306
app.add_routes([web.static('/static', join(PROJECT_ROOT, 'app', 'static'))])

app/static/provider-azure.vue

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<template>
2+
<div>
3+
<div v-if="ui_config_error && ui_config_error === 'missing_requests'" class="form-text alert alert-danger" role="alert">
4+
Python module "requests" is missing, please install it to proceed
5+
</div>
6+
<div v-if="ui_config_error && ui_config_error === 'missing_azure'" class="form-text alert alert-danger" role="alert">
7+
Python Azure SDK libraries are missing, please install it to proceed
8+
</div>
9+
<div class="form-text alert alert-info" role="alert">
10+
<strong>Prerequisites:</strong> <a href="https://github.com/trailofbits/algo/blob/master/docs/cloud-azure.md"
11+
target="_blank" rel="noopener noreferrer">Install azure-cli</a>
12+
</div>
13+
<region-select v-model="region"
14+
v-bind:options="ui_region_options"
15+
v-bind:loading="ui_loading_check || ui_loading_regions"
16+
v-bind:error="ui_region_error">
17+
</region-select>
18+
<button v-on:click="submit"
19+
v-bind:disabled="!is_valid" class="btn btn-primary" type="button">Next
20+
</button>
21+
</div>
22+
</template>
23+
24+
<script>
25+
module.exports = {
26+
data: function () {
27+
return {
28+
region: null,
29+
// helper variables
30+
ui_loading_check: false,
31+
ui_config_error: false,
32+
ui_loading_regions: false,
33+
ui_region_error: null,
34+
ui_region_options: []
35+
}
36+
},
37+
computed: {
38+
is_valid() {
39+
return !!this.region;
40+
}
41+
},
42+
created: function () {
43+
this.check_config();
44+
},
45+
methods: {
46+
check_config() {
47+
this.ui_loading_check = true;
48+
fetch("/azure_config")
49+
.then(r => {
50+
if (r.status === 200 || r.status === 400) {
51+
return r.json();
52+
}
53+
throw new Error(r.status);
54+
})
55+
.then(response => {
56+
if (response.status === 'ok') {
57+
this.load_regions();
58+
} else if (response.error) {
59+
this.ui_config_error = response.error;
60+
}
61+
})
62+
.finally(() => {
63+
this.ui_loading_check = false;
64+
});
65+
},
66+
load_regions() {
67+
this.ui_loading_regions = true;
68+
this.ui_region_error = null;
69+
fetch("/azure_regions")
70+
.then((r) => {
71+
if (r.status === 200) {
72+
return r.json();
73+
}
74+
throw new Error(r.status);
75+
})
76+
.then((data) => {
77+
this.ui_region_options = data.map(i => ({key: i.name, value: i.displayName}));
78+
})
79+
.catch((err) => {
80+
this.ui_region_error = err;
81+
})
82+
.finally(() => {
83+
this.ui_loading_regions = false;
84+
});
85+
},
86+
submit() {
87+
this.$emit("submit", {
88+
region: this.region
89+
});
90+
}
91+
},
92+
components: {
93+
"region-select": window.httpVueLoader("/static/region-select.vue"),
94+
}
95+
};
96+
</script>

app/static/provider-setup.vue

+2-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ module.exports = {
6363
'gce': window.httpVueLoader('/static/provider-gce.vue'),
6464
'vultr': window.httpVueLoader('/static/provider-vultr.vue'),
6565
'scaleway': window.httpVueLoader('/static/provider-scaleway.vue'),
66-
'hetzner': window.httpVueLoader('/static/provider-hetzner.vue')
66+
'hetzner': window.httpVueLoader('/static/provider-hetzner.vue'),
67+
'azure': window.httpVueLoader('/static/provider-azure.vue')
6768
}
6869
};
6970
</script>

0 commit comments

Comments
 (0)