Commit 7add9280 by Heechul Kim

added ipmi power off/on

parent 017ec2e3
...@@ -242,13 +242,13 @@ def provision_machine(name): ...@@ -242,13 +242,13 @@ def provision_machine(name):
# clean up dpt_file # clean up dpt_file
try: try:
os.unlink(dpt_file) os.remove(dpt_file)
except Exception as e: except Exception as e:
log.warn(e) log.warn(e)
# clean up svc_iface_file if exists. # clean up svc_iface_file if exists.
if svc_iface_file: if svc_iface_file:
try: try:
os.unlink(svc_iface_file) os.remove(svc_iface_file)
except Exception as e: except Exception as e:
log.warn(e) log.warn(e)
...@@ -341,14 +341,14 @@ def delete_machine(name): ...@@ -341,14 +341,14 @@ def delete_machine(name):
s_mac = '01-' + d['mac'].replace(':', '-') s_mac = '01-' + d['mac'].replace(':', '-')
s_pxelinuxcfg = "{}/{}".format(PXELINUXCFG, s_mac) s_pxelinuxcfg = "{}/{}".format(PXELINUXCFG, s_mac)
try: try:
os.unlink(s_pxelinuxcfg) os.remove(s_pxelinuxcfg)
except Exception as e: except Exception as e:
log.warn(e) log.warn(e)
# delete tarball # delete tarball
s_tarball = "{}/{}.tar".format(TFTP_FAI_DIR, name) s_tarball = "{}/{}.tar".format(TFTP_FAI_DIR, name)
try: try:
os.unlink(s_tarball) os.remove(s_tarball)
except Exception as e: except Exception as e:
log.warn(e) log.warn(e)
...@@ -442,7 +442,7 @@ def install_machine(data): ...@@ -442,7 +442,7 @@ def install_machine(data):
log.info('IPMI power cycle is succeeded: {}'.format(l_out)) log.info('IPMI power cycle is succeeded: {}'.format(l_out))
# delete s_tmp # delete s_tmp
os.unlink(s_tmp) os.remove(s_tmp)
return (True, s_date) return (True, s_date)
...@@ -530,3 +530,66 @@ def dpt_machine(): ...@@ -530,3 +530,66 @@ def dpt_machine():
return l_dpt return l_dpt
def poweron_machine(name):
"""Power on machine using IPMI"""
# Get ipmi_ip of machine
s_rsc = '{}/machine/{}'.format(etcdc.prefix, name)
try:
r = etcdc.read(s_rsc)
except etcd.EtcdKeyNotFound as e:
log.error(e)
return (False, e)
d = ast.literal_eval(r.value)
ipmi_ip = d['ipmi_ip']
s_tmp = '/tmp/{}.pass'.format(name)
with open(s_tmp, 'w') as f:
f.write(IPMIPASS)
# power on
s_cmd = '{} -I lanplus -H {} -U {} -f {} chassis power on'\
.format(IPMITOOL, ipmi_ip, IPMIUSER, s_tmp)
log.debug(s_cmd)
(b_ret, l_out) = cmd(s_cmd)
if not b_ret:
s_msg = '{} power on is failed: {}'.format(name, l_out)
log.error(s_msg)
else:
s_msg = '{} power on is succeeded: {}'.format(name, l_out)
log.info(s_msg)
return (b_ret, s_msg)
def poweroff_machine(name):
"""Power off machine using IPMI"""
# Get ipmi_ip of machine
s_rsc = '{}/machine/{}'.format(etcdc.prefix, name)
try:
r = etcdc.read(s_rsc)
except etcd.EtcdKeyNotFound as e:
log.error(e)
return (False, e)
d = ast.literal_eval(r.value)
ipmi_ip = d['ipmi_ip']
s_tmp = '/tmp/{}.pass'.format(name)
with open(s_tmp, 'w') as f:
f.write(IPMIPASS)
# power on
s_cmd = '{} -I lanplus -H {} -U {} -f {} chassis power off'\
.format(IPMITOOL, ipmi_ip, IPMIUSER, s_tmp)
log.debug(s_cmd)
(b_ret, l_out) = cmd(s_cmd)
if not b_ret:
s_msg = '{} power on is failed: {}'.format(name, l_out)
log.error(s_msg)
else:
s_msg = '{} power on is succeeded: {}'.format(name, l_out)
log.info(s_msg)
# clean up pass tmp file
try:
os.remove(s_tmp)
except Exception as e:
log.warn(e)
return (b_ret, s_msg)
...@@ -27,6 +27,8 @@ from porch.api.machine.bizlogic import install_machine ...@@ -27,6 +27,8 @@ from porch.api.machine.bizlogic import install_machine
from porch.api.machine.bizlogic import show_console_machine from porch.api.machine.bizlogic import show_console_machine
from porch.api.machine.bizlogic import close_console_machine from porch.api.machine.bizlogic import close_console_machine
from porch.api.machine.bizlogic import dpt_machine from porch.api.machine.bizlogic import dpt_machine
from porch.api.machine.bizlogic import poweron_machine
from porch.api.machine.bizlogic import poweroff_machine
log = logging.getLogger('porch') log = logging.getLogger('porch')
...@@ -139,7 +141,7 @@ class MachineOS(Resource): ...@@ -139,7 +141,7 @@ class MachineOS(Resource):
return d_msg, i_ret_code return d_msg, i_ret_code
@ns.route('/<string:name>/console') @ns.route('/<string:name>/console')
@api.response(404, 'App not found.') @ns.response(404, 'Machine not found.')
class MachineConsole(Resource): class MachineConsole(Resource):
@jwt_required @jwt_required
...@@ -156,7 +158,7 @@ class MachineConsole(Resource): ...@@ -156,7 +158,7 @@ class MachineConsole(Resource):
return s_url return s_url
@ns.route('/<string:name>/console/close') @ns.route('/<string:name>/console/close')
@api.response(404, 'Pod not found.') @ns.response(404, 'Machine not found.')
class MachineConsoleClose(Resource): class MachineConsoleClose(Resource):
@jwt_required @jwt_required
...@@ -187,7 +189,7 @@ class MachineInstalled(Resource): ...@@ -187,7 +189,7 @@ class MachineInstalled(Resource):
return d_msg, i_ret_code return d_msg, i_ret_code
@ns.route('/dpt') @ns.route('/dpt')
@api.response(404, 'App not found.') @ns.response(404, 'Machine not found.')
class MachineDPT(Resource): class MachineDPT(Resource):
@jwt_required @jwt_required
...@@ -197,3 +199,40 @@ class MachineDPT(Resource): ...@@ -197,3 +199,40 @@ class MachineDPT(Resource):
l_dpt = list() l_dpt = list()
l_dpt = dpt_machine() l_dpt = dpt_machine()
return l_dpt return l_dpt
@ns.route('/<string:name>/poweron')
class MachinePowerOn(Resource):
@ns.response(200, 'Machine successfully powered on.')
@jwt_required
def post(self, name):
"""Power on a machine.
"""
i_ret_code = 200
(b_ret, s_msg) = poweron_machine(name)
if not b_ret:
d_msg = {'error': s_msg}
i_ret_code = 400
else:
d_msg = {'info': s_msg}
return d_msg, i_ret_code
@ns.route('/<string:name>/poweroff')
class MachinePowerOff(Resource):
@ns.response(200, 'Machine successfully powered off.')
@jwt_required
def post(self, name):
"""Power off a machine.
"""
i_ret_code = 200
(b_ret, s_msg) = poweroff_machine(name)
if not b_ret:
d_msg = {'error': s_msg}
i_ret_code = 400
else:
d_msg = {'info': s_msg}
return d_msg, i_ret_code
...@@ -54,11 +54,42 @@ ...@@ -54,11 +54,42 @@
<button <button
class="purple small circular" class="purple small circular"
v-if="cell.row.ipmi_ip" v-if="cell.row.ipmi_ip"
@click="showConsole(cell.row)"
> >
<i>computer</i> <i>eject</i>
<q-tooltip>서버 콘솔: {{ cell.row.name }}</q-tooltip> <q-tooltip>IPMI 기능: {{ cell.row.name }}</q-tooltip>
</button> <q-popover
ref="popover"
anchor="top left"
self="top right"
>
<div class="list">
<div class="item item-link item-delimiter">
<div
class="item-content"
@click="showConsole(cell.row), $refs.popover.close()"
>
<i>computer</i> 콘솔 보기
</div>
</div>
<div class="item item-link item-delimiter">
<div
class="item-content"
@click="powerOn(cell.row), $refs.popover.close()"
>
<i>play_circle_filled</i> 머신 켜기
</div>
</div>
<div class="item item-link item-delimiter">
<div
class="item-content"
@click="powerOff(cell.row), $refs.popover.close()"
>
<i>stop</i>머신 끄기
</div>
</div>
</div>
</q-popover>
</button>&nbsp;
</template> </template>
</q-data-table> </q-data-table>
<q-modal <q-modal
...@@ -224,6 +255,54 @@ export default { ...@@ -224,6 +255,54 @@ export default {
}, response => { }, response => {
}) })
}, },
powerOn: function (row) {
const token = this.$store.state.token
const headers = {
headers: {
'Authorization': `Bearer ${token}`
}
}
let url = API_URL + `/machine/${row.name}/poweron`
this.$http.post(url, {}, headers).then(response => {
Toast.create.positive(`서버 ${row.name} 켜기 성공`)
}, response => {
let err = response.status + ' ' + response.statusText + ' ' +
response.body
Toast.create.negative(err)
})
},
powerOff: function (row) {
let self = this
Dialog.create({
title: '확인',
message: `머신 ${row.name} 끄시겠습니까?`,
buttons: [
{ label: '아니오' },
{
label: '예',
handler () {
self.processPowerOff(row.name)
}
}
]
})
},
processPowerOff: function (name) {
const token = this.$store.state.token
const headers = {
headers: {
'Authorization': `Bearer ${token}`
}
}
let url = API_URL + `/machine/${name}/poweroff`
this.$http.post(url, {}, headers).then(response => {
Toast.create.positive(`서버 ${name} 끄기 성공`)
}, response => {
let err = response.status + ' ' + response.statusText + ' ' +
response.body
Toast.create.negative(err)
})
},
showConsole: function (row) { showConsole: function (row) {
const token = this.$store.state.token const token = this.$store.state.token
const headers = { const headers = {
...@@ -239,7 +318,7 @@ export default { ...@@ -239,7 +318,7 @@ export default {
this.$refs.consoleModal.open() this.$refs.consoleModal.open()
}, 500) }, 500)
}, response => { }, response => {
let err = `콘솔 생성 실패` let err = '콘솔 생성 실패'
Toast.create.negative({ Toast.create.negative({
html: err, html: err,
timeout: 5000 timeout: 5000
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment