-
Notifications
You must be signed in to change notification settings - Fork 127
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'archipel-agent' of https://github.com/everplays/Archipel …
…into archipel-vmguest Conflicts: ArchipelAgent/archipel-core/archipelcore/archipelEntity.py
- Loading branch information
Showing
17 changed files
with
2,438 additions
and
4 deletions.
There are no files selected for viewing
661 changes: 661 additions & 0 deletions
661
ArchipelAgent/archipel-agent-virtualmachine-agent/LICENSE
Large diffs are not rendered by default.
Oops, something went wrong.
2 changes: 2 additions & 0 deletions
2
ArchipelAgent/archipel-agent-virtualmachine-agent/MANIFEST.in
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
include LICENSE setup.py setup.cfg | ||
recursive-include archipelagentvirtualmachineagent * |
50 changes: 50 additions & 0 deletions
50
ArchipelAgent/archipel-agent-virtualmachine-agent/archipelvirtualmachineagent/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# __init__.py | ||
# | ||
# Copyright (C) 2012 parspooyesh <everplays@gmail.com> | ||
# This file is part of ArchipelProject | ||
# http://archipelproject.org | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU Affero General Public License as | ||
# published by the Free Software Foundation, either version 3 of the | ||
# License, or (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU Affero General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU Affero General Public License | ||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
import virtualmachineagent | ||
|
||
def make_archipel_plugin(configuration, entity, group): | ||
""" | ||
This function is the plugin factory. It will be called by the object you want | ||
to be plugged in. It must return a list whit at least on dictionary containing | ||
a key for the the plugin informations, and a key for the plugin object. | ||
@type configuration: Config Object | ||
@param configuration: the general configuration object | ||
@type entity: L{TNArchipelEntity} | ||
@param entity: the entity that has load the plugin | ||
@type group: string | ||
@param group: the entry point group name in which the plugin has been loaded | ||
@rtype: array | ||
@return: array of dictionary containing the plugins informations and objects | ||
""" | ||
return [{"info": virtualmachineagent.TNVirtualMachineAgent.plugin_info(), | ||
"plugin": virtualmachineagent.TNVirtualMachineAgent(configuration, entity, group)}] | ||
|
||
def version(): | ||
""" | ||
This function can be called runarchipel -v in order to get the version of the | ||
installed plugin. You only should have to change the egg name. | ||
@rtype: tupple | ||
@return: tupple containing the package name and the version | ||
""" | ||
import pkg_resources | ||
return (__name__, pkg_resources.get_distribution("archipel-agent-virtualmachine-guest").version, [virtualmachineagent.TNVirtualMachineAgent.plugin_info()]) | ||
|
211 changes: 211 additions & 0 deletions
211
...nt/archipel-agent-virtualmachine-agent/archipelvirtualmachineagent/virtualmachineagent.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# virtualmachineagent.py | ||
# | ||
# Copyright (C) 2012 parspooyesh <everplays@gmail.com> | ||
# This file is part of ArchipelProject | ||
# http://archipelproject.org | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU Affero General Public License as | ||
# published by the Free Software Foundation, either version 3 of the | ||
# License, or (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU Affero General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU Affero General Public License | ||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
import xmpp | ||
from archipelcore.archipelPlugin import TNArchipelPlugin | ||
from archipelcore.utils import build_error_iq | ||
|
||
ARCHIPEL_ERROR_CODE_VIRTUALMACHINEAGENT_EXEC = -10001 | ||
|
||
# Namespace | ||
ARCHIPEL_NS_GUEST_CONTROL = "archipel:guest:control" | ||
|
||
class TNVirtualMachineAgent(TNArchipelPlugin): | ||
""" | ||
this module enables user to send commands to archipelguest running on guest os | ||
""" | ||
def __init__(self, configuration, entity, entry_point_group): | ||
""" | ||
Initialize the plugin. | ||
@type configuration: Configuration object | ||
@param configuration: the configuration | ||
@type entity: L{TNArchipelEntity} | ||
@param entity: the entity that owns the plugin | ||
@type entry_point_group: string | ||
@param entry_point_group: the group name of plugin entry_point | ||
""" | ||
TNArchipelPlugin.__init__(self, configuration=configuration, entity=entity, entry_point_group=entry_point_group) | ||
self.entity.add_vm_definition_hook(self.add_net_switch_to_definition) | ||
|
||
@staticmethod | ||
def plugin_info(): | ||
""" | ||
Return informations about the plugin. | ||
@rtype: dict | ||
@return: dictionary contaning plugin informations | ||
""" | ||
return { "common-name" : "Virtual Machine Agent", | ||
"identifier" : "virtualmachineguestagent", | ||
"configuration-section" : None, | ||
"configuration-tokens" : []} | ||
|
||
def register_handlers(self): | ||
""" | ||
lets register our stanza handlers | ||
""" | ||
TNArchipelPlugin.register_handlers(self) | ||
self.entity.xmppclient.RegisterHandler('message', self.process_message, typ="chat") | ||
self.entity.xmppclient.RegisterHandler('iq', self.process_iq, ns=ARCHIPEL_NS_GUEST_CONTROL) | ||
|
||
def unregister_handlers(self): | ||
""" | ||
hmm, seems we have to unregister our handlers | ||
""" | ||
TNArchipelEntity.unregister_handlers(self) | ||
self.entity.xmppclient.UnregisterHandler('message', self.process_message, typ="chat") | ||
self.entity.xmppclient.UnregisterHandler('iq', self.process_iq, ns=ARCHIPEL_NS_GUEST_CONTROL) | ||
|
||
def execute(self, command, executor): | ||
""" | ||
generates an Iq get to agent running on guest | ||
@type command: String | ||
@param command: the command that should be executed on guest machine | ||
@type executor: String | ||
@param executor: the jid that sent the command (will be used for sending result back) | ||
@rtype: xmpp.protocol.Iq | ||
@return: generated Iq stanza | ||
""" | ||
to = xmpp.JID(self.entity.uuid+'-agent@'+self.entity.jid.getDomain()+'/guestagent') | ||
iq = xmpp.protocol.Iq(typ='get', to=to) | ||
iq.setQueryNS(ARCHIPEL_NS_GUEST_CONTROL); | ||
query = iq.getTag("query"); | ||
archipel = query.addChild('archipel', attrs={ | ||
"executor": executor, | ||
"action": "exec"}); | ||
archipel.addData(command) | ||
return iq | ||
|
||
def add_net_switch_to_definition(self, sender, xmldesc): | ||
""" | ||
adds network switches if GUEST.enabled configuration is true | ||
@type sender: xmpp.JID | ||
@param sender: the jid that edited definition | ||
@type xmldesc: xmpp.Node | ||
@param xmldesc: xml definition that is going to be sent to libvirt | ||
@rtype: xmpp.Node | ||
@return: xml definition | ||
""" | ||
shouldBeAdded = False | ||
name = xmldesc.getTag('name').getData() | ||
hostname = 'user,hostname=%s.%s' % (name, self.entity.jid.getDomain()) | ||
# check if we already have added switch | ||
commandline = xmldesc.getTag('commandline', namespace='qemu') | ||
if commandline == None: | ||
# add commandline tag, if we don't have any | ||
shouldBeAdded = True | ||
commandline = xmldesc.addChild(name='qemu:commandline', attrs={ | ||
"xmlns:qemu": 'http://libvirt.org/schemas/domain/qemu/1.0'}) | ||
else: | ||
# if we have commandline tag, check for args to be like: | ||
# 0: -net | ||
# 1: nic,model=virtio,addr=0xf,macaddr=92:42:ce:df:64:61 | ||
# 2: -net | ||
# 3: user,hostname=... | ||
hasSwitches = 0 | ||
for arg in commandline.getTags('arg', namespace='qemu'): | ||
if arg.getAttr('value') == '-net' and (hasSwitches == 0 or hasSwitches == 2): | ||
hasSwitches += 1 | ||
continue | ||
if hasSwitches == 1: | ||
if arg.getAttr('value')=='nic,model=virtio,addr=0xf,macaddr=92:42:ce:df:64:61': | ||
hasSwitches += 1 | ||
continue | ||
if hasSwitches == 3: | ||
if arg.getAttr('value')==hostname: | ||
hasSwitches += 1 | ||
break | ||
hasSwitches = 0 | ||
if hasSwitches < 4: | ||
shouldBeAdded = True | ||
if shouldBeAdded: | ||
commandline.addChild(name='qemu:arg', attrs={'value': '-net'}) | ||
commandline.addChild(name='qemu:arg', attrs={'value': 'nic,model=virtio,addr=0xf,macaddr=92:42:ce:df:64:61'}) | ||
commandline.addChild(name='qemu:arg', attrs={'value': '-net'}) | ||
commandline.addChild(name='qemu:arg', attrs={'value': hostname }) | ||
return xmldesc | ||
|
||
def process_iq(self, conn, iq): | ||
""" | ||
processes iq messages with archipel:guest:control | ||
@type conn: xmpp.Dispatcher | ||
@param conn: instance of connection that sent message | ||
@type iq: xmpp.Protocol.Iq | ||
@param iq: received Iq stanza | ||
""" | ||
reply = None | ||
action = self.entity.check_acp(conn, iq) | ||
|
||
if action == "exec": | ||
reply = self.iq_exec(iq) | ||
if reply: | ||
conn.send(reply) | ||
raise xmpp.NodeProcessed | ||
|
||
def iq_exec(self, iq): | ||
""" | ||
processes iq with exec type and returns the stanza that should be sent | ||
@type id: xmpp.Protocol.Iq | ||
@param id: received iq | ||
@rtype: xmpp.Protocol | ||
@return: the stanza that should be sent or None if we've not processes the stanza | ||
""" | ||
# if we've received iq from agent running in guest os it has to be result of | ||
# a executed command, so tunnel result back to user as message | ||
# TODO: if we received an Iq from agent running in guest and jid has permission | ||
# to send us Iq, we should tunnel his/her command to agent and sent it back as Iq | ||
# when we received result Iq | ||
reply = None | ||
try: | ||
if str(iq.getFrom()).lower() == (self.entity.uuid+"-agent@"+self.entity.jid.getDomain()+"/guestagent").lower(): | ||
archipel = iq.getTag("query").getTag("archipel") | ||
reply = xmpp.protocol.Message(archipel.getAttr('executor'), archipel.getData()) | ||
except Exception as ex: | ||
reply = build_error_iq(self, ex, iq, ARCHIPEL_ERROR_CODE_VIRTUALMACHINEAGENT_EXEC) | ||
return reply | ||
|
||
def process_message(self, conn, msg): | ||
""" | ||
processes messages that start with !exec as command that should be run on guest os | ||
@type conn: xmpp.Dispatcher | ||
@param conn: instance of connection that sent message | ||
@type msg: xmpp.Protocol.Message | ||
@param msg: received message stanza | ||
""" | ||
body = str(msg.getBody()) | ||
if body.find("!exec") == 0 and self.entity.permission_center.check_permission(str(msg.getFrom().getStripped()), "message"): | ||
runIq = self.msg_exec(msg) | ||
self.entity.log.info('sending: '+str(runIq)) | ||
conn.send(runIq) | ||
raise xmpp.NodeProcessed | ||
|
||
def msg_exec(self, msg): | ||
""" | ||
makes an Iq stanza to agent running on guest to run the command | ||
@type msg: xmpp.Protocol.Message | ||
@param msg: message that starts with !exec | ||
@rtype: xmpp.Protocol | ||
@return: the stanza that must be sent | ||
""" | ||
body = msg.getBody() | ||
command = body.replace('!exec', '').strip() | ||
executor = msg.getFrom() | ||
return self.execute(command, executor) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[egg_info] | ||
tag_build = beta | ||
tag_svn_revision = true |
83 changes: 83 additions & 0 deletions
83
ArchipelAgent/archipel-agent-virtualmachine-agent/setup.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# | ||
# setup.py | ||
# | ||
# Copyright (C) 2012 parspooyesh <everplays@gmail.com> | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU Affero General Public License as | ||
# published by the Free Software Foundation, either version 3 of the | ||
# License, or (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU Affero General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU Affero General Public License | ||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
from setuptools import setup, find_packages | ||
|
||
VERSION = '0.5.0' | ||
|
||
AUTHOR = 'Behrooz Shabani' | ||
MAIL = 'everplays@gmail.com' | ||
URL = 'http://archipelproject.org' | ||
LICENSE = 'AGPL' | ||
NAME = 'archipel-agent-virtualmachine-guest' | ||
SHORTDESCRIPTION = "This module enables user to execute commands on guest os" | ||
LONGDESCRIPTION = "This module works as a tunnel between guest-agent running on \ | ||
guest os and user (or other modules). module transforms every messages starting with \ | ||
!exec to guest-agent (using xmpp) to run on guest os, so if user runs !exec ls the ls \ | ||
command will run on guest os and result of it will be sent back to user as message." | ||
ENTRY_POINTS = { 'archipel.plugin.virtualmachine' : [ | ||
'factory=archipelvirtualmachineagent:make_archipel_plugin'], | ||
'archipel.plugin' : [ | ||
'factory=archipelvirtualmachineagent:version']} | ||
|
||
RPM_REQUIRED_DEPS = "archipel-core" | ||
|
||
## HACK FOR DEPS IN RPMS | ||
from setuptools.command.bdist_rpm import bdist_rpm | ||
def custom_make_spec_file(self): | ||
spec = self._original_make_spec_file() | ||
lineDescription = "%description" | ||
spec.insert(spec.index(lineDescription) - 1, "requires: %s" % RPM_REQUIRED_DEPS) | ||
return spec | ||
bdist_rpm._original_make_spec_file = bdist_rpm._make_spec_file | ||
bdist_rpm._make_spec_file = custom_make_spec_file | ||
## END OF HACK | ||
|
||
|
||
setup(name=NAME, | ||
version=VERSION, | ||
description=SHORTDESCRIPTION, | ||
long_description=LONGDESCRIPTION, | ||
classifiers=[ | ||
'Development Status :: 4 - Beta', | ||
'Environment :: Console', | ||
'Environment :: No Input/Output (Daemon)', | ||
'Intended Audience :: Developers', | ||
'Intended Audience :: Education', | ||
'Intended Audience :: End Users/Desktop', | ||
'Intended Audience :: Science/Research', | ||
'Intended Audience :: System Administrators', | ||
'Intended Audience :: Telecommunications Industry', | ||
'License :: OSI Approved :: GNU Affero General Public License v3', | ||
'Operating System :: POSIX :: Linux', | ||
'Programming Language :: Python', | ||
'Topic :: Internet', | ||
'Topic :: System :: Emulators', | ||
'Topic :: System :: Operating System'], | ||
keywords='archipel, virtualization, libvirt, orchestration', | ||
author=AUTHOR, | ||
author_email=MAIL, | ||
url=URL, | ||
license=LICENSE, | ||
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), | ||
include_package_data=True, | ||
zip_safe=False, | ||
install_requires=[ | ||
"archipel-core>=0.5.0beta" | ||
], | ||
entry_points=ENTRY_POINTS | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.