diff --git a/hooks/charmhelpers/contrib/mellanox/__init__.py b/hooks/charmhelpers/contrib/mellanox/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/hooks/charmhelpers/contrib/mellanox/infiniband.py b/hooks/charmhelpers/contrib/mellanox/infiniband.py
new file mode 100644
index 0000000..8ff2f71
--- /dev/null
+++ b/hooks/charmhelpers/contrib/mellanox/infiniband.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright 2014-2015 Canonical Limited.
+#
+# This file is part of charm-helpers.
+#
+# charm-helpers is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3 as
+# published by the Free Software Foundation.
+#
+# charm-helpers 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with charm-helpers. If not, see .
+
+
+__author__ = "Jorge Niedbalski "
+
+from charmhelpers.fetch import (
+ apt_install,
+ apt_update,
+)
+
+from charmhelpers.core.hookenv import (
+ log,
+ INFO,
+)
+
+try:
+ from netifaces import interfaces as network_interfaces
+except ImportError:
+ apt_install('python-netifaces')
+ from netifaces import interfaces as network_interfaces
+
+import os
+import re
+import subprocess
+
+from charmhelpers.core.kernel import modprobe
+
+REQUIRED_MODULES = (
+ "mlx4_ib",
+ "mlx4_en",
+ "mlx4_core",
+ "ib_ipath",
+ "ib_mthca",
+ "ib_srpt",
+ "ib_srp",
+ "ib_ucm",
+ "ib_isert",
+ "ib_iser",
+ "ib_ipoib",
+ "ib_cm",
+ "ib_uverbs"
+ "ib_umad",
+ "ib_sa",
+ "ib_mad",
+ "ib_core",
+ "ib_addr",
+ "rdma_ucm",
+)
+
+REQUIRED_PACKAGES = (
+ "ibutils",
+ "infiniband-diags",
+ "ibverbs-utils",
+)
+
+IPOIB_DRIVERS = (
+ "ib_ipoib",
+)
+
+ABI_VERSION_FILE = "/sys/class/infiniband_mad/abi_version"
+
+
+class DeviceInfo(object):
+ pass
+
+
+def install_packages():
+ apt_update()
+ apt_install(REQUIRED_PACKAGES, fatal=True)
+
+
+def load_modules():
+ for module in REQUIRED_MODULES:
+ modprobe(module, persist=True)
+
+
+def is_enabled():
+ """Check if infiniband is loaded on the system"""
+ return os.path.exists(ABI_VERSION_FILE)
+
+
+def stat():
+ """Return full output of ibstat"""
+ return subprocess.check_output(["ibstat"])
+
+
+def devices():
+ """Returns a list of IB enabled devices"""
+ return subprocess.check_output(['ibstat', '-l']).splitlines()
+
+
+def device_info(device):
+ """Returns a DeviceInfo object with the current device settings"""
+
+ status = subprocess.check_output([
+ 'ibstat', device, '-s']).splitlines()
+
+ regexes = {
+ "CA type: (.*)": "device_type",
+ "Number of ports: (.*)": "num_ports",
+ "Firmware version: (.*)": "fw_ver",
+ "Hardware version: (.*)": "hw_ver",
+ "Node GUID: (.*)": "node_guid",
+ "System image GUID: (.*)": "sys_guid",
+ }
+
+ device = DeviceInfo()
+
+ for line in status:
+ for expression, key in regexes.items():
+ matches = re.search(expression, line)
+ if matches:
+ setattr(device, key, matches.group(1))
+
+ return device
+
+
+def ipoib_interfaces():
+ """Return a list of IPOIB capable ethernet interfaces"""
+ interfaces = []
+
+ for interface in network_interfaces():
+ try:
+ driver = re.search('^driver: (.+)$', subprocess.check_output([
+ 'ethtool', '-i',
+ interface]), re.M).group(1)
+
+ if driver in IPOIB_DRIVERS:
+ interfaces.append(interface)
+ except:
+ log("Skipping interface %s" % interface, level=INFO)
+ continue
+
+ return interfaces
diff --git a/hooks/charmhelpers/core/hugepage.py b/hooks/charmhelpers/core/hugepage.py
new file mode 100644
index 0000000..a783ad9
--- /dev/null
+++ b/hooks/charmhelpers/core/hugepage.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2014-2015 Canonical Limited.
+#
+# This file is part of charm-helpers.
+#
+# charm-helpers is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3 as
+# published by the Free Software Foundation.
+#
+# charm-helpers 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with charm-helpers. If not, see .
+
+import yaml
+from charmhelpers.core import fstab
+from charmhelpers.core import sysctl
+from charmhelpers.core.host import (
+ add_group,
+ add_user_to_group,
+ fstab_mount,
+ mkdir,
+)
+from charmhelpers.core.strutils import bytes_from_string
+from subprocess import check_output
+
+
+def hugepage_support(user, group='hugetlb', nr_hugepages=256,
+ max_map_count=65536, mnt_point='/run/hugepages/kvm',
+ pagesize='2MB', mount=True, set_shmmax=False):
+ """Enable hugepages on system.
+
+ Args:
+ user (str) -- Username to allow access to hugepages to
+ group (str) -- Group name to own hugepages
+ nr_hugepages (int) -- Number of pages to reserve
+ max_map_count (int) -- Number of Virtual Memory Areas a process can own
+ mnt_point (str) -- Directory to mount hugepages on
+ pagesize (str) -- Size of hugepages
+ mount (bool) -- Whether to Mount hugepages
+ """
+ group_info = add_group(group)
+ gid = group_info.gr_gid
+ add_user_to_group(user, group)
+ if max_map_count < 2 * nr_hugepages:
+ max_map_count = 2 * nr_hugepages
+ sysctl_settings = {
+ 'vm.nr_hugepages': nr_hugepages,
+ 'vm.max_map_count': max_map_count,
+ 'vm.hugetlb_shm_group': gid,
+ }
+ if set_shmmax:
+ shmmax_current = int(check_output(['sysctl', '-n', 'kernel.shmmax']))
+ shmmax_minsize = bytes_from_string(pagesize) * nr_hugepages
+ if shmmax_minsize > shmmax_current:
+ sysctl_settings['kernel.shmmax'] = shmmax_minsize
+ sysctl.create(yaml.dump(sysctl_settings), '/etc/sysctl.d/10-hugepage.conf')
+ mkdir(mnt_point, owner='root', group='root', perms=0o755, force=False)
+ lfstab = fstab.Fstab()
+ fstab_entry = lfstab.get_entry_by_attr('mountpoint', mnt_point)
+ if fstab_entry:
+ lfstab.remove_entry(fstab_entry)
+ entry = lfstab.Entry('nodev', mnt_point, 'hugetlbfs',
+ 'mode=1770,gid={},pagesize={}'.format(gid, pagesize), 0, 0)
+ lfstab.add_entry(entry)
+ if mount:
+ fstab_mount(mnt_point)
diff --git a/hooks/charmhelpers/core/kernel.py b/hooks/charmhelpers/core/kernel.py
new file mode 100644
index 0000000..5dc6495
--- /dev/null
+++ b/hooks/charmhelpers/core/kernel.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright 2014-2015 Canonical Limited.
+#
+# This file is part of charm-helpers.
+#
+# charm-helpers is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3 as
+# published by the Free Software Foundation.
+#
+# charm-helpers 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with charm-helpers. If not, see .
+
+__author__ = "Jorge Niedbalski "
+
+from charmhelpers.core.hookenv import (
+ log,
+ INFO
+)
+
+from subprocess import check_call, check_output
+import re
+
+
+def modprobe(module, persist=True):
+ """Load a kernel module and configure for auto-load on reboot."""
+ cmd = ['modprobe', module]
+
+ log('Loading kernel module %s' % module, level=INFO)
+
+ check_call(cmd)
+ if persist:
+ with open('/etc/modules', 'r+') as modules:
+ if module not in modules.read():
+ modules.write(module)
+
+
+def rmmod(module, force=False):
+ """Remove a module from the linux kernel"""
+ cmd = ['rmmod']
+ if force:
+ cmd.append('-f')
+ cmd.append(module)
+ log('Removing kernel module %s' % module, level=INFO)
+ return check_call(cmd)
+
+
+def lsmod():
+ """Shows what kernel modules are currently loaded"""
+ return check_output(['lsmod'],
+ universal_newlines=True)
+
+
+def is_module_loaded(module):
+ """Checks if a kernel module is already loaded"""
+ matches = re.findall('^%s[ ]+' % module, lsmod(), re.M)
+ return len(matches) > 0
+
+
+def update_initramfs(version='all'):
+ """Updates an initramfs image"""
+ return check_call(["update-initramfs", "-k", version, "-u"])
diff --git a/hooks/identity-admin-relation-broken b/hooks/identity-admin-relation-broken
new file mode 120000
index 0000000..4dc4326
--- /dev/null
+++ b/hooks/identity-admin-relation-broken
@@ -0,0 +1 @@
+neutron_plumgrid_hooks.py
\ No newline at end of file
diff --git a/hooks/identity-admin-relation-changed b/hooks/identity-admin-relation-changed
new file mode 120000
index 0000000..4dc4326
--- /dev/null
+++ b/hooks/identity-admin-relation-changed
@@ -0,0 +1 @@
+neutron_plumgrid_hooks.py
\ No newline at end of file
diff --git a/hooks/identity-admin-relation-departed b/hooks/identity-admin-relation-departed
new file mode 120000
index 0000000..4dc4326
--- /dev/null
+++ b/hooks/identity-admin-relation-departed
@@ -0,0 +1 @@
+neutron_plumgrid_hooks.py
\ No newline at end of file
diff --git a/hooks/neutron-plugin-api-subordinate-relation-joined b/hooks/neutron-plugin-api-subordinate-relation-joined
new file mode 120000
index 0000000..4dc4326
--- /dev/null
+++ b/hooks/neutron-plugin-api-subordinate-relation-joined
@@ -0,0 +1 @@
+neutron_plumgrid_hooks.py
\ No newline at end of file
diff --git a/templates/kilo/plumgrid.ini b/templates/kilo/plumgrid.ini
new file mode 100644
index 0000000..5a18833
--- /dev/null
+++ b/templates/kilo/plumgrid.ini
@@ -0,0 +1,20 @@
+# icehouse
+###############################################################################
+# [ WARNING ]
+# Configuration file maintained by Juju. Local changes may be overwritten.
+###############################################################################
+[plumgriddirector]
+# This line should be pointing to the PLUMgrid Director,
+# for the PLUMgrid platform.
+director_server={{ virtual_ip }}
+director_server_port=443
+# Authentification parameters for the Director.
+# These are the admin credentials to manage and control
+# the PLUMgrid Director server.
+username={{ pg_username }}
+password={{ pg_password }}
+servertimeout=70
+
+{% if database_host -%}
+connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %}
+{% endif -%}