Init commit
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ea2818f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) Mirantis Inc.
+
+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.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4a83bf8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,35 @@
+DESTDIR=/
+SALTENVDIR=/usr/share/salt-formulas/env
+RECLASSDIR=/usr/share/salt-formulas/reclass
+FORMULANAME=$(shell grep name: metadata.yml|head -1|cut -d : -f 2|grep -Eo '[a-z0-9\-\_]*')
+
+MAKE_PID := $(shell echo $$PPID)
+JOB_FLAG := $(filter -j%, $(subst -j ,-j,$(shell ps T | grep "^\s*$(MAKE_PID).*$(MAKE)")))
+
+ifneq ($(subst -j,,$(JOB_FLAG)),)
+JOBS := $(subst -j,,$(JOB_FLAG))
+else
+JOBS := 1
+endif
+
+all:
+	@echo "make install - Install into DESTDIR"
+	@echo "make test    - Run tests"
+	@echo "make clean   - Cleanup after tests run"
+
+install:
+	# Formula
+	[ -d $(DESTDIR)/$(SALTENVDIR) ] || mkdir -p $(DESTDIR)/$(SALTENVDIR)
+	cp -a $(FORMULANAME) $(DESTDIR)/$(SALTENVDIR)/
+	[ ! -d _modules ] || cp -a _modules $(DESTDIR)/$(SALTENVDIR)/
+	[ ! -d _states ] || cp -a _states $(DESTDIR)/$(SALTENVDIR)/ || true
+	# Metadata
+	[ -d $(DESTDIR)/$(RECLASSDIR)/service/$(FORMULANAME) ] || mkdir -p $(DESTDIR)/$(RECLASSDIR)/service/$(FORMULANAME)
+	cp -a metadata/service/* $(DESTDIR)/$(RECLASSDIR)/service/$(FORMULANAME)
+
+test:
+	[ ! -d tests ] || (cd tests; ./run_tests.sh)
+
+clean:
+	[ ! -d tests/build ] || rm -rf tests/build
+	[ ! -d build ] || rm -rf build
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..49d5957
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.1
diff --git a/baremetal_simulator/files/vm.xml b/baremetal_simulator/files/vm.xml
new file mode 100644
index 0000000..f71cc8d
--- /dev/null
+++ b/baremetal_simulator/files/vm.xml
@@ -0,0 +1,55 @@
+<domain type='{{ node.engine|default('qemu') }}'>
+  <name>{{ node.name }}</name>
+  <memory unit='KiB'>{{ node.properties.memory_mb * 1024 }}</memory>
+  <vcpu placement='static'>{{ node.properties.cpus }}</vcpu>
+  <os>
+    <type arch='{{ node.properties.cpu_arch|default('x86_64') }}' machine='pc-1.0'>hvm</type>
+    <boot dev='network'/>
+    <bootmenu enable='no'/>
+    <bios useserial='yes'/>
+  </os>
+  <features>
+    <acpi/>
+    <apic/>
+    <pae/>
+  </features>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>restart</on_crash>
+  <devices>
+    <disk type='file' device='disk'>
+      <driver name='qemu' type='{{ node.disk_format|default("qcow2") }}' cache='writeback'/>
+      <source file='{{ '/var/lib/libvirt/images/' + node.name + '.' + node.disk_format|default("qcow2") }}'/>
+          <target dev='vda' bus='virtio'/>
+          <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+    </disk>
+    <controller type='ide' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    {%- for port in node.ports %}
+    <interface type='ethernet'>
+      <mac address='{{ port.address }}'/>
+      <target dev='{{ 'tap-' + node.name + 'i' + loop.index|string }}'/>
+      <model type='virtio'/>
+      <address type='pci' domain='0x0000' bus='0x01' slot='{{ '0x0' + loop.index|string }}'  function='0x0'/>
+    </interface>
+    {%- endfor %}
+    <serial type='file'>
+      <source path="{{ '/var/log/ironic-bm-logs/' + node.name + '_console.log' }}"/>
+      <target port='0'/>
+    </serial>
+    <serial type='pty'>
+      <target port='1'/>
+    </serial>
+    <input type='mouse' bus='ps2'/>
+    <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'/>
+    <video>
+      <model type='cirrus' vram='9216' heads='1'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+    </video>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+    </memballoon>
+  </devices>
+</domain>
diff --git a/baremetal_simulator/init.sls b/baremetal_simulator/init.sls
new file mode 100644
index 0000000..9efdd0f
--- /dev/null
+++ b/baremetal_simulator/init.sls
@@ -0,0 +1,141 @@
+{%- from "baremetal_simulator/map.jinja" import baremetal_simulator with context %}
+{%- if baremetal_simulator.enabled %}
+
+simulator_pkgs:
+  pkg.installed:
+    - names: {{ baremetal_simulator.pkgs }}
+
+simulator_pip_pkgs:
+  pip.installed:
+    - names: {{ baremetal_simulator.pip_pkgs }}
+    - require:
+      - pkg: python-pip
+
+libvirt-bin:
+  service.running:
+    - watch:
+      - file: /etc/libvirt/qemu.conf
+
+cgroup:
+  file.append:
+    - name: /etc/libvirt/qemu.conf
+    - source: salt://ironic/files/qemu-cgroup.conf
+
+brbm:
+  openvswitch_bridge.present
+
+brbm-phy:
+  cmd.run:
+    - names:
+      - ip addr add {{ baremetal_simulator.brbm_net.ip }}/{{ baremetal_simulator.brbm_net.prefix }} dev brbm-phy
+      - ip link set dev brbm-phy up || true
+      - ip link set dev ovs-brbm up || true
+      - ip link add ovs-brbm type veth peer name brbm-phy || true
+    - unless: ip addr show dev brbm-phy |grep -q {{ baremetal_simulator.brbm_net.ip }}
+
+ovs-brbm_in_ovs:
+  openvswitch_port.present:
+    - name: ovs-brbm
+    - bridge: brbm
+    - require:
+       - brbm-phy
+
+brbm-to-ovs:
+  cmd.run:
+    - names:
+      - ovs-vsctl --may-exist add-port br-int brint-brbm -- set Interface brint-brbm type=patch options:peer=brbm-brint
+      - ovs-vsctl --may-exist add-port brbm brbm-brint -- set Interface brbm-brint type=patch options:peer=brint-brbm
+    - unless: (ovs-vsctl show |grep -q "Port brint-brbm") && (ovs-vsctl show |grep -q "Port brbm-brint")
+
+default_pool:
+  cmd.run:
+    - name: virsh pool-define-as --name default dir --target /var/lib/libvirt/images && virsh pool-autostart default && virsh pool-start default
+    - unless: virsh pool-info default
+
+/var/log/ironic-bm-logs/:
+  file.directory:
+    - makedirs: true
+
+deploy_ramdisk:
+  file.managed:
+    - name: {{ baremetal_simulator.http_root }}/{{ baremetal_simulator.deploy_ramdisk_file }}
+    - source: {{ baremetal_simulator.deploy_ramdisk_ref }}
+    - skip_verify: true
+
+deploy_kernel:                                                                                                                                                                              
+  file.managed:                                                                                                                                                          
+    - name: {{ baremetal_simulator.http_root }}/{{ baremetal_simulator.deploy_kernel_file }}
+    - source: {{ baremetal_simulator.deploy_kernel_ref }}
+    - skip_verify: true
+
+{%- if baremetal_simulator.cirros_image_ref is defined %}
+
+{{ baremetal_simulator.cirros_image_name }}_file:
+  file.managed:
+    - name: {{ baremetal_simulator.http_root }}/{{ baremetal_simulator.cirros_image_name }}
+    - source: {{ baremetal_simulator.cirros_image_ref }}
+    - skip_verify: true
+
+{%- endif %}
+
+{%- for identity_name, nodes in baremetal_simulator.nodes.iteritems() %}
+  {%- for node in nodes %}
+
+disk_create_node{{ loop.index }}:
+  cmd.run:
+    - name: virsh vol-create-as default {{ node.name }}.qcow2 --capacity {{ node.properties.local_gb }}G --format qcow2
+    - unless: test -f /var/lib/libvirt/images/{{ node.name }}.qcow2
+
+vm_{{ node.name }}_present:
+  cmd.run:
+    - name: virsh undefine {{ node.name }} && sleep 1; virsh define /tmp/{{ node.name }}.xml
+    - onchanges:
+      - file: /tmp/{{ node.name }}.xml
+
+/tmp/{{ node.name }}.xml:
+  file.managed:
+    - source: salt://baremetal_simulator/files/vm.xml
+    - template: jinja
+    - defaults:
+        node: {{ node }}
+
+vbcm_add_{{ node.name }}:
+  cmd.run:
+    - name: vbmc add {{ node.name }} --port {{ node.driver_info.ipmi_port }}
+    - unless: vbmc show {{ node.name }}
+
+vbmc_start_{{ node.name }}:
+  cmd.run:
+    - name: vbmc start {{ node.name }} > /dev/null 2>&1 && sleep 1
+    - unless: vbmc show {{ node.name }} | grep status |grep -q running
+
+node_{{ node.name }}_present:
+  ironicng.node_present:
+    - name: {{ node.name }}
+    - driver: {{ node.driver }}
+    - properties: {{ node.properties }}
+    - profile: {{ identity_name }}
+    - driver_info: {{ node.driver_info }}
+
+{%- for port in node.ports %}
+
+{{ node.name }}_tap_device_{{ loop.index }}:
+  cmd.run:
+    - name: ip tuntap add dev tap-{{ node.name }}i{{ loop.index }} mode tap; ip link set dev tap-{{ node.name }}i{{ loop.index }} up
+    - unless: ip link show tap-{{ node.name }}i{{ loop.index }}
+
+{{ node.name }}_tap{{ loop.index }}_in_ovs:
+  openvswitch_port.present:
+    - name: tap-{{ node.name }}i{{ loop.index }}
+    - bridge: brbm
+
+{{ node.name }}_port{{ loop.index }}_present:
+  ironicng.port_present:
+    - address: {{ port.address }}
+    - node_name: {{ node.name }}
+    - profile: {{ identity_name }}
+{%- endfor %}
+
+{%- endfor %}
+{%- endfor %}
+{%- endif %}
diff --git a/baremetal_simulator/map.jinja b/baremetal_simulator/map.jinja
new file mode 100644
index 0000000..79f1427
--- /dev/null
+++ b/baremetal_simulator/map.jinja
@@ -0,0 +1,6 @@
+{% set baremetal_simulator = salt['grains.filter_by']({
+    'Common': {
+        'pkgs': ['python-pip', 'openvswitch-switch', 'libvirt-bin'],
+        'pip_pkgs': ['virtualbmc']
+    }
+}, base='Common', merge=pillar.get('baremetal_simulator', {})) %}
diff --git a/metadata.yml b/metadata.yml
new file mode 100644
index 0000000..067cfdd
--- /dev/null
+++ b/metadata.yml
@@ -0,0 +1,3 @@
+name: "baremetal_simulator"
+version: "0.1"
+source: "https://github.com/jumpojoy/salt-formula-baremetal-simulator"
diff --git a/metadata/service/simulator.yml b/metadata/service/simulator.yml
new file mode 100644
index 0000000..7a94209
--- /dev/null
+++ b/metadata/service/simulator.yml
@@ -0,0 +1,63 @@
+applications:
+  - baremetal_simulator
+parameters:
+  baremetal_simulator:
+    enabled: true
+    http_root: /var/www/httproot
+    brbm_net:
+      ip: 192.168.90.1
+      prefix: 24
+    deploy_ramdisk_file: tinyipa-stable-newton.gz
+    deploy_kernel_file: tinyipa-stable-newton.vmlinuz
+    deploy_ramdisk_ref: https://tarballs.openstack.org/ironic-python-agent/tinyipa/files/${baremetal_simulator:deploy_ramdisk_file}
+    deploy_kernel_ref: https://tarballs.openstack.org/ironic-python-agent/tinyipa/files/${baremetal_simulator:deploy_kernel_file}
+    cirros_image_name: cirros-0.3.5-x86_64-disk.img
+    cirros_image_ref: http://download.cirros-cloud.net/0.3.5/${baremetal_simulator:cirros_image_name}
+    nodes:
+      admin_identity:
+        - name: n0
+          driver: agent_ipmitool
+          properties:
+            local_gb: 10
+            cpus: 2
+            memory_mb: 1024
+          driver_info:
+            ipmi_username: admin
+            ipmi_password: password
+            ipmi_address: ${_param:single_address}
+            ipmi_port: 6200
+            deploy_ramdisk: http://${_param:single_address}/${baremetal_simulator:deploy_ramdisk_file}
+            deploy_kernel: http://${_param:single_address}/${baremetal_simulator:deploy_kernel_file}
+          ports:
+            - address: aa:bb:cc:dd:00:00
+            - address: aa:bb:cc:dd:00:01
+        - name: n1
+          driver: agent_ipmitool
+          properties:
+            local_gb: 10
+            cpus: 2
+            memory_mb: 1024
+          driver_info:
+            ipmi_username: admin
+            ipmi_password: password
+            ipmi_address: ${_param:single_address}
+            ipmi_port: 6201
+            deploy_ramdisk: http://${_param:single_address}/${baremetal_simulator:deploy_ramdisk_file}
+            deploy_kernel: http://${_param:single_address}/${baremetal_simulator:deploy_kernel_file}
+          ports:
+            - address: aa:bb:cc:dd:01:00
+        - name: n2
+          driver: agent_ipmitool
+          properties:
+            local_gb: 10
+            cpus: 2
+            memory_mb: 1024
+          driver_info:
+            ipmi_username: admin
+            ipmi_password: password
+            ipmi_address: ${_param:single_address}
+            ipmi_port: 6202
+            deploy_ramdisk: http://${_param:single_address}/${baremetal_simulator:deploy_ramdisk_file}
+            deploy_kernel: http://${_param:single_address}/${baremetal_simulator:deploy_kernel_file}
+          ports:
+            - address: aa:bb:cc:dd:02:00