Skip to content

Commit a3f1513

Browse files
committed
use cloud-init for templates, add ssh key for cloud-init, delete expire before vm creation
1 parent dd876a8 commit a3f1513

File tree

12 files changed

+55
-88
lines changed

12 files changed

+55
-88
lines changed

proxstar/__init__.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ def create():
410410
template = request.form['template']
411411
disk = request.form['disk']
412412
iso = request.form['iso']
413+
ssh_key = request.form['ssh_key']
413414
if iso != 'none':
414415
iso = "{}:iso/{}".format(app.config['PROXMOX_ISO_STORAGE'],
415416
iso)
@@ -438,17 +439,16 @@ def create():
438439
iso,
439440
timeout=300)
440441
else:
441-
password = gen_password(16)
442442
q.enqueue(
443443
setup_template_task,
444444
template,
445445
name,
446446
username,
447-
password,
447+
ssh_key,
448448
cores,
449449
memory,
450450
timeout=600)
451-
return password, 200
451+
return '', 200
452452
return '', 200
453453
else:
454454
return '', 403
@@ -557,10 +557,8 @@ def template_disk(template_id):
557557
def template_edit(template_id):
558558
if 'rtp' in session['userinfo']['groups']:
559559
name = request.form['name']
560-
username = request.form['username']
561-
password = request.form['password']
562560
disk = request.form['disk']
563-
set_template_info(db, template_id, name, username, password, disk)
561+
set_template_info(db, template_id, name, disk)
564562
return '', 200
565563
else:
566564
return '', 403
@@ -584,4 +582,4 @@ def exit_handler():
584582
atexit.register(exit_handler)
585583

586584
if __name__ == "__main__":
587-
app.run()
585+
app.run(threaded=False)

proxstar/db.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,6 @@ def get_templates(db):
145145
template_dict = dict()
146146
template_dict['id'] = template.id
147147
template_dict['name'] = template.name
148-
template_dict['username'] = template.username
149-
template_dict['password'] = template.password
150148
template_dict['disk'] = template.disk
151149
templates.append(template_dict)
152150
return templates
@@ -158,8 +156,6 @@ def get_template(db, template_id):
158156
template = db.query(Template).filter(Template.id == template_id).one()
159157
template_dict['id'] = template.id
160158
template_dict['name'] = template.name
161-
template_dict['username'] = template.username
162-
template_dict['password'] = template.password
163159
template_dict['disk'] = template.disk
164160
return template_dict
165161

@@ -194,13 +190,10 @@ def delete_allowed_user(db, user):
194190
db.commit()
195191

196192

197-
def set_template_info(db, template_id, name, username, password, disk):
193+
def set_template_info(db, template_id, name, disk):
198194
if db.query(exists().where(Template.id == template_id, )).scalar():
199195
template = db.query(Template).filter(Template.id == template_id,
200196
).one()
201197
template.name = name
202-
template.username = username
203-
if password:
204-
template.password = password
205198
template.disk = disk
206199
db.commit()

proxstar/models.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ class Template(Base):
3434
__tablename__ = 'template'
3535
id = Column(Integer, primary_key=True)
3636
name = Column(String(32), nullable=False)
37-
username = Column(Text, nullable=False)
38-
password = Column(Text, nullable=False)
3937
disk = Column(Integer, nullable=False)
4038

4139

proxstar/proxmox.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ def connect_proxmox():
1010
proxmox = ProxmoxAPI(
1111
host,
1212
user=app.config['PROXMOX_USER'],
13-
password=app.config['PROXMOX_PASS'],
14-
verify_ssl=False)
13+
private_key_file='proxmox_ssh_key',
14+
password=app.config['PROXMOX_SSH_KEY_PASS'],
15+
backend='ssh_paramiko')
1516
version = proxmox.version.get()
1617
return proxmox
1718
except:

proxstar/static/css/styles.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,7 @@ table, th, td {
129129
.swal-button--ok {
130130
background-color: #4caf50;
131131
}
132+
133+
#show-for-template {
134+
display: none
135+
}

