MoltenIron is now an Open Stack project!

Change-Id: I74065793294f53d39cb5405b17781b5fb97a05eb
This commit is contained in:
Mark Hamzy 2016-11-08 13:48:41 -06:00
parent dc37d424c7
commit f09fbb4348
20 changed files with 5 additions and 3307 deletions

View File

@ -1,130 +1,7 @@
MoltenIron overview
===================
NOTE: MoltenIron is now an Open Stack project!
MoltenIron maintains a pool of bare metal nodes.
git clone git://git.openstack.org/openstack/molteniron.git
https://git.openstack.org/cgit/openstack/molteniron/
https://github.com/openstack/molteniron/
Starting
--------
Before starting the server for the first time, the createDB.py
script must be run.
To start the server:
```bash
moltenirond-helper start
```
To stop the server:
```bash
moltenirond-helper stop
```
MoltenIron client
-----------------
Use the molteniron client (molteniron) to communicate with the server. For
usage information type:
```bash
molteniron -h
```
For usage of a specific command use:
```bash
molteniron [command] -h
```
MoltenIron commands
-------------------
command | description
------- | -----------
add | Add a node
allocate | Allocate a node
release | Release a node
get_field | Get a specific field in a node
set_field | Set a specific field with a value in a node
status | Return the status of every node
delete_db | Delete every database entry
Configuration of MoltenIron
---------------------------
Configuration of MoltenIron is specified in the file conf.yaml.
"B)" means that this configuration option is required for both the client and
the server. "C)" means that it is required only for the client. "S)" means
it is only required for the server.
usage | key | description
----- | --- | -----------
B) | mi_port | the port that the server uses to respond to commands.
C) | serverIP | The IP address of the server. This is only used by
| | clients.
S) | maxTime | The maximum amount of time, in seconds, that a node
| | is allowed to be allocated to a particular BM node.
S) | logdir | The path to the directory where the logs should be
| | stored.
S) | maxLogDays | The amount of time, in days, to keep old logs.
S) | sqlUser | The username to use for the MI server. This user
| | will automatically be generated when createDB.py is run.
S) | sqlPass | The password of sqlUser
Running testcases
-----------------
The suite of testcases is checked by tox. But, before you can run tox, you
need to change the local yaml configuration file to point to the log
directory.
```bash
(LOG=$(pwd)/testenv/log; sed -i -r -e 's,^(logdir: )(.*)$,\1'${LOG}',' conf.yaml; rm -rf testenv/; tox -e testenv)
```
Running inside a Continuous Integration environment
---------------------------------------------------
During the creation of a job, add the following snippet of bash code:
```bash
# Setup MoltenIron and all necessary prerequisites.
# And then call the MI script to allocate a node.
(
REPO_DIR=/opt/stack/new/third-party-ci-tools
MI_CONF_DIR=/usr/local/etc/molteniron/
MI_IP=10.1.2.3 # @TODO - Replace with your IP addr here!
# Grab molteniron and install it
git clone https://git.openstack.org/openstack/third-party-ci-tools ${REPO_DIR} || exit 1
cd ${REPO_DIR}/nodepool/molteniron
# @BUG Install prerequisite before running pip to install the requisites
hash mysql_config || sudo apt install -y libmysqlclient-dev
# Install the requisites for this package
sudo pip install --upgrade --force-reinstall --requirement requirements.txt
# Run the python package installation program
sudo python setup.py install
if [ -n "${MI_IP}" ]
then
# Set the molteniron server IP in the conf file
sudo sed -i "s/127.0.0.1/${MI_IP}/g" ${MI_CONF_DIR}/conf.yaml
fi
export dsvm_uuid
# NOTE: dsvm_uuid used in the following script, hence the -E
sudo -E ${REPO_DIR}/nodepool/molteniron/utils/test_hook_configure_mi.sh
) || exit $?
```
and change the MI_IP environment variable to be your MoltenIron server!
During the destruction of a job, add the following snippet of bash code:
```bash
DSVM_UUID="$(</etc/nodepool/uuid)"
echo "Cleaning up resources associated with node: ${DSVM_UUID}"
molteniron release ${DSVM_UUID}
```
https://launchpad.net/molteniron

View File

@ -1,9 +0,0 @@
mi_port: 5656
serverIP: 127.0.0.1
timeout: 5
retry: 5
maxTime: 6000
logdir: "./logs"
maxLogDays: 15
sqlUser: "root"
sqlPass: "password"

View File

@ -1,41 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
import os
import sys
import yaml
def SQL(query):
print(os.popen("mysql -u root -p --execute=\"" + query + "\"").read())
def main():
path = sys.argv[0]
dirs = path.split("/")
newPath = "/".join(dirs[:-1]) + "/"
fobj = open(newPath + "conf.yaml", "r")
conf = yaml.load(fobj)
# Create the SQL User
SQL("CREATE USER '"+conf["sqlUser"]+"'@'localhost' "
"IDENTIFIED BY '"+conf["sqlPass"]+"';")
SQL("GRANT ALL ON MoltenIron.* TO '"+conf["sqlUser"]+"'@'localhost';")
return 0
if __name__ == "__main__":
main()

View File

