OpenStack Compute (Nova) Client
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

baremetal.py 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. # Copyright 2013 Hewlett-Packard Development Company, L.P.
  2. # All Rights Reserved.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. """
  16. Baremetal interface (v2 extension).
  17. """
  18. from novaclient import base
  19. from novaclient.i18n import _
  20. from novaclient.openstack.common import cliutils
  21. from novaclient import utils
  22. class BareMetalNode(base.Resource):
  23. """
  24. A baremetal node (typically a physical server or an empty VM).
  25. """
  26. def __repr__(self):
  27. return "<BareMetalNode: %s>" % self.id
  28. class BareMetalNodeInterface(base.Resource):
  29. """
  30. An interface belonging to a baremetal node.
  31. """
  32. def __repr__(self):
  33. return "<BareMetalNodeInterface: %s>" % self.id
  34. class BareMetalNodeManager(base.ManagerWithFind):
  35. """
  36. Manage :class:`BareMetalNode` resources.
  37. """
  38. resource_class = BareMetalNode
  39. def create(self,
  40. service_host,
  41. cpus,
  42. memory_mb,
  43. local_gb,
  44. prov_mac_address,
  45. pm_address=None,
  46. pm_user=None,
  47. pm_password=None,
  48. terminal_port=None):
  49. """
  50. Create a baremetal node.
  51. :param service_host: Name of controlling compute host
  52. :param cpus: Number of CPUs in the node
  53. :param memory_mb: Megabytes of RAM in the node
  54. :param local_gb: Gigabytes of local storage in the node
  55. :param pm_address: Power management IP for the node
  56. :param pm_user: Username for the node's power management
  57. :param pm_password: Password for the node's power management
  58. :param prov_mac_address: MAC address to provision the node
  59. :param terminal_port: ShellInABox port
  60. :rtype: :class:`BareMetalNode`
  61. """
  62. body = {'node': {'service_host': service_host,
  63. 'cpus': cpus,
  64. 'memory_mb': memory_mb,
  65. 'local_gb': local_gb,
  66. 'pm_address': pm_address,
  67. 'pm_user': pm_user,
  68. 'pm_password': pm_password,
  69. 'prov_mac_address': prov_mac_address,
  70. 'terminal_port': terminal_port}}
  71. return self._create('/os-baremetal-nodes', body, 'node')
  72. def delete(self, node):
  73. """
  74. Delete a baremetal node.
  75. :param node: The :class:`BareMetalNode` to delete.
  76. """
  77. self._delete('/os-baremetal-nodes/%s' % base.getid(node))
  78. def get(self, node_id):
  79. """
  80. Get a baremetal node.
  81. :param node_id: The ID of the node to delete.
  82. :rtype: :class:`BareMetalNode`
  83. """
  84. return self._get("/os-baremetal-nodes/%s" % node_id, 'node')
  85. def list(self):
  86. """
  87. Get a list of all baremetal nodes.
  88. :rtype: list of :class:`BareMetalNode`
  89. """
  90. return self._list('/os-baremetal-nodes', 'nodes')
  91. def add_interface(self, node_id, address, datapath_id=0, port_no=0):
  92. """
  93. Add an interface to a baremetal node.
  94. :param node_id: The ID of the node to modify.
  95. :param address: The MAC address to add.
  96. :param datapath_id: Datapath ID of OpenFlow switch for the interface
  97. :param port_no: OpenFlow port number for the interface
  98. :rtype: :class:`BareMetalNodeInterface`
  99. """
  100. body = {'add_interface': {'address': address,
  101. 'datapath_id': datapath_id,
  102. 'port_no': port_no}}
  103. url = '/os-baremetal-nodes/%s/action' % node_id
  104. _resp, body = self.api.client.post(url, body=body)
  105. return BareMetalNodeInterface(self, body['interface'])
  106. def remove_interface(self, node_id, address):
  107. """
  108. Remove an interface from a baremetal node.
  109. :param node_id: The ID of the node to modify.
  110. :param address: The MAC address to remove.
  111. :rtype: bool
  112. """
  113. req_body = {'remove_interface': {'address': address}}
  114. url = '/os-baremetal-nodes/%s/action' % node_id
  115. self.api.client.post(url, body=req_body)
  116. def list_interfaces(self, node_id):
  117. """
  118. List the interfaces on a baremetal node.
  119. :param node_id: The ID of the node to list.
  120. :rtype: list
  121. """
  122. interfaces = []
  123. node = self._get("/os-baremetal-nodes/%s" % node_id, 'node')
  124. for interface in node.interfaces:
  125. interface_object = BareMetalNodeInterface(self, interface)
  126. interfaces.append(interface_object)
  127. return interfaces
  128. @cliutils.arg(
  129. 'service_host',
  130. metavar='<service_host>',
  131. help=_('Name of nova compute host which will control this baremetal '
  132. 'node'))
  133. @cliutils.arg(
  134. 'cpus',
  135. metavar='<cpus>',
  136. type=int,
  137. help=_('Number of CPUs in the node'))
  138. @cliutils.arg(
  139. 'memory_mb',
  140. metavar='<memory_mb>',
  141. type=int,
  142. help=_('Megabytes of RAM in the node'))
  143. @cliutils.arg(
  144. 'local_gb',
  145. metavar='<local_gb>',
  146. type=int,
  147. help=_('Gigabytes of local storage in the node'))
  148. @cliutils.arg(
  149. 'prov_mac_address',
  150. metavar='<prov_mac_address>',
  151. help=_('MAC address to provision the node'))
  152. @cliutils.arg(
  153. '--pm_address', default=None,
  154. metavar='<pm_address>',
  155. help=_('Power management IP for the node'))
  156. @cliutils.arg(
  157. '--pm_user', default=None,
  158. metavar='<pm_user>',
  159. help=_('Username for the node\'s power management'))
  160. @cliutils.arg(
  161. '--pm_password', default=None,
  162. metavar='<pm_password>',
  163. help=_('Password for the node\'s power management'))
  164. @cliutils.arg(
  165. '--terminal_port', default=None,
  166. metavar='<terminal_port>',
  167. type=int,
  168. help=_('ShellInABox port?'))
  169. def do_baremetal_node_create(cs, args):
  170. """Create a baremetal node."""
  171. node = cs.baremetal.create(args.service_host, args.cpus,
  172. args.memory_mb, args.local_gb,
  173. args.prov_mac_address,
  174. pm_address=args.pm_address,
  175. pm_user=args.pm_user,
  176. pm_password=args.pm_password,
  177. terminal_port=args.terminal_port)
  178. _print_baremetal_resource(node)
  179. @cliutils.arg(
  180. 'node',
  181. metavar='<node>',
  182. help=_('ID of the node to delete.'))
  183. def do_baremetal_node_delete(cs, args):
  184. """Remove a baremetal node and any associated interfaces."""
  185. node = _find_baremetal_node(cs, args.node)
  186. cs.baremetal.delete(node)
  187. def _translate_baremetal_node_keys(collection):
  188. convert = [('service_host', 'host'),
  189. ('local_gb', 'disk_gb'),
  190. ('prov_mac_address', 'mac_address'),
  191. ('pm_address', 'pm_address'),
  192. ('pm_user', 'pm_username'),
  193. ('pm_password', 'pm_password'),
  194. ('terminal_port', 'terminal_port'),
  195. ]
  196. for item in collection:
  197. keys = item.__dict__.keys()
  198. for from_key, to_key in convert:
  199. if from_key in keys and to_key not in keys:
  200. setattr(item, to_key, item._info[from_key])
  201. def _print_baremetal_nodes_list(nodes):
  202. """Print the list of baremetal nodes."""
  203. def _parse_address(fields):
  204. macs = []
  205. for interface in fields.interfaces:
  206. macs.append(interface['address'])
  207. return ', '.join("%s" % i for i in macs)
  208. formatters = {
  209. 'MAC Address': _parse_address
  210. }
  211. _translate_baremetal_node_keys(nodes)
  212. utils.print_list(nodes, [
  213. 'ID',
  214. 'Host',
  215. 'Task State',
  216. 'CPUs',
  217. 'Memory_MB',
  218. 'Disk_GB',
  219. 'MAC Address',
  220. 'PM Address',
  221. 'PM Username',
  222. 'PM Password',
  223. 'Terminal Port',
  224. ], formatters=formatters)
  225. def do_baremetal_node_list(cs, _args):
  226. """Print list of available baremetal nodes."""
  227. nodes = cs.baremetal.list()
  228. _print_baremetal_nodes_list(nodes)
  229. def _find_baremetal_node(cs, node):
  230. """Get a node by ID."""
  231. return utils.find_resource(cs.baremetal, node)
  232. def _print_baremetal_resource(resource):
  233. """Print details of a baremetal resource."""
  234. info = resource._info.copy()
  235. utils.print_dict(info)
  236. def _print_baremetal_node_interfaces(interfaces):
  237. """Print interfaces of a baremetal node."""
  238. utils.print_list(interfaces, [
  239. 'ID',
  240. 'Datapath_ID',
  241. 'Port_No',
  242. 'Address',
  243. ])
  244. @cliutils.arg(
  245. 'node',
  246. metavar='<node>',
  247. help=_("ID of node"))
  248. def do_baremetal_node_show(cs, args):
  249. """Show information about a baremetal node."""
  250. node = _find_baremetal_node(cs, args.node)
  251. _print_baremetal_resource(node)
  252. @cliutils.arg(
  253. 'node',
  254. metavar='<node>',
  255. help=_("ID of node"))
  256. @cliutils.arg(
  257. 'address',
  258. metavar='<address>',
  259. help=_("MAC address of interface"))
  260. @cliutils.arg(
  261. '--datapath_id',
  262. default=0,
  263. metavar='<datapath_id>',
  264. help=_("OpenFlow Datapath ID of interface"))
  265. @cliutils.arg(
  266. '--port_no',
  267. default=0,
  268. metavar='<port_no>',
  269. help=_("OpenFlow port number of interface"))
  270. def do_baremetal_interface_add(cs, args):
  271. """Add a network interface to a baremetal node."""
  272. bmif = cs.baremetal.add_interface(args.node, args.address,
  273. args.datapath_id, args.port_no)
  274. _print_baremetal_resource(bmif)
  275. @cliutils.arg('node', metavar='<node>', help=_("ID of node"))
  276. @cliutils.arg(
  277. 'address',
  278. metavar='<address>',
  279. help=_("MAC address of interface"))
  280. def do_baremetal_interface_remove(cs, args):
  281. """Remove a network interface from a baremetal node."""
  282. cs.baremetal.remove_interface(args.node, args.address)
  283. @cliutils.arg('node', metavar='<node>', help=_("ID of node"))
  284. def do_baremetal_interface_list(cs, args):
  285. """List network interfaces associated with a baremetal node."""
  286. interfaces = cs.baremetal.list_interfaces(args.node)
  287. _print_baremetal_node_interfaces(interfaces)