mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-20 10:50:08 +03:00
This reverts commit 952cecb74d8091f1e479a73edd9adfadcf730f3e.
This commit is contained in:
parent
1fe1e72c7e
commit
dbbce59527
@ -17,7 +17,7 @@
|
||||
const { Validator } = require('jsonschema')
|
||||
const { role, service, action } = require('server/routes/api/oneflow/schemas')
|
||||
const {
|
||||
oneFlowConnection,
|
||||
oneFlowConection,
|
||||
returnSchemaError,
|
||||
} = require('server/routes/api/oneflow/utils')
|
||||
const { defaults, httpCodes } = require('server/utils/constants')
|
||||
@ -91,13 +91,13 @@ const serviceTemplate = (
|
||||
if (params && params.id) {
|
||||
config.path = '/service_template/{0}'
|
||||
config.request = params.id
|
||||
oneFlowConnection(
|
||||
oneFlowConection(
|
||||
config,
|
||||
(data) => success(next, res, data),
|
||||
(data) => error(next, res, data)
|
||||
)
|
||||
} else {
|
||||
oneFlowConnection(
|
||||
oneFlowConection(
|
||||
config,
|
||||
(data) => success(next, res, data),
|
||||
(data) => error(next, res, data)
|
||||
@ -130,7 +130,7 @@ const serviceTemplateDelete = (
|
||||
password,
|
||||
request: params.id,
|
||||
}
|
||||
oneFlowConnection(
|
||||
oneFlowConection(
|
||||
config,
|
||||
(data) => success(next, res, data),
|
||||
(data) => error(next, res, data)
|
||||
@ -173,7 +173,7 @@ const serviceTemplateCreate = (
|
||||
password,
|
||||
post: template,
|
||||
}
|
||||
oneFlowConnection(
|
||||
oneFlowConection(
|
||||
config,
|
||||
(data) => success(next, res, data),
|
||||
(data) => error(next, res, data)
|
||||
@ -224,7 +224,7 @@ const serviceTemplateUpdate = (
|
||||
request: params.id,
|
||||
post: template,
|
||||
}
|
||||
oneFlowConnection(
|
||||
oneFlowConection(
|
||||
config,
|
||||
(data) => success(next, res, data),
|
||||
(data) => error(next, res, data)
|
||||
@ -275,7 +275,7 @@ const serviceTemplateAction = (
|
||||
request: params.id,
|
||||
post: template,
|
||||
}
|
||||
oneFlowConnection(
|
||||
oneFlowConection(
|
||||
config,
|
||||
(data) => success(next, res, data),
|
||||
(data) => error(next, res, data)
|
||||
|
@ -13,43 +13,32 @@
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
const btoa = require('btoa')
|
||||
const https = require('https')
|
||||
// eslint-disable-next-line node/no-deprecated-api
|
||||
const { parse } = require('url')
|
||||
|
||||
const { request: axios } = require('axios')
|
||||
|
||||
const { defaults, httpCodes } = require('server/utils/constants')
|
||||
const {
|
||||
httpResponse,
|
||||
executeCommand,
|
||||
executeCommandAsync,
|
||||
publish,
|
||||
getSunstoneAuth,
|
||||
} = require('server/utils/server')
|
||||
const {
|
||||
consoleParseToString,
|
||||
consoleParseToJSON,
|
||||
} = require('server/utils/opennebula')
|
||||
const { createTokenServerAdmin } = require('server/routes/api/auth/utils')
|
||||
const { Actions: ActionHost } = require('server/utils/constants/commands/host')
|
||||
const { Actions: ActionVM } = require('server/utils/constants/commands/vm')
|
||||
const {
|
||||
resourceFromData,
|
||||
resources,
|
||||
params: commandParams,
|
||||
} = require('server/routes/api/vcenter/command-flags')
|
||||
const { getSunstoneConfig } = require('server/utils/yml')
|
||||
|
||||
const {
|
||||
httpMethod,
|
||||
defaultEmptyFunction,
|
||||
defaultCommandVcenter,
|
||||
defaultRegexpStartJSON,
|
||||
defaultRegexpEndJSON,
|
||||
defaultRegexpSplitLine,
|
||||
} = defaults
|
||||
const { POST } = httpMethod
|
||||
|
||||
const { ok, internalServerError, badRequest, accepted } = httpCodes
|
||||
const { LIST, IMPORT } = resourceFromData
|
||||
const appConfig = getSunstoneConfig()
|
||||
@ -61,7 +50,6 @@ const regexExclude = [
|
||||
/^\u001b\[.*?m\u001b\[.*?m# vCenter.*/i,
|
||||
]
|
||||
const regexHeader = /^IMID,.*/i
|
||||
const regexGetVcenterId = /-(?<id>.*)_/s
|
||||
|
||||
const validObjects = Object.values(resources)
|
||||
|
||||
@ -385,194 +373,11 @@ const importVobject = (
|
||||
httpReturn(accepted)
|
||||
}
|
||||
|
||||
/**
|
||||
* Axios request.
|
||||
*
|
||||
* @param {object} params - Axios params
|
||||
* @param {Function} callback - Success Axios callback
|
||||
* @param {Function} error - Error Axios callback
|
||||
*/
|
||||
const request = (
|
||||
params = {},
|
||||
callback = defaultEmptyFunction,
|
||||
error = defaultEmptyFunction
|
||||
) => {
|
||||
const defaultsProperties = {
|
||||
method: POST,
|
||||
httpsAgent: new https.Agent({
|
||||
rejectUnauthorized: false,
|
||||
}),
|
||||
validateStatus: (status) => status,
|
||||
}
|
||||
axios({
|
||||
...defaultsProperties,
|
||||
...params,
|
||||
})
|
||||
.then((response) => {
|
||||
if (response && response.statusText) {
|
||||
if (response.status >= 200 && response.status < 400) {
|
||||
if (response.data) {
|
||||
return response.data
|
||||
}
|
||||
}
|
||||
throw Error(response.data)
|
||||
} else if (response.data) {
|
||||
throw Error(response.data)
|
||||
}
|
||||
})
|
||||
.then((data) => {
|
||||
callback(data)
|
||||
})
|
||||
.catch((e) => {
|
||||
error(e)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get system config.
|
||||
*
|
||||
* @param {object} res - http response
|
||||
* @param {Function} next - express stepper
|
||||
* @param {object} params - params of http request
|
||||
* @param {object} userData - user of http request
|
||||
* @param {function(string, string): Function} oneConnection - One Connection
|
||||
*/
|
||||
const getToken = (
|
||||
res = {},
|
||||
next = defaultEmptyFunction,
|
||||
params = {},
|
||||
userData = {},
|
||||
oneConnection = defaultEmptyFunction
|
||||
) => {
|
||||
const { username, key, iv } = getSunstoneAuth()
|
||||
const { id } = params
|
||||
const responser = (code = badRequest, data = '') => {
|
||||
res.locals.httpCode = httpResponse(code, data, '')
|
||||
next()
|
||||
}
|
||||
|
||||
if (!(username && key && iv) || !Number.isInteger(parseInt(id, 10))) {
|
||||
responser()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const tokenWithServerAdmin = createTokenServerAdmin({
|
||||
serverAdmin: username,
|
||||
username,
|
||||
key,
|
||||
iv,
|
||||
})
|
||||
if (!tokenWithServerAdmin.token) {
|
||||
responser()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const connect = oneConnection(
|
||||
`${username}:${username}`,
|
||||
tokenWithServerAdmin.token
|
||||
)
|
||||
|
||||
connect(ActionVM.VM_INFO, [parseInt(id, 10), true], (err, vminfo) => {
|
||||
if (
|
||||
!(
|
||||
vminfo &&
|
||||
vminfo.VM &&
|
||||
vminfo.VM.DEPLOY_ID &&
|
||||
vminfo.VM.HISTORY_RECORDS &&
|
||||
vminfo.VM.HISTORY_RECORDS.HISTORY
|
||||
) ||
|
||||
err
|
||||
) {
|
||||
responser(internalServerError)
|
||||
}
|
||||
|
||||
const history = vminfo.VM.HISTORY_RECORDS.HISTORY
|
||||
const arrayHistory = Array.isArray(history) ? history : [history]
|
||||
|
||||
const hostID = parseInt(
|
||||
arrayHistory.reduce(
|
||||
(max, record) => (record.SEQ > max.SEQ ? record : max),
|
||||
arrayHistory[0]
|
||||
).HID,
|
||||
10
|
||||
)
|
||||
|
||||
const vmid = vminfo.VM.DEPLOY_ID.match(regexGetVcenterId).groups.id
|
||||
|
||||
connect(ActionHost.HOST_INFO, [hostID, true], (err, hostinfo) => {
|
||||
if (
|
||||
!(
|
||||
hostinfo &&
|
||||
hostinfo.HOST &&
|
||||
hostinfo.HOST.TEMPLATE &&
|
||||
hostinfo.HOST.TEMPLATE.VCENTER_HOST &&
|
||||
hostinfo.HOST.TEMPLATE.VCENTER_USER &&
|
||||
hostinfo.HOST.TEMPLATE.VCENTER_PASSWORD
|
||||
) ||
|
||||
err
|
||||
) {
|
||||
responser(internalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const { VCENTER_HOST, VCENTER_USER, VCENTER_PASSWORD } =
|
||||
hostinfo.HOST.TEMPLATE
|
||||
|
||||
const responseInternalServer = () => {
|
||||
responser(internalServerError)
|
||||
}
|
||||
|
||||
const genToken = (data) => {
|
||||
request(
|
||||
{
|
||||
url: `https://${VCENTER_HOST}/api/vcenter/vm/vm-${vmid}/console/tickets`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'vmware-api-session-id': data,
|
||||
},
|
||||
data: JSON.stringify({ type: 'WEBMKS' }),
|
||||
},
|
||||
(success) => {
|
||||
const { ticket } = success
|
||||
const { protocol, hostname, port, path } = parse(ticket)
|
||||
|
||||
const httpProtocol = protocol === 'wss:' ? 'https' : 'http'
|
||||
const esxUrl = `${httpProtocol}://${hostname}:${port}`
|
||||
const token = path.replace('/ticket/', '')
|
||||
global.vcenterToken = { [token]: esxUrl }
|
||||
responser(ok, {
|
||||
ticket: token,
|
||||
})
|
||||
},
|
||||
responseInternalServer
|
||||
)
|
||||
}
|
||||
|
||||
request(
|
||||
{
|
||||
url: `https://${VCENTER_HOST}/api/session`,
|
||||
headers: {
|
||||
Authorization: `Basic ${btoa(
|
||||
`${VCENTER_USER}:${VCENTER_PASSWORD}`
|
||||
)}`,
|
||||
},
|
||||
},
|
||||
genToken,
|
||||
responseInternalServer
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const functionRoutes = {
|
||||
list,
|
||||
listAll,
|
||||
cleartags,
|
||||
importHost,
|
||||
importVobject,
|
||||
getToken,
|
||||
}
|
||||
module.exports = functionRoutes
|
||||
|
@ -21,14 +21,12 @@ const {
|
||||
listAll,
|
||||
cleartags,
|
||||
importHost,
|
||||
getToken,
|
||||
} = require('server/routes/api/vcenter/functions')
|
||||
const { resources } = require('server/routes/api/vcenter/command-flags')
|
||||
|
||||
const { TEMPLATES, DATASTORES, NETWORKS, IMAGES } = resources
|
||||
|
||||
const {
|
||||
VCENTER_TOKEN,
|
||||
VCENTER_CLEAR_TAGS,
|
||||
VCENTER_IMPORT_HOSTS,
|
||||
VCENTER_IMPORT_DATASTORES,
|
||||
@ -40,10 +38,6 @@ const {
|
||||
} = Actions
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
...Commands[VCENTER_TOKEN],
|
||||
action: getToken,
|
||||
},
|
||||
{
|
||||
...Commands[VCENTER_CLEAR_TAGS],
|
||||
action: cleartags,
|
||||
|
@ -23,7 +23,6 @@ const basepath = '/vcenter'
|
||||
const { POST, GET } = httpMethod
|
||||
const { resource, postBody, query } = fromData
|
||||
|
||||
const VCENTER_TOKEN = 'vcenter.token'
|
||||
const VCENTER_CLEAR_TAGS = 'vcenter.cleartags'
|
||||
const VCENTER_IMPORT_HOSTS = 'vcenter.importhosts'
|
||||
const VCENTER_IMPORT_DATASTORES = 'vcenter.importdatastores'
|
||||
@ -33,7 +32,6 @@ const VCENTER_IMPORT_IMAGES = 'vcenter.importimages'
|
||||
const VCENTER_LIST_ALL = 'vcenter.listall'
|
||||
const VCENTER_LIST = 'vcenter.list'
|
||||
const Actions = {
|
||||
VCENTER_TOKEN,
|
||||
VCENTER_CLEAR_TAGS,
|
||||
VCENTER_IMPORT_HOSTS,
|
||||
VCENTER_IMPORT_TEMPLATES,
|
||||
@ -47,16 +45,6 @@ const Actions = {
|
||||
module.exports = {
|
||||
Actions,
|
||||
Commands: {
|
||||
[VCENTER_TOKEN]: {
|
||||
path: `${basepath}/token/:id`,
|
||||
httpMethod: GET,
|
||||
auth: true,
|
||||
params: {
|
||||
id: {
|
||||
from: resource,
|
||||
},
|
||||
},
|
||||
},
|
||||
[VCENTER_CLEAR_TAGS]: {
|
||||
path: `${basepath}/cleartags/:id`,
|
||||
httpMethod: POST,
|
||||
|
@ -17,6 +17,7 @@
|
||||
// eslint-disable-next-line node/no-deprecated-api
|
||||
const { parse } = require('url')
|
||||
const { createProxyMiddleware } = require('http-proxy-middleware')
|
||||
const { readFileSync } = require('fs-extra')
|
||||
const { getFireedgeConfig } = require('server/utils/yml')
|
||||
const { messageTerminal } = require('server/utils/general')
|
||||
const {
|
||||
@ -54,10 +55,14 @@ const vmrcProxy = createProxyMiddleware(endpointVmrc, {
|
||||
if (parseURL && parseURL.pathname) {
|
||||
const ticket = parseURL.pathname.split('/')[3]
|
||||
writeInLogger(ticket, 'path to vmrc token: %s')
|
||||
if (global && global.vcenterToken && global.vcenterToken[ticket]) {
|
||||
return global.vcenterToken[ticket]
|
||||
} else {
|
||||
writeInLogger(ticket, 'Non-existent token: %s')
|
||||
try {
|
||||
const esxi = readFileSync(
|
||||
`${global.paths.VMRC_TOKENS || ''}/${ticket}`
|
||||
).toString()
|
||||
|
||||
return esxi
|
||||
} catch (error) {
|
||||
writeInLogger(ticket, 'Error to read vmrc token file: %s')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ include OpenNebulaJSON
|
||||
|
||||
require 'sunstone_vnc'
|
||||
require 'sunstone_guac'
|
||||
require 'sunstone_vmrc'
|
||||
require 'sunstone_vm_helper'
|
||||
require 'OpenNebulaAddons'
|
||||
require 'OpenNebulaJSON/JSONUtils'
|
||||
@ -336,6 +337,33 @@ class SunstoneServer < CloudServer
|
||||
return guac.proxy(resource, type_connection, client)
|
||||
end
|
||||
|
||||
########################################################################
|
||||
# VMRC
|
||||
########################################################################
|
||||
def startvmrc(id, vmrc, _client=nil)
|
||||
resource = retrieve_resource("vm", id)
|
||||
if OpenNebula.is_error?(resource)
|
||||
return [404, resource.to_json]
|
||||
end
|
||||
vm_pool = VirtualMachinePool.new(@client, -1)
|
||||
user_pool = UserPool.new(@client)
|
||||
|
||||
rc = user_pool.info
|
||||
if OpenNebula.is_error?(rc)
|
||||
puts rc.message
|
||||
exit -1
|
||||
end
|
||||
|
||||
rc = vm_pool.info
|
||||
if OpenNebula.is_error?(rc)
|
||||
puts rc.message
|
||||
exit -1
|
||||
end
|
||||
|
||||
client = _client.nil? ? @client : _client
|
||||
return vmrc.proxy(resource, client)
|
||||
end
|
||||
|
||||
########################################################################
|
||||
# Accounting & Monitoring
|
||||
########################################################################
|
||||
|
101
src/sunstone/models/sunstone_vmrc.rb
Normal file
101
src/sunstone/models/sunstone_vmrc.rb
Normal file
@ -0,0 +1,101 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2021, OpenNebula Project, OpenNebula Systems #
|
||||
# #
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
||||
# not use this file except in compliance with the License. You may obtain #
|
||||
# a copy of the License at #
|
||||
# #
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 #
|
||||
# #
|
||||
# Unless required by applicable law or agreed to in writing, software #
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, #
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
||||
# See the License for the specific language governing permissions and #
|
||||
# limitations under the License. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
#----------------------------------------------------------------------------#
|
||||
# This class provides support for launching and stopping a vmrc proxy server #
|
||||
#----------------------------------------------------------------------------#
|
||||
|
||||
require 'rubygems'
|
||||
require 'json'
|
||||
require 'opennebula'
|
||||
require 'base64'
|
||||
require 'openssl'
|
||||
require 'vcenter_driver'
|
||||
require 'fileutils'
|
||||
require 'sunstone_remotes'
|
||||
|
||||
if !ONE_LOCATION
|
||||
VMRC_TICKETS = '/var/lib/one/sunstone_vmrc_tokens/'
|
||||
else
|
||||
VMRC_TICKETS = ONE_LOCATION + '/var/sunstone_vmrc_tokens/'
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p VMRC_TICKETS
|
||||
|
||||
# Class for necessary VMRC ticket creation
|
||||
class SunstoneVMRC < SunstoneRemoteConnections
|
||||
|
||||
attr_reader :proxy_port
|
||||
|
||||
def initialize(logger, options = {})
|
||||
super
|
||||
end
|
||||
|
||||
def proxy(vm_resource, client = nil)
|
||||
# Check configurations and VM attributes
|
||||
unless allowed_console_states.include?(vm_resource['LCM_STATE'])
|
||||
error_message = "Wrong state (#{vm_resource['LCM_STATE']}) to
|
||||
open a VMRC session"
|
||||
return error(400, error_message)
|
||||
end
|
||||
|
||||
unless vm_resource['USER_TEMPLATE/HYPERVISOR'] == 'vcenter'
|
||||
return error(400, 'VMRC Connection is only for vcenter hipervisor')
|
||||
end
|
||||
|
||||
unless vm_resource['MONITORING/VCENTER_ESX_HOST']
|
||||
error_message = 'Could not determine the vCenter ESX host where
|
||||
the VM is running. Wait till the VCENTER_ESX_HOST attribute is
|
||||
retrieved once the host has been monitored'
|
||||
return error(400, error_message)
|
||||
end
|
||||
|
||||
vm_id = vm_resource['ID']
|
||||
one_vm = VCenterDriver::VIHelper.one_item(
|
||||
OpenNebula::VirtualMachine,
|
||||
vm_id
|
||||
)
|
||||
vm_ref = one_vm['DEPLOY_ID']
|
||||
|
||||
host_id = one_vm['HISTORY_RECORDS/HISTORY[last()]/HID'].to_i
|
||||
|
||||
vi_client = VCenterDriver::VIClient.new_from_host(host_id, client)
|
||||
|
||||
vm = VCenterDriver::VirtualMachine.new(vi_client, vm_ref, vm_id)
|
||||
|
||||
parameters = vm.html_console_parameters
|
||||
|
||||
data = {
|
||||
:host => parameters[:host],
|
||||
:port => parameters[:port],
|
||||
:ticket => parameters[:ticket]
|
||||
}
|
||||
|
||||
file = File.open(
|
||||
VMRC_TICKETS +
|
||||
VCenterDriver::FileHelper.sanitize(data[:ticket]),
|
||||
'w'
|
||||
)
|
||||
file.write('https://' + data[:host] + ':' + data[:port].to_s)
|
||||
file.close
|
||||
|
||||
info = SunstoneVMHelper.get_remote_info(vm_resource)
|
||||
encode_info = Base64.encode64(info.to_json)
|
||||
|
||||
[200, { :data => data, :info => encode_info }.to_json]
|
||||
end
|
||||
|
||||
end
|
@ -629,14 +629,14 @@ define(function(require) {
|
||||
"vmrc" : function(params) {
|
||||
var callback = params.success;
|
||||
var callback_error = params.error;
|
||||
var vm_id = params.data.id;
|
||||
var id = params.data.id;
|
||||
var resource = RESOURCE;
|
||||
|
||||
var request = OpenNebulaHelper.request(resource, null, params.data);
|
||||
$.ajax({
|
||||
url: Config.publicFireedgeEndpoint + "/fireedge/api/vcenter/token/" + vm_id,
|
||||
type: "GET",
|
||||
headers: {"Authorization": fireedge_token},
|
||||
url: "vm/" + id + "/startvmrc",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
return callback ? callback(request, response) : null;
|
||||
},
|
||||
|
@ -281,9 +281,13 @@ $vnc = SunstoneVNC.new($conf, logger)
|
||||
#init Guacamole proxy
|
||||
$guac = SunstoneGuac.new(logger)
|
||||
|
||||
#init VMRC proxy
|
||||
$vmrc = SunstoneVMRC.new(logger)
|
||||
|
||||
configure do
|
||||
set :run, false
|
||||
set :vnc, $vnc
|
||||
set :vmrc, $vmrc
|
||||
set :erb, :trim => '-'
|
||||
end
|
||||
|
||||
@ -1206,6 +1210,15 @@ post '/vm/:id/guac/:type' do
|
||||
@SunstoneServer.startguac(vm_id, type_connection, $guac, user)
|
||||
end
|
||||
|
||||
##############################################################################
|
||||
# Start VMRC Session for a target VM
|
||||
##############################################################################
|
||||
post '/vm/:id/startvmrc' do
|
||||
vm_id = params[:id]
|
||||
serveradmin_client = $cloud_auth.client(nil, session[:active_zone_endpoint])
|
||||
@SunstoneServer.startvmrc(vm_id, $vmrc, serveradmin_client)
|
||||
end
|
||||
|
||||
##############################################################################
|
||||
# Perform an action on a Resource
|
||||
##############################################################################
|
||||
|
Loading…
x
Reference in New Issue
Block a user