@ -1,237 +0,0 @@
#! /usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
import argparse
import httplib
import json
import sys
import os
import yaml
import argparse
DEBUG = False
def split_commandline_args(argv):
front = []
back = []
command_found = False
for elm in argv:
if command_found:
back.append(elm)
else:
front.append(elm)
if elm[0] != '-':
command_found = True
return (front, back)
class MoltenIron(object):
def __init__(self, conf, argv):
self.conf = conf
(argv, rest_argv) = split_commandline_args(argv)
# Parse the arguments and generate a request
parser = argparse.ArgumentParser()
parser.add_argument('command', help='Subcommand to run')
(args, unknown_args) = parser.parse_known_args (argv)
unknown_args += rest_argv
request = getattr(self, args.command)(unknown_args)
# Send the request and print the response
self.response_str = self.send(request)
self.response_json = json.loads(self.response_str)
def send(self, request):
"""Send the generated request """
connection = httplib.HTTPConnection(str(self.conf['serverIP']),
int(self.conf['mi_port']))
connection.request('POST', '/', json.dumps(request))
response = connection.getresponse()
return response.read()
def get_response(self):
"""Returns the response from the server """
return self.response_str
def get_response_map(self):
"""Returns the response from the server """
return self.response_json
def add(self, argv):
"""Generate a request to add a node to the MoltenIron database """
parser = argparse.ArgumentParser(
description='Add a node to the micli')
parser.add_argument('name', help="Name of the baremetal node")
parser.add_argument('ipmi_ip', help="IP for issuing IPMI commands to"
" this node")
parser.add_argument('ipmi_user', help="IPMI username used when issuing"
" IPMI commands to this node")
parser.add_argument('ipmi_password', help="IPMI password used when"
" issuing IPMI commands to this node")
parser.add_argument('allocation_pool', help="Comma separated list of"
" IPs to be used in deployment")
parser.add_argument('port_hwaddr', help="MAC address of port on"
" machine to use during deployment")
parser.add_argument('cpu_arch', help="Architecture of the node")
parser.add_argument('cpus', type=int, help="Number of CPUs on the"
" node")
parser.add_argument('ram_mb', type=int, help="Amount of RAM (in MiB)"
" that the node has")
parser.add_argument('disk_gb', type=int, help="Amount of disk (in GiB)"
" that the node has")
args = parser.parse_args(argv)
request = vars(args)
request['method'] = 'add'
return request
def allocate(self, argv):
"""Generate request to checkout a node from the MoltenIron database """
parser = argparse.ArgumentParser(
description="Checkout a node in molteniron. Returns the node's"
" info")
parser.add_argument('owner_name', help="Name of the requester")
parser.add_argument('number_of_nodes', type=int, help="How many nodes"
" to reserve")
args = parser.parse_args(argv)
request = vars(args)
request['method'] = 'allocate'
return request
def release(self, argv):
"""Generate a request to release an allocated node from the MoltenIron
database
"""
parser = argparse.ArgumentParser(
description="Given an owner name, release allocated node,"
" returning it to the available state")
parser.add_argument('owner_name', help="Name of the owner who"
" currently owns the nodes to be released")
args = parser.parse_args(argv)
request = vars(args)
request['method'] = 'release'
return request
def get_field(self, argv):
"""Generate a request to return a field of data from an owned node from
the MoltenIron database
"""
parser = argparse.ArgumentParser(
description="Given an owner name and the name of a field, get the"
" value of the field")
parser.add_argument('owner_name', help="Name of the owner who"
" currently owns the nodes to get the field from")
parser.add_argument('field_name', help="Name of the field to retrieve"
" the value from")
args = parser.parse_args(argv)
request = vars(args)
request['method'] = 'get_field'
return request
def set_field(self, argv):
"""Generate request to set a field of data from an id in the MoltenIron
database
"""
parser = argparse.ArgumentParser(
description='Given an id, set a field with a value')
parser.add_argument('id', help='Id of the entry')
parser.add_argument('key', help='Field name to set')
parser.add_argument('value', help='Field value to set')
args = parser.parse_args(argv)
request = vars(args)
request['method'] = 'set_field'
return request
def status(self, argv):
"""Return status """
parser = argparse.ArgumentParser(
description="Return a list of current MoltenIron Node database"
" entries")
args = parser.parse_args(argv)
request = vars(args)
request['method'] = 'status'
return request
def delete_db(self, argv):
"""Delete all database entries"""
parser = argparse.ArgumentParser(
description="Delete every entry in the MoltenIron Node database")
args = parser.parse_args(argv)
request = vars(args)
request['method'] = 'delete_db'
return request
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Molteniron command line tool")
parser.add_argument("-c",
"--conf-dir",
action="store",
type=str,
dest="conf_dir",
help="The directory where configuration is stored")
# We want individual command help later. So we need to remove a --help
# found at the end of the command line as long as there is at least
# one argument that doesn't start with '-'.
(argv, rest_argv) = split_commandline_args(list(sys.argv[1:]))
(args, unknown_args) = parser.parse_known_args (argv)
unknown_args += rest_argv
if args.conf_dir:
if not os.path.isdir (args.conf_dir):
msg = "Error: %s is not a valid directory" % (args.conf_dir, )
print >> sys.stderr, msg
sys.exit(1)
yaml_file = os.path.realpath("%s/conf.yaml" % (args.conf_dir, ))
else:
yaml_file = "/usr/local/etc/molteniron/conf.yaml"
with open(yaml_file, "r") as fobj:
conf = yaml.load(fobj)
mi = MoltenIron(conf, unknown_args)
print(mi.get_response())
try:
rc = mi.get_response_map()['status']
except KeyError:
print("Error: Server returned: %s" % (mi.get_response_map(),))
rc = 444
if rc == 200:
exit(0)
else:
exit(1)

View File