proxstar/static/js/script.js

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ $("#create-vm").click(function(){
390390
const cores = document.getElementById('cores').value;
391391
const mem = document.getElementById('mem').value;
392392
const template = document.getElementById('template').value;
393+
const ssh_key = document.getElementById('ssh-key').value;
393394
const iso = document.getElementById('iso').value;
394395
const user = document.getElementById('user');
395396
const max_cpu = $(this).data('max_cpu');
@@ -451,6 +452,7 @@ $("#create-vm").click(function(){
451452
data.append('template', template);
452453
data.append('disk', disk);
453454
data.append('iso', iso);
455+
data.append('ssh_key', ssh_key);
454456
if (user) {
455457
data.append('user', user.value);
456458
}
@@ -459,12 +461,10 @@ $("#create-vm").click(function(){
459461
method: 'post',
460462
body: data
461463
}).then((response) => {
462-
return response.text()
463-
}).then((password) => {
464464
if (template == 'none') {
465465
var swal_text = `${name} is now being created. Check back soon and it should be good to go.`
466466
} else {
467-
var swal_text = `${name} is now being created. Check back soon and it should be good to go. The SSH credentials are your CSH username for the user and ${password} for the password. Save this password because you will not be able to retrieve it again!`
467+
var swal_text = `${name} is now being created. Check back soon and it should be good to go. The SSH credentials are your CSH username for the user and the SSH key you provided.`
468468
}
469469
return swal(`${swal_text}`, {
470470
icon: "success",
@@ -753,16 +753,19 @@ $(".add-ignored-pool").click(function(){
753753
});
754754
});
755755

756-
function hide_for_template(obj) {
756+
function change_for_template(obj) {
757757
var template_element = obj;
758758
var selected = template_element.options[template_element.selectedIndex].value;
759759
var hide_area = document.getElementById('hide-for-template');
760+
var show_area = document.getElementById('show-for-template');
760761

761-
if(selected === 'none'){
762+
if (selected === 'none') {
762763
hide_area.style.display = 'block';
764+
show_area.style.display = 'none';
763765
}
764-
else{
766+
else {
765767
hide_area.style.display = 'none';
768+
show_area.style.display = 'block';
766769
}
767770
}
768771

@@ -869,7 +872,6 @@ $(".resize-disk").click(function(){
869872
$(".edit-template").click(function(){
870873
const template_id = $(this).data('template_id');
871874
const template_name = $(this).data('template_name');
872-
const template_username = $(this).data('template_username');
873875
const template_disk = $(this).data('template_disk');
874876
var options = document.createElement('div');
875877
name_text = document.createElement('p');
@@ -878,18 +880,6 @@ $(".edit-template").click(function(){
878880
var name = document.createElement('input');
879881
name.defaultValue = template_name;
880882
options.append(name);
881-
username_text = document.createElement('p');
882-
username_text.innerHTML = 'Username';
883-
options.append(username_text);
884-
var username = document.createElement('input');
885-
username.defaultValue = template_username;
886-
options.append(username);
887-
password_text = document.createElement('p');
888-
password_text.innerHTML = 'Password';
889-
options.append(password_text);
890-
var password = document.createElement('input');
891-
password.type = 'password';
892-
options.append(password);
893883
disk_text = document.createElement('p');
894884
disk_text.innerHTML = 'Disk Size (GB)';
895885
options.append(disk_text);
@@ -917,8 +907,6 @@ $(".edit-template").click(function(){
917907
if (willChange) {
918908
var data = new FormData();
919909
data.append('name', $(name).val());
920-
data.append('username', $(username).val());
921-
data.append('password', $(password).val());
922910
data.append('disk', $(disk).val());
923911
fetch(`/template/${template_id}/edit`, {
924912
credentials: 'same-origin',

proxstar/tasks.py

Lines changed: 7 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def create_vm_task(user, name, cores, memory, disk, iso):
5858
get_next_ip(starrs, app.config['STARRS_IP_RANGE']))
5959
job.meta['status'] = 'setting VM expiration'
6060
job.save_meta()
61+
delete_vm_expire(db, vmid)
6162
get_vm_expire(db, vmid, app.config['VM_EXPIRE_MONTHS'])
6263
job.meta['status'] = 'complete'
6364
job.save_meta()
@@ -114,7 +115,7 @@ def generate_pool_cache_task():
114115
store_pool_cache(db, pools)
115116

116117

117-
def setup_template_task(template_id, name, user, password, cores, memory):
118+
def setup_template_task(template_id, name, user, ssh_key, cores, memory):
118119
with app.app_context():
119120
job = get_current_job()
120121
proxmox = connect_proxmox()
@@ -139,6 +140,11 @@ def setup_template_task(template_id, name, user, password, cores, memory):
139140
vm = VM(vmid)
140141
vm.set_cpu(cores)
141142
vm.set_mem(memory)
143+
print("[{}] Applying cloud-init config.".format(name))
144+
job.meta['status'] = 'applying cloud-init'
145+
vm.set_ci_user(user)
146+
vm.set_ci_ssh_key(ssh_key)
147+
vm.set_ci_network()
142148
print(
143149
"[{}] Waiting for STARRS to propogate before starting VM.".format(
144150
name))
@@ -149,46 +155,6 @@ def setup_template_task(template_id, name, user, password, cores, memory):
149155
job.meta['status'] = 'starting VM'
150156
job.save_meta()
151157
vm.start()
152-
print("[{}] Waiting for VM to start before SSHing.".format(name))
153-
job.meta['status'] = 'waiting for VM to start'
154-
job.save_meta()
155-
time.sleep(20)
156-
print("[{}] Creating SSH session.".format(name))
157-
job.meta['status'] = 'creating SSH session'
158-
job.save_meta()
159-
client = paramiko.SSHClient()
160-
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
161-
retry = 0
162-
while retry < 30:
163-
try:
164-
client.connect(
165-
ip,
166-
username=template['username'],
167-
password=template['password'])
168-
break
169-
except:
170-
retry += 1
171-
time.sleep(3)
172-
print("[{}] Running user creation commands.".format(name))
173-
job.meta['status'] = 'running user creation commands'
174-
job.save_meta()
175-
stdin, stdout, stderr = client.exec_command("useradd {}".format(user))
176-
exit_status = stdout.channel.recv_exit_status()
177-
root_password = gen_password(32)
178-
stdin, stdout, stderr = client.exec_command(
179-
"echo '{}' | passwd root --stdin".format(root_password))
180-
exit_status = stdout.channel.recv_exit_status()
181-
stdin, stdout, stderr = client.exec_command(
182-
"echo '{}' | passwd '{}' --stdin".format(password, user))
183-
exit_status = stdout.channel.recv_exit_status()
184-
stdin, stdout, stderr = client.exec_command(
185-
"passwd -e '{}'".format(user))
186-
exit_status = stdout.channel.recv_exit_status()
187-
stdin, stdout, stderr = client.exec_command(
188-
"echo '{} ALL=(ALL:ALL) ALL' | sudo EDITOR='tee -a' visudo".format(
189-
user))
190-
exit_status = stdout.channel.recv_exit_status()
191-
client.close()
192158
print("[{}] Template successfully provisioned.".format(name))
193159
job.meta['status'] = 'completed'
194160
job.save_meta()

proxstar/templates/create.html

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ <h3 class="card-title">Create VM</h3>
3939
</div>
4040
<div class="form-group">
4141
<label for="template" class="pull-left">Template</label>
42-
<select name="template" id="template" class="form-control" onchange="hide_for_template(this)">
43-
<option value="none"></option>
42+
<select name="template" id="template" class="form-control" onchange="change_for_template(this)">
43+
<option value="none">None</option>
4444
{% for template in templates %}
4545
<option value="{{ template['id'] }}">{{ template['name'] }} ({{ template['disk'] }}GB)</option>
4646
{% endfor %}
@@ -61,6 +61,12 @@ <h3 class="card-title">Create VM</h3>
6161
</select>
6262
</div>
6363
</div>
64+
<div id="show-for-template">
65+
<div class="form-group">
66+
<label for="ssh-key" class="pull-left">Public SSH Key</label>
67+
<input type="text" name="ssh-key" id="ssh-key" class="form-control">
68+
</div>
69+
</div>
6470
{% if user['rtp'] %}
6571
<div class="form-group">
6672
<label for="user" class="pull-left">User</label>

proxstar/templates/settings.html

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ <h3 class="panel-title">Templates</h3>
1414
<tr role="row">
1515
<th>Proxmox ID</th>
1616
<th>Name</th>
17-
<th>Username</th>
1817
<th>Disk Size (GB)</th>
1918
<th>Delete</th>
2019
</tr>
@@ -24,10 +23,9 @@ <h3 class="panel-title">Templates</h3>
2423
<tr role="row">
2524
<td>{{ template['id'] }}</td>
2625
<td>{{ template['name'] }}</td>
27-
<td>{{ template['username'] }}</td>
2826
<td>{{ template['disk'] }}</td>
2927
<td>
30-
<button class="btn btn-sm btn-info edit-template" data-template_id="{{ template['id'] }}" data-template_name="{{ template['name'] }}" data-template_username="{{ template['username'] }}" data-template_disk="{{ template['disk'] }}">
28+
<button class="btn btn-sm btn-info edit-template" data-template_id="{{ template['id'] }}" data-template_name="{{ template['name'] }}" data-template_disk="{{ template['disk'] }}">
3129
<i class="fas fa-edit"></i>
3230
</button>
3331
<button class="btn btn-sm btn-danger delete-template" data-template_id="{{ template['id'] }}">

proxstar/vm.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import time
22
import json
3+
import urllib
34
from proxstar import db, starrs
45
from proxstar.db import get_vm_expire
56
from proxstar.util import lazy_property
@@ -202,6 +203,19 @@ def resize_disk(self, disk, size):
202203
def expire(self):
203204
return get_vm_expire(db, self.id, app.config['VM_EXPIRE_MONTHS'])
204205

206+
def set_ci_user(self, user):
207+
proxmox = connect_proxmox()
208+
proxmox.nodes(self.node).qemu(self.id).config.put(ciuser=user)
209+
210+
def set_ci_ssh_key(self, ssh_key):
211+
proxmox = connect_proxmox()
212+
escaped_key = urllib.parse.quote(ssh_key, safe='')
213+
proxmox.nodes(self.node).qemu(self.id).config.put(sshkey=escaped_key)
214+
215+
def set_ci_network(self):
216+
proxmox = connect_proxmox()
217+
proxmox.nodes(self.node).qemu(self.id).config.put(ipconfig0='ip=dhcp')
218+
205219

206220
def create_vm(proxmox, user, name, cores, memory, disk, iso):
207221
node = proxmox.nodes(get_node_least_mem(proxmox))
@@ -237,7 +251,7 @@ def clone_vm(proxmox, template_id, name, pool):
237251
name=name,
238252
pool=pool,
239253
full=1,
240-
description='Managed by Proxstar',
254+
description='Managed\ by\ Proxstar',
241255
target=target)
242256
retry = 0
243257
while retry < 60:

0 commit comments

Comments
 (0)