3
# Copyright (c) 2011 Citrix Systems, Inc.
4
# Copyright 2011 OpenStack LLC.
5
# Copyright 2011 United States Government as represented by the
6
# Administrator of the National Aeronautics and Space Administration.
9
# Licensed under the Apache License, Version 2.0 (the "License"); you may
10
# not use this file except in compliance with the License. You may obtain
11
# a copy of the License at
13
# http://www.apache.org/licenses/LICENSE-2.0
15
# Unless required by applicable law or agreed to in writing, software
16
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18
# License for the specific language governing permissions and limitations
22
# XenAPI plugin for reading/writing information to xenstore
28
import simplejson as json
37
from pluginlib_nova import *
38
configure_logging("xenstore")
45
def wrapper(*args, **kwargs):
46
return json.dumps(fnc(*args, **kwargs))
50
class TimeoutError(StandardError):
55
def key_init(self, arg_dict):
56
"""Handles the Diffie-Hellman key exchange with the agent to
57
establish the shared secret key used to encrypt/decrypt sensitive
58
info to be passed, such as passwords. Returns the shared
61
pub = int(arg_dict["pub"])
62
arg_dict["value"] = json.dumps({"name": "keyinit", "value": pub})
63
request_id = arg_dict["id"]
64
arg_dict["path"] = "data/host/%s" % request_id
65
xenstore.write_record(self, arg_dict)
67
resp = _wait_for_agent(self, request_id, arg_dict)
68
except TimeoutError, e:
69
raise PluginError("%s" % e)
74
def password(self, arg_dict):
75
"""Writes a request to xenstore that tells the agent to set
76
the root password for the given VM. The password should be
77
encrypted using the shared secret key that was returned by a
78
previous call to key_init. The encrypted password value should
79
be passed as the value for the 'enc_pass' key in arg_dict.
81
pub = int(arg_dict["pub"])
82
enc_pass = arg_dict["enc_pass"]
83
arg_dict["value"] = json.dumps({"name": "password", "value": enc_pass})
84
request_id = arg_dict["id"]
85
arg_dict["path"] = "data/host/%s" % request_id
86
xenstore.write_record(self, arg_dict)
88
resp = _wait_for_agent(self, request_id, arg_dict)
89
except TimeoutError, e:
90
raise PluginError("%s" % e)
95
def resetnetwork(self, arg_dict):
96
"""Writes a resquest to xenstore that tells the agent
99
arg_dict['value'] = json.dumps({'name': 'resetnetwork', 'value': ''})
100
request_id = arg_dict['id']
101
arg_dict['path'] = "data/host/%s" % request_id
102
xenstore.write_record(self, arg_dict)
105
def _wait_for_agent(self, request_id, arg_dict):
106
"""Periodically checks xenstore for a response from the agent.
107
The request is always written to 'data/host/{id}', and
108
the agent's response for that request will be in 'data/guest/{id}'.
109
If no value appears from the agent within the time specified by
110
AGENT_TIMEOUT, the original request is deleted and a TimeoutError
113
arg_dict["path"] = "data/guest/%s" % request_id
114
arg_dict["ignore_missing_path"] = True
117
if time.time() - start > AGENT_TIMEOUT:
118
# No response within the timeout period; bail out
119
# First, delete the request record
120
arg_dict["path"] = "data/host/%s" % request_id
121
xenstore.delete_record(self, arg_dict)
123
"TIMEOUT: No response from agent within %s seconds." %
125
ret = xenstore.read_record(self, arg_dict)
126
# Note: the response for None with be a string that includes
129
# The agent responded
135
if __name__ == "__main__":
136
XenAPIPlugin.dispatch(
137
{"key_init": key_init,
138
"password": password,
139
"resetnetwork": resetnetwork})