@ -1,124 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
import argparse
import sys
import os
import signal
import yaml
from daemonize import Daemonize
from molteniron import moltenirond
PID = "/var/run/moltenirond.pid"
YAML_CONF = "/usr/local/etc/molteniron/conf.yaml"
def get_moltenirond_pid():
if not os.path.isfile(PID):
return -1
with open(PID) as fobj:
lines = fobj.readlines()
try:
pid = int(lines[0])
try:
# Send harmless kill signal in order to test existance
os.kill(pid, 0)
except Exception:
return -1
return pid
except Exception:
return -1
def moltenirond_main():
with open(YAML_CONF, "r") as fobj:
conf = yaml.load(fobj)
moltenirond.listener(conf)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Molteniron daemon helper")
parser.add_argument("-c",
"--conf-dir",
action="store",
type=str,
dest="conf_dir",
help="The directory where configuration is stored")
parser.add_argument("-p",
"--pid-dir",
action="store",
type=str,
dest="pid_dir",
help="The directory where PID information is stored")
parser.add_argument("-v",
"--verbose",
action="store",
type=bool,
dest="verbose",
help="Set a verbose information mode")
parser.add_argument("command", type=str, nargs=1, help="the command")
args = parser.parse_args ()
if args.conf_dir:
if not os.path.isdir (args.conf_dir):
msg = "Error: %s is not a valid directory" % (args.conf_dir, )
print >> sys.stderr, msg
sys.exit(1)
YAML_CONF = os.path.realpath("%s/conf.yaml" % (args.conf_dir, ))
if args.pid_dir:
if not os.path.isdir (args.pid_dir):
msg = "Error: %s is not a valid directory" % (args.pid_dir, )
print >> sys.stderr, msg
sys.exit(1)
PID = os.path.realpath("%s/moltenirond.pid" % (args.pid_dir, ))
if args.verbose:
print "YAML_CONF = %s" % (YAML_CONF, )
print "PID = %s" % (PID, )
if len(args.command) != 1:
msg = "Error: Expecting one command? Received: %s" % (args.command, )
print >> sys.stderr, msg
sys.exit (1)
if args.command[0].upper().lower() == "start":
pid = get_moltenirond_pid()
if pid > 0:
print >> sys.stderr, "Error: The daemon is already running"
sys.exit(1)
daemon = Daemonize(app="moltenirond",
pid=PID,
action=moltenirond_main)
daemon.start()
elif args.command[0].upper().lower() == "stop":
pid = get_moltenirond_pid()
if pid > 0:
os.remove (PID)
os.kill(pid, signal.SIGTERM)
else:
print >> sys.stderr, "Error: The daemon doesn't exist?"
sys.exit(1)
else:
msg = "Error: Unknown command: %s" % (args.command[0], )
print >> sys.stderr, msg
sys.exit (1)

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
daemonize
MySQL-python
pyyaml
sqlalchemy
sqlalchemy_utils

View File

@ -1,27 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
from distutils.core import setup
setup(name="molteniron",
version="1.0",
description="database for Ironic Baremetal services",
url="https://github.com/openstack/third-party-ci-tools",
py_modules=["molteniron/__init__", "molteniron/moltenirond"],
scripts=["molteniron/moltenirond-helper", "molteniron/molteniron"],
data_files=[("etc/molteniron/", ["conf.yaml"])]
)

View File

@ -1,134 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
import sys
import os
import yaml
import argparse
from molteniron import moltenirond
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Molteniron command line tool")
parser.add_argument("-c",
"--conf-dir",
action="store",
type=str,
dest="conf_dir",
help="The directory where configuration is stored")
args = parser.parse_args(sys.argv[1:])
if args.conf_dir:
if not os.path.isdir (args.conf_dir):
msg = "Error: %s is not a valid directory" % (args.conf_dir, )
print >> sys.stderr, msg
sys.exit(1)
yaml_file = os.path.realpath("%s/conf.yaml" % (args.conf_dir, ))
else:
yaml_file = "/usr/local/etc/molteniron/conf.yaml"
with open(yaml_file, "r") as fobj:
conf = yaml.load(fobj)
node1 = {
"name": "pkvmci816",
"ipmi_ip": "10.228.219.134",
"ipmi_user": "user",
"ipmi_password": "2f024600fc5ef6f7",
"port_hwaddr": "97:c3:b0:47:0c:0d",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.10,10.228.112.11"
}
node2 = {
"name": "pkvmci818",
"ipmi_ip": "10.228.219.133",
"ipmi_user": "user",
"ipmi_password": "6cf0957c985b2deb",
"port_hwaddr": "2d:9e:3c:83:8a:be",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.8,10.228.112.9"
}
node3 = {
"name": "pkvmci851",
"ipmi_ip": "10.228.118.129",
"ipmi_user": "user",
"ipmi_password": "cc777c10196db585",
"port_hwaddr": "47:b0:dc:d5:82:d9",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f",
"timestamp": "1460489832",
"allocation_pool": "10.228.112.12,10.228.112.13"
}
node4 = {
"name": "pkvmci853",
"ipmi_ip": "10.228.118.133",
"ipmi_user": "user",
"ipmi_password": "a700a2d789075276",
"port_hwaddr": "44:94:1a:c7:8a:9f",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d",
"timestamp": "1460491566",
"allocation_pool": "10.228.112.14,10.228.112.15"
}
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node1)
print ret
assert ret['status'] == 400
assert ret['message'] == "Node already exists"
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret['status'] == 400
assert ret['message'] == "Node already exists"
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret['status'] == 400
assert ret['message'] == "Node already exists"
database.close()
del database

View File

@ -1,201 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
import sys
import os
import yaml
import argparse
from molteniron import moltenirond
def compare_provisioned_nodes(lhs, rhs):
lhs = lhs.copy()
rhs = rhs.copy()
rhs['provisioned'] = 'hamzy'
del lhs['status']
del lhs['timestamp']
del rhs['status']
del rhs['timestamp']
del lhs['id']
assert lhs == rhs
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Molteniron command line tool")
parser.add_argument("-c",
"--conf-dir",
action="store",
type=str,
dest="conf_dir",
help="The directory where configuration is stored")
args = parser.parse_args(sys.argv[1:])
if args.conf_dir:
if not os.path.isdir (args.conf_dir):
msg = "Error: %s is not a valid directory" % (args.conf_dir, )
print >> sys.stderr, msg
sys.exit(1)
yaml_file = os.path.realpath("%s/conf.yaml" % (args.conf_dir, ))
else:
yaml_file = "/usr/local/etc/molteniron/conf.yaml"
with open(yaml_file, "r") as fobj:
conf = yaml.load(fobj)
node1 = {
"name": "pkvmci816",
"ipmi_ip": "10.228.219.134",
"ipmi_user": "user",
"ipmi_password": "e05cc5f061426e34",
"port_hwaddr": "f8:de:29:33:a4:ed",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.10,10.228.112.11"
}
node2 = {
"name": "pkvmci818",
"ipmi_ip": "10.228.219.133",
"ipmi_user": "user",
"ipmi_password": "0614d63b6635ea3d",
"port_hwaddr": "4c:c5:da:28:2c:2d",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.8,10.228.112.9"
}
node3 = {
"name": "pkvmci851",
"ipmi_ip": "10.228.118.129",
"ipmi_user": "user",
"ipmi_password": "928b056134e4d770",
"port_hwaddr": "53:76:c6:09:50:64",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f",
"timestamp": "1460489832",
"allocation_pool": "10.228.112.12,10.228.112.13"
}
node4 = {
"name": "pkvmci853",
"ipmi_ip": "10.228.118.133",
"ipmi_user": "user",
"ipmi_password": "33f448a4fc176492",
"port_hwaddr": "85:e0:73:e9:fc:ca",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d",
"timestamp": "1460491566",
"allocation_pool": "10.228.112.14,10.228.112.15"
}
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
ret = database.allocateBM("hamzy", 1)
print ret
assert ret['status'] == 200
assert len(ret["nodes"]) == 1
compare_provisioned_nodes (ret["nodes"]["node_1"], node1)
database.close()
del database
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
database.delete_db()
database.close()
del database
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
ret = database.allocateBM("hamzy", 2)
print ret
assert ret['status'] == 200
assert len(ret["nodes"]) == 2
compare_provisioned_nodes (ret["nodes"]["node_1"], node1)
compare_provisioned_nodes (ret["nodes"]["node_2"], node2)
database.close()
del database
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
database.delete_db()
database.close()
del database
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
ret = database.allocateBM("hamzy", 3)
print ret
assert ret == {'status': 404,
'message': ('Not enough available nodes found. '
'Found 2, requested 3')}
database.close()
del database

View File

@ -1,203 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
import sys
import os
import yaml
import argparse
import time
from molteniron import moltenirond
def compare_culled_nodes(lhs, rhs):
lhs = lhs.copy()
rhs = rhs.copy()
del rhs['allocation_pool']
# timestamp can be converted on the server
del lhs['timestamp']
del rhs['timestamp']
del lhs['id']
assert lhs == rhs
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Molteniron command line tool")
parser.add_argument("-c",
"--conf-dir",
action="store",
type=str,
dest="conf_dir",
help="The directory where configuration is stored")
args = parser.parse_args(sys.argv[1:])
if args.conf_dir:
if not os.path.isdir (args.conf_dir):
msg = "Error: %s is not a valid directory" % (args.conf_dir, )
print >> sys.stderr, msg
sys.exit(1)
yaml_file = os.path.realpath("%s/conf.yaml" % (args.conf_dir, ))
else:
yaml_file = "/usr/local/etc/molteniron/conf.yaml"
with open(yaml_file, "r") as fobj:
conf = yaml.load(fobj)
node1 = {
"name": "pkvmci816",
"ipmi_ip": "10.228.219.134",
"ipmi_user": "user",
"ipmi_password": "34118fd3509621ba",
"port_hwaddr": "ff:2c:e1:cc:8e:7c",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.10,10.228.112.11"
}
node2 = {
"name": "pkvmci818",
"ipmi_ip": "10.228.219.133",
"ipmi_user": "user",
"ipmi_password": "fa2125690a95b43c",
"port_hwaddr": "f6:58:13:02:64:59",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "-1",
"allocation_pool": "10.228.112.8,10.228.112.9"
}
node3 = {
"name": "pkvmci851",
"ipmi_ip": "10.228.118.129",
"ipmi_user": "user",
"ipmi_password": "3aee014d56425a6c",
"port_hwaddr": "6e:d4:a5:ae:13:55",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f",
# NOTE: time() can return fractional values. Ex: 1460560140.47
"timestamp": str (time.time() - 1000.0),
"allocation_pool": "10.228.112.12,10.228.112.13"
}
node4 = {
"name": "pkvmci853",
"ipmi_ip": "10.228.118.133",
"ipmi_user": "user",
"ipmi_password": "254dd9fb34ddcac7",
"port_hwaddr": "a0:c9:22:23:22:9d",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d",
"timestamp": str (time.time() - 2000.0),
"allocation_pool": "10.228.112.14,10.228.112.15"
}
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
ret = database.cull (1000)
print ret
assert ret['status'] == 200
assert len(ret['nodes']) == 2
compare_culled_nodes (ret['nodes']['node_3'], node3)
compare_culled_nodes (ret['nodes']['node_4'], node4)
database.close()
del database
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
database.delete_db()
database.close()
del database
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
ret = database.cull (2000)
print ret
assert ret['status'] == 200
assert len(ret['nodes']) == 1
compare_culled_nodes (ret['nodes']['node_4'], node4)
database.close()
del database
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
database.delete_db()
database.close()
del database
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
ret = database.cull (3000)
print ret
assert ret['status'] == 200
assert len(ret['nodes']) == 0
database.close()
del database

View File

@ -1,185 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
import sys
import os
import yaml
import argparse
from molteniron import moltenirond
def compare_provisioned_nodes(lhs, rhs):
lhs = lhs.copy()
rhs = rhs.copy()
rhs['provisioned'] = 'hamzy'
del lhs['status']
del lhs['timestamp']
del rhs['status']
del rhs['timestamp']
del lhs['id']
assert lhs == rhs
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Molteniron command line tool")
parser.add_argument("-c",
"--conf-dir",
action="store",
type=str,
dest="conf_dir",
help="The directory where configuration is stored")
args = parser.parse_args(sys.argv[1:])
if args.conf_dir:
if not os.path.isdir (args.conf_dir):
msg = "Error: %s is not a valid directory" % (args.conf_dir, )
print >> sys.stderr, msg
sys.exit(1)
yaml_file = os.path.realpath("%s/conf.yaml" % (args.conf_dir, ))
else:
yaml_file = "/usr/local/etc/molteniron/conf.yaml"
with open(yaml_file, "r") as fobj:
conf = yaml.load(fobj)
node1 = {
"name": "pkvmci816",
"ipmi_ip": "10.228.219.134",
"ipmi_user": "user",
"ipmi_password": "16f6954d347c4de2",
"port_hwaddr": "28:5a:e7:e3:fe:75",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.10,10.228.112.11"
}
node2 = {
"name": "pkvmci818",
"ipmi_ip": "10.228.219.133",
"ipmi_user": "user",
"ipmi_password": "3a23241cfa516699",
"port_hwaddr": "7d:0a:e5:b9:41:9b",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.8,10.228.112.9"
}
node3 = {
"name": "pkvmci851",
"ipmi_ip": "10.228.118.129",
"ipmi_user": "user",
"ipmi_password": "4f7e47c57f27ec55",
"port_hwaddr": "5a:e8:11:e9:11:a2",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f",
"timestamp": "1460489832",
"allocation_pool": "10.228.112.12,10.228.112.13"
}
node4 = {
"name": "pkvmci853",
"ipmi_ip": "10.228.118.133",
"ipmi_user": "user",
"ipmi_password": "aeff165ded2c2f9f",
"port_hwaddr": "4d:18:82:dc:2c:d6",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d",
"timestamp": "1460491566",
"allocation_pool": "10.228.112.14,10.228.112.15"
}
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
ret = database.allocateBM("hamzy", 1)
print ret
assert ret['status'] == 200
assert len(ret["nodes"]) == 1
compare_provisioned_nodes (ret["nodes"]["node_1"], node1)
session = database.get_session()
n1 = session.query(moltenirond.Nodes).filter_by(name=node1["name"]).one()
session.close()
ret = database.deallocateBM(n1.id)
print ret
assert ret['status'] == 200
database.close()
del database
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
database.delete_db()
database.close()
del database
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
ret = database.allocateBM("hamzy", 1)
print ret
assert ret['status'] == 200
assert len(ret["nodes"]) == 1
compare_provisioned_nodes (ret["nodes"]["node_1"], node1)
session = database.get_session()
n1 = session.query(moltenirond.Nodes).filter_by(name=node1["name"]).one()
session.close()
ret = database.deallocateBM(n1.ipmi_ip)
print ret
assert ret['status'] == 200
database.close()
del database

View File

@ -1,146 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
import sys
import os
import yaml
import argparse
from molteniron import moltenirond
def compare_provisioned_nodes(lhs, rhs):
lhs = lhs.copy()
rhs = rhs.copy()
rhs['provisioned'] = 'hamzy'
del lhs['status']
del lhs['timestamp']
del rhs['status']
del rhs['timestamp']
del lhs['id']
assert lhs == rhs
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Molteniron command line tool")
parser.add_argument("-c",
"--conf-dir",
action="store",
type=str,
dest="conf_dir",
help="The directory where configuration is stored")
args = parser.parse_args(sys.argv[1:])
if args.conf_dir:
if not os.path.isdir (args.conf_dir):
msg = "Error: %s is not a valid directory" % (args.conf_dir, )
print >> sys.stderr, msg
sys.exit(1)
yaml_file = os.path.realpath("%s/conf.yaml" % (args.conf_dir, ))
else:
yaml_file = "/usr/local/etc/molteniron/conf.yaml"
with open(yaml_file, "r") as fobj:
conf = yaml.load(fobj)
node1 = {
"name": "pkvmci816",
"ipmi_ip": "10.228.219.134",
"ipmi_user": "user",
"ipmi_password": "f367d07be07d6358",
"port_hwaddr": "6d:9a:78:f3:ed:3a",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.10,10.228.112.11"
}
node2 = {
"name": "pkvmci818",
"ipmi_ip": "10.228.219.133",
"ipmi_user": "user",
"ipmi_password": "1c6a27307f8fe79d",
"port_hwaddr": "16:23:e8:07:b4:a9",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.8,10.228.112.9"
}
node3 = {
"name": "pkvmci851",
"ipmi_ip": "10.228.118.129",
"ipmi_user": "user",
"ipmi_password": "1766d597a024dd8d",
"port_hwaddr": "12:33:9f:04:07:9b",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f",
"timestamp": "1460489832",
"allocation_pool": "10.228.112.12,10.228.112.13"
}
node4 = {
"name": "pkvmci853",
"ipmi_ip": "10.228.118.133",
"ipmi_user": "user",
"ipmi_password": "7c55be8b4ef42869",
"port_hwaddr": "c2:31:e9:8a:75:96",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d",
"timestamp": "1460491566",
"allocation_pool": "10.228.112.14,10.228.112.15"
}
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
ret = database.allocateBM("hamzy", 1)
print ret
assert ret['status'] == 200
assert len(ret["nodes"]) == 1
compare_provisioned_nodes (ret["nodes"]["node_1"], node1)
ret = database.deallocateOwner("hamzy")
print ret
assert ret['status'] == 200
database.close()
del database

View File

@ -1,138 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
import sys
import os
import yaml
import argparse
from molteniron import moltenirond
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Molteniron command line tool")
parser.add_argument("-c",
"--conf-dir",
action="store",
type=str,
dest="conf_dir",
help="The directory where configuration is stored")
args = parser.parse_args(sys.argv[1:])
if args.conf_dir:
if not os.path.isdir (args.conf_dir):
msg = "Error: %s is not a valid directory" % (args.conf_dir, )
print >> sys.stderr, msg
sys.exit(1)
yaml_file = os.path.realpath("%s/conf.yaml" % (args.conf_dir, ))
else:
yaml_file = "/usr/local/etc/molteniron/conf.yaml"
with open(yaml_file, "r") as fobj:
conf = yaml.load(fobj)
node1 = {
"name": "pkvmci816",
"ipmi_ip": "10.228.219.134",
"ipmi_user": "user",
"ipmi_password": "e23af1e52896cf02",
"port_hwaddr": "5d:7e:05:dd:fe:65",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.10,10.228.112.11"
}
node2 = {
"name": "pkvmci818",
"ipmi_ip": "10.228.219.133",
"ipmi_user": "user",
"ipmi_password": "57212373db56c76a",
"port_hwaddr": "7e:41:89:e1:28:03",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.8,10.228.112.9"
}
node3 = {
"name": "pkvmci851",
"ipmi_ip": "10.228.118.129",
"ipmi_user": "user",
"ipmi_password": "c2f4b0bfa31fe9de",
"port_hwaddr": "4f:a7:48:59:6a:a7",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f",
"timestamp": "1460489832",
"allocation_pool": "10.228.112.12,10.228.112.13"
}
node4 = {
"name": "pkvmci853",
"ipmi_ip": "10.228.118.133",
"ipmi_user": "user",
"ipmi_password": "f99d122fc129c1dd",
"port_hwaddr": "a2:0d:bc:ca:c5:a5",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d",
"timestamp": "1460491566",
"allocation_pool": "10.228.112.14,10.228.112.15"
}
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
ret = database.doClean(1)
print ret
assert ret == {'status': 400, 'message': 'The node at 1 has status ready'}
ret = database.doClean(2)
print ret
assert ret == {'status': 400, 'message': 'The node at 2 has status ready'}
ret = database.doClean(3)
print ret
assert ret == {'status': 200}
ret = database.doClean(4)
print ret
assert ret == {'status': 200}

View File

@ -1,142 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
import sys
import os
import yaml
import argparse
from molteniron import moltenirond
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Molteniron command line tool")
parser.add_argument("-c",
"--conf-dir",
action="store",
type=str,
dest="conf_dir",
help="The directory where configuration is stored")
args = parser.parse_args(sys.argv[1:])
if args.conf_dir:
if not os.path.isdir (args.conf_dir):
msg = "Error: %s is not a valid directory" % (args.conf_dir, )
print >> sys.stderr, msg
sys.exit(1)
yaml_file = os.path.realpath("%s/conf.yaml" % (args.conf_dir, ))
else:
yaml_file = "/usr/local/etc/molteniron/conf.yaml"
with open(yaml_file, "r") as fobj:
conf = yaml.load(fobj)
node1 = {
"name": "pkvmci816",
"ipmi_ip": "10.228.219.134",
"ipmi_user": "user",
"ipmi_password": "7db1486ac9ea6533",
"port_hwaddr": "ca:2c:ab:88:47:b0",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "hamzy",
"timestamp": "",
"allocation_pool": "10.228.112.10,10.228.112.11"
}
node2 = {
"name": "pkvmci818",
"ipmi_ip": "10.228.219.133",
"ipmi_user": "user",
"ipmi_password": "c3f8e3f3407e880b",
"port_hwaddr": "90:24:5c:d5:0e:b3",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "mjturek",
"timestamp": "",
"allocation_pool": "10.228.112.8,10.228.112.9"
}
node3 = {
"name": "pkvmci851",
"ipmi_ip": "10.228.118.129",
"ipmi_user": "user",
"ipmi_password": "1bcbf739c7108291",
"port_hwaddr": "9c:6b:1b:31:a5:2d",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f",
"timestamp": "1460489832",
"allocation_pool": "10.228.112.12,10.228.112.13"
}
node4 = {
"name": "pkvmci853",
"ipmi_ip": "10.228.118.133",
"ipmi_user": "user",
"cpu_arch": "ppc64el",
"ipmi_password": "0c200c858ac46280",
"port_hwaddr": "64:49:12:c6:3f:bd",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "mjturek",
"timestamp": "1460491566",
"allocation_pool": "10.228.112.14,10.228.112.15"
}
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
ret = database.get_field("hamzy", "cpus")
print ret
assert ret['status'] == 200
assert len(ret['result']) ==1
assert ret['result'][0]['field'] == node1["cpus"]
ret = database.get_field("mjturek", "port_hwaddr")
print ret
assert ret['status'] == 200
assert len(ret['result']) == 2
assert ret['result'][0]['field'] == node2["port_hwaddr"]
assert ret['result'][1]['field'] == node4["port_hwaddr"]
ret = database.get_field("mmedvede", "candy")
print ret
assert ret == {'status': 400, 'message': 'field candy does not exist'}
database.close()
del database

View File

@ -1,137 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
import sys
import os
import yaml
import argparse
from molteniron import moltenirond
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Molteniron command line tool")
parser.add_argument("-c",
"--conf-dir",
action="store",
type=str,
dest="conf_dir",
help="The directory where configuration is stored")
args = parser.parse_args(sys.argv[1:])
if args.conf_dir:
if not os.path.isdir (args.conf_dir):
msg = "Error: %s is not a valid directory" % (args.conf_dir, )
print >> sys.stderr, msg
sys.exit(1)
yaml_file = os.path.realpath("%s/conf.yaml" % (args.conf_dir, ))
else:
yaml_file = "/usr/local/etc/molteniron/conf.yaml"
with open(yaml_file, "r") as fobj:
conf = yaml.load(fobj)
node1 = {
"name": "pkvmci816",
"ipmi_ip": "10.228.219.134",
"ipmi_user": "user",
"ipmi_password": "1aa328d7767653ad",
"port_hwaddr": "17:e7:f1:ab:a5:9f",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "hamzy",
"timestamp": "",
"allocation_pool": "10.228.112.10,10.228.112.11"
}
node2 = {
"name": "pkvmci818",
"ipmi_ip": "10.228.219.133",
"ipmi_user": "user",
"ipmi_password": "84b9d9ceb866f612",
"port_hwaddr": "0b:f1:9c:9d:a6:eb",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "mjturek",
"timestamp": "",
"allocation_pool": "10.228.112.8,10.228.112.9"
}
node3 = {
"name": "pkvmci851",
"ipmi_ip": "10.228.118.129",
"ipmi_user": "user",
"ipmi_password": "ba60285a1fd69800",
"port_hwaddr": "da:e0:86:2a:80:9c",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f",
"timestamp": "1460489832",
"allocation_pool": "10.228.112.12,10.228.112.13"
}
node4 = {
"name": "pkvmci853",
"ipmi_ip": "10.228.118.133",
"ipmi_user": "user",
"cpu_arch": "ppc64el",
"ipmi_password": "7810c66057ef4f2d",
"port_hwaddr": "d6:bc:ca:83:95:e7",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "mjturek",
"timestamp": "1460491566",
"allocation_pool": "10.228.112.14,10.228.112.15"
}
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
ret = database.get_ips("hamzy")
print ret
assert ret['status'] == 200
assert len(ret['ips']) == 1
assert ret['ips'] == [ node1["ipmi_ip"] ]
ret = database.get_ips("mjturek")
print ret
assert ret['status'] == 200
assert len(ret['ips']) == 2
assert ret['ips'] == [ node2["ipmi_ip"], node4["ipmi_ip"] ]
database.close()
del database

View File

@ -1,132 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2016 IBM Corporation.
#
# 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.
import sys
import os
import yaml
import argparse
from molteniron import moltenirond
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Molteniron command line tool")
parser.add_argument("-c",
"--conf-dir",
action="store",
type=str,
dest="conf_dir",
help="The directory where configuration is stored")
args = parser.parse_args(sys.argv[1:])
if args.conf_dir:
if not os.path.isdir (args.conf_dir):
msg = "Error: %s is not a valid directory" % (args.conf_dir, )
print >> sys.stderr, msg
sys.exit(1)
yaml_file = os.path.realpath("%s/conf.yaml" % (args.conf_dir, ))
else:
yaml_file = "/usr/local/etc/molteniron/conf.yaml"
with open(yaml_file, "r") as fobj:
conf = yaml.load(fobj)
node1 = {
"name": "pkvmci816",
"ipmi_ip": "10.228.219.134",
"ipmi_user": "user",
"ipmi_password": "2703f5fee17f2073",
"port_hwaddr": "b1:71:dd:02:9e:20",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.10,10.228.112.11"
}
node2 = {
"name": "pkvmci818",
"ipmi_ip": "10.228.219.133",
"ipmi_user": "user",
"ipmi_password": "c3f06ff4b798a4ea",
"port_hwaddr": "88:6e:9e:fa:65:d8",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "ready",
"provisioned": "",
"timestamp": "",
"allocation_pool": "10.228.112.8,10.228.112.9"
}
node3 = {
"name": "pkvmci851",
"ipmi_ip": "10.228.118.129",
"ipmi_user": "user",
"ipmi_password": "2885d1af50781461",
"port_hwaddr": "a2:a2:64:79:6b:69",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "7a72eccd-3153-4d08-9848-c6d3b1f18f9f",
"timestamp": "1460489832",
"allocation_pool": "10.228.112.12,10.228.112.13"
}
node4 = {
"name": "pkvmci853",
"ipmi_ip": "10.228.118.133",
"ipmi_user": "user",
"ipmi_password": "3e374dc88ca43b4f",
"port_hwaddr": "50:4a:56:3c:e9:0f",
"cpu_arch": "ppc64el",
"cpus": 20L,
"ram_mb": 51000L,
"disk_gb": 500L,
"status": "used",
"provisioned": "6b8823ef-3e14-4811-98b9-32e27397540d",
"timestamp": "1460491566",
"allocation_pool": "10.228.112.14,10.228.112.15"
}
# 8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----
database = moltenirond.DataBase(conf, moltenirond.TYPE_SQLITE_MEMORY)
ret = database.addBMNode (node1)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node2)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node3)
print ret
assert ret == {'status': 200}
ret = database.addBMNode (node4)
print ret
assert ret == {'status': 200}
session = database.get_session()
n1 = session.query(moltenirond.Nodes).filter_by(name=node1["name"]).one()
session.close()
ret = database.removeBMNode(n1.id, False)
print ret
assert ret['status'] == 200
database.close()
del database

View File

@ -1,83 +0,0 @@
[tox]
envlist = py27
[testenv:devenv]
envdir = devenv
basepython = python2.7
# usedevelop = True
# will create a devenv/lib/python2.7/site-packages/molteniron.egg-link which
# will point back to the git directory.
# Instead, we want the module installed in the virtual environment.
usedevelop = False
deps = -rrequirements.txt
[testenv:testenv]
envdir = testenv
basepython = python2.7
# usedevelop = True
# will create a testenv/lib/python2.7/site-packages/molteniron.egg-link which
# will point back to the git directory.
# Instead, we want the module installed in the virtual environment.
usedevelop = False
# Skip automatic tarballing of source distribution. We will manually run
# setup.py later...
skipsdist = True
# Don't worry about installing bash commands in the virtual environment.
whitelist_externals = mkdir
deps = -rrequirements.txt
commands = mkdir -p testenv/var/run/
python setup.py \
install \
--install-data=testenv/ \
--install-scripts=testenv/bin/ \
--install-purelib=testenv/lib/python2.7/site-packages/
moltenirond-helper \
--conf-dir=testenv/etc/molteniron/ \
--pid-dir=testenv/var/run/ \
start
molteniron \
--conf-dir=testenv/etc/molteniron/ \
delete_db
molteniron \
--conf-dir=testenv/etc/molteniron/ \
add test 10.1.2.1 user password 10.1.2.3,10.1.2.4 de:ad:be:ef:00:01 ppc64el 8 2048 32
molteniron \
--conf-dir=testenv/etc/molteniron/ \
allocate hamzy 1
molteniron \
--conf-dir=testenv/etc/molteniron/ \
get_field hamzy port_hwaddr
molteniron \
--conf-dir=testenv/etc/molteniron/ \
release hamzy
python \
tests/testAllocateBM.py \
--conf-dir=testenv/etc/molteniron/
python \
tests/testAddBMNode.py \
--conf-dir=testenv/etc/molteniron/
python \
tests/testCull.py \
--conf-dir=testenv/etc/molteniron/
python \
tests/testDeallocateBM.py \
--conf-dir=testenv/etc/molteniron/
python \
tests/testDeallocateOwner.py \
--conf-dir=testenv/etc/molteniron/
python \
tests/testDoClean.py \
--conf-dir=testenv/etc/molteniron/
python \
tests/testGetField.py \
--conf-dir=testenv/etc/molteniron/
python \
tests/testGetIps.py \
--conf-dir=testenv/etc/molteniron/
python \
tests/testRemoveBMNode.py \
--conf-dir=testenv/etc/molteniron/
moltenirond-helper \
--conf-dir=testenv/etc/molteniron/ \
--pid-dir=testenv/var/run/ \
stop

View File

@ -1,130 +0,0 @@
#!/bin/bash
# Copyright (c) 2016 IBM Corporation.
#
# 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.
errcho()
{
# Redirect stdout to stderr for the echo command
>&2 echo $@;
}
#
# NOTE:
#
# This script expects the environment variable dsvm_uuid to be set!
#
if [ -z "${dsvm_uuid}" ]
then
errcho "Error: environment variable unset: dsvm_uuid"
exit 1
fi
# Is the command-line JSON processor installed?
hash jq || sudo apt-get install -y jq
# Turn off Bash debugging temporarily to stop password being shown in log files
set +x
# allocate a BM node to a dsvm guest named dsvm_uuid, then amend the localrc
# and hardware_info files.
JSON_RSP=$(molteniron allocate $dsvm_uuid 1)
if [ $? -gt 0 ]
then
# Save the response for local debugging
echo "${JSON_RSP}" > /tmp/json.rsp
errcho "Error: allocate $dsvm_uuid 1"
MESSAGE=$(echo "${JSON_RSP}" | jq .message)
# Is there a message response?
# NOTE: jq not finding a message key returns null
if [ $? -eq 0 -a "${MESSAGE}" != "null" ]
then
errcho "Error: ${MESSAGE}"
fi
exit 1
fi
# Convert from a JSON string into a Bash array
declare -A NODE
while IFS="=" read -r key value
do
NODE[$key]="$value"
done < <(
echo ${JSON_RSP} | jq --raw-output '.nodes[]|to_entries|map("\(.key)=\(.value|tostring)")|.[]'
RC=$?
if [ ${RC} -gt 0 ]
then
echo "error=${RC}"
fi
)
if [ -n "${NODE[error]}" ]
then
errcho "Error: jq failed to parse response"
errcho "jq .nodes:"
errcho ${JSON_RSP} | jq '.nodes[]'
errcho "jq .nodes|to_entries|map:"
errcho ${JSON_RSP} | jq --raw-output '.nodes[]|to_entries|map("\(.key)=\(.value|tostring)")|.[]'
exit 2
elif [ -z "${NODE[ipmi_ip]}" \
-o -z "${NODE[port_hwaddr]}" \
-o -z "${NODE[ipmi_user]}" \
-o -z "${NODE[ipmi_password]}" ]
then
echo "ERROR: One of NODE's ipmi_ip, port_hwaddr, ipmi_user, or ipmi_password is empty!"
if [ -n "${NODE[ipmi_password]}" ]
then
SAFE_PASSWORD="*hidden*"
else
SAFE_PASSWORD=""
fi
echo "NODE[ipmi_ip] = ${NODE[ipmi_ip]}"
echo "NODE[port_hwaddr] = ${NODE[port_hwaddr]}"
echo "NODE[ipmi_user] = ${NODE[ipmi_user]}"
echo "NODE[ipmi_password] = ${SAFE_PASSWORD}"
echo "jq command returns:"
echo ${JSON_RSP} | jq --raw-output '.nodes[]|to_entries|map("\(.key)=\(.value|tostring)")|.[]'
exit 3
fi
# Set IPMI info file
printf "${NODE[ipmi_ip]} ${NODE[port_hwaddr]} ${NODE[ipmi_user]} ${NODE[ipmi_password]}\\n" > "/opt/stack/new/devstack/files/hardware_info"
set -x
# Add the hardware properties to the localrc file
printf "IRONIC_HW_ARCH=${NODE[cpu_arch]}\\nIRONIC_HW_NODE_CPU=${NODE[cpus]}\\nIRONIC_HW_NODE_RAM=${NODE[ram_mb]}\\nIRONIC_HW_NODE_DISK=${NODE[disk_gb]}\\n" >> "/opt/stack/new/devstack/localrc"
# Add the allocation pools to the localrc
IFS=',' read -r -a ALLOCATION_POOL <<< ${NODE[allocation_pool]}
POOL=''
for IP in ${ALLOCATION_POOL[@]}
do
echo "IP=${IP}"
if [ -n "${POOL}" ]
then
POOL+=" --allocation-pool "
fi
POOL+="start=${IP},end=${IP}"
done
# append ip pools to the end of our localrc
printf "ALLOCATION_POOL=\"${POOL}\"\n" >> "/opt/stack/new/devstack/localrc"