summaryrefslogtreecommitdiffstats
path: root/laas-fog
diff options
context:
space:
mode:
authorParker Berberian <pberberian@iol.unh.edu>2017-12-20 13:04:12 -0500
committerParker Berberian <pberberian@iol.unh.edu>2017-12-20 13:04:12 -0500
commitbfd1f0efbe3196cdd6ab6bb811fc53828e45528f (patch)
treeb2747aab9a5d092a9977c0e7133ebc16eb809117 /laas-fog
parentfc52e89492c20ca7a93d4e48f0cfa01ddacf7fa8 (diff)
Adds ability to capture and image hosts
JIRA: PHAROS-322 Adds the action metadata files, action code, and workflow definitions that allows us to image a selected host with any disk image or operating system. For example, to install ubuntu on host "pod4", run st2 run pharoslaas.fog_imageWorkflow host=pod4 os=ubuntu Change-Id: I9cb0bf031f19313b3b9ad6c5e3ed11dff4ea2039 Signed-off-by: Parker Berberian <pberberian@iol.unh.edu>
Diffstat (limited to 'laas-fog')
-rw-r--r--laas-fog/pharoslaas/actions/fogAction.py153
-rw-r--r--laas-fog/pharoslaas/actions/fog_captureHost.py37
-rw-r--r--laas-fog/pharoslaas/actions/fog_captureHost.yaml25
-rw-r--r--laas-fog/pharoslaas/actions/fog_captureWorkflow.yaml25
-rw-r--r--laas-fog/pharoslaas/actions/fog_changeImage.py38
-rw-r--r--laas-fog/pharoslaas/actions/fog_changeImage.yaml31
-rw-r--r--laas-fog/pharoslaas/actions/fog_imageWorkflow.yaml31
-rw-r--r--laas-fog/pharoslaas/actions/fog_startImaging.py55
-rw-r--r--laas-fog/pharoslaas/actions/fog_startImaging.yaml27
-rw-r--r--laas-fog/pharoslaas/actions/fog_waitForCapture.py37
-rw-r--r--laas-fog/pharoslaas/actions/fog_waitForCapture.yaml25
-rw-r--r--laas-fog/pharoslaas/actions/fog_waitForImaging.py44
-rw-r--r--laas-fog/pharoslaas/actions/fog_waitForImaging.yaml25
-rw-r--r--laas-fog/pharoslaas/actions/restartHost.sh20
-rw-r--r--laas-fog/pharoslaas/actions/restartHost.yaml27
-rw-r--r--laas-fog/pharoslaas/actions/waitForBoot.sh29
-rw-r--r--laas-fog/pharoslaas/actions/waitForBoot.yaml26
-rw-r--r--laas-fog/pharoslaas/actions/workflows/fog_captureWorkflow.yaml27
-rw-r--r--laas-fog/pharoslaas/actions/workflows/fog_imageWorkflow.yaml39
19 files changed, 721 insertions, 0 deletions
diff --git a/laas-fog/pharoslaas/actions/fogAction.py b/laas-fog/pharoslaas/actions/fogAction.py
new file mode 100644
index 0000000..ef74939
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fogAction.py
@@ -0,0 +1,153 @@
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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 requests
+import sys
+import json
+import time
+from st2actions.runners.pythonrunner import Action
+
+
+class FogAction(Action):
+ """
+ This class talks with the REST web api for the FOG server.
+ """
+ def __init__(self, config=None):
+ self.baseURL = config['fog']['address']
+ self.fogKey = config['fog']['api_key']
+ self.userKey = config['fog']['user_key']
+ self.updateHeader()
+
+ def updateHeader(self):
+ """
+ recreates the http header used to talk to the fog api
+ """
+ self.header = {}
+ self.header['fog-api-token'] = self.fogKey
+ self.header['fog-user-token'] = self.userKey
+
+ def getImageID(self, img=None, os=None, host=None):
+ """
+ returns the numerical id associated with the given img name or
+ operating system. If both are given, the img gets priority.
+ if img is a number, it is assumed to be a valid id
+ """
+ # st2 will promote an empty arg to the str "None" :(
+ if not img or img == "None":
+ return self.getImageIDFromOS(os, host)
+ try:
+ return int(img)
+ except:
+ url = self.baseURL+"image"
+ images = requests.get(url=url, headers=self.header)
+ images = images.json()['images']
+ for image in images:
+ if img == image['name']:
+ return image['id']
+ return -1
+
+ def getImageIDFromOS(self, os, host):
+ enum = {"ubuntu": "ubuntu_image",
+ "centos": "centos_image",
+ "suse": "suse_image"
+ }
+ os = os.lower()
+ if os not in enum.keys():
+ return -1
+ host_dict = json.loads(
+ self.action_service.get_value(name=host, local=False)
+ )
+ return int(host_dict[enum[os]])
+
+ def delTask(self, hostNum):
+ """
+ Tries to delete an existing task for the host
+ with hostNum as a host number
+ """
+ try:
+ url = self.baseURL+'fog/host/'+str(hostNum)+'/cancel'
+ req = requests.delete(url, headers=self.header)
+ if req.status_code == 200:
+ self.logger.info("%s", "successfully deleted image task")
+ except Exception:
+ self.logger.exception("Failed to delete the imaging task!")
+
+ def getHostNumber(self, hostname):
+ """
+ returns the host number of given host
+ """
+ try:
+ req = requests.get(self.baseURL+"host", headers=self.header)
+ hostData = req.json()
+ if hostData is not None:
+ for hostDict in hostData['hosts']:
+ if hostname == hostDict['name']:
+ return hostDict['id']
+ return -1
+ except Exception:
+ self.logger.exception('%s', "Failed to connect to the FOG server")
+
+ def request(self, url, data=None, method="get"):
+ if data is not None:
+ return self.dataRequest(url, data, method=method)
+ try:
+ response = requests.get(url, headers=self.header)
+ return response.json()
+ except Exception:
+ self.logger.exception("Failed to reach FOG at %s", url)
+ sys.exit(1)
+
+ def dataRequest(self, url, data, method="post"):
+ methods = {
+ "post": requests.post,
+ "put": requests.put
+ }
+ try:
+ return methods[method](url, json=data, headers=self.header)
+ except Exception:
+ self.logger.exception("Failed to reach FOG at %s", url)
+ sys.exit(1)
+
+ def getFogHost(self, host):
+ hostData = self.action_service.get_value(host, local=False)
+ return json.loads(hostData)['fog_name']
+
+ def waitForTask(self, taskID):
+ """
+ Watches a task and waits for it to finish (disapear).
+ There may be a smarter way to do this and track errors,
+ but st2 will timeout for me if something goes wrong
+ """
+ task = self.getTask(taskID)
+ while(task):
+ time.sleep(15)
+ task = self.getTask(taskID)
+
+ def getAllTasks(self):
+ try:
+ tasks = requests.get(
+ self.baseURL+'task/current',
+ headers=self.header
+ ).json()['tasks']
+ return tasks
+ except Exception:
+ return []
+
+ def getTask(self, taskID):
+ for task in self.getAllTasks():
+ if task['id'] == taskID:
+ return task
+ return {}
diff --git a/laas-fog/pharoslaas/actions/fog_captureHost.py b/laas-fog/pharoslaas/actions/fog_captureHost.py
new file mode 100644
index 0000000..d8ee343
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fog_captureHost.py
@@ -0,0 +1,37 @@
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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 fogAction import FogAction
+import requests
+import sys
+
+
+class StartCaptureAction(FogAction):
+ def __init__(self, config=None):
+ super(StartCaptureAction, self).__init__(config=config)
+
+ def run(self, host=None):
+ """
+ Schedules a capture for the given host with its
+ assigned image
+ """
+ host = self.getFogHost(host)
+ num = str(self.getHostNumber(host))
+ url = self.baseURL+'host/'+num+'/task'
+ try:
+ requests.post(url, headers=self.header, json={"taskTypeID": 2})
+ except Exception:
+ sys.exit(1)
diff --git a/laas-fog/pharoslaas/actions/fog_captureHost.yaml b/laas-fog/pharoslaas/actions/fog_captureHost.yaml
new file mode 100644
index 0000000..3e38825
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fog_captureHost.yaml
@@ -0,0 +1,25 @@
+---
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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. #
+##############################################################################
+
+name: fog_captureHost
+entry_point: fog_captureHost.py
+runner_type: python-script
+enabled: true
+parameters:
+ host:
+ type: string
+ required: true
diff --git a/laas-fog/pharoslaas/actions/fog_captureWorkflow.yaml b/laas-fog/pharoslaas/actions/fog_captureWorkflow.yaml
new file mode 100644
index 0000000..a951d55
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fog_captureWorkflow.yaml
@@ -0,0 +1,25 @@
+---
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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. #
+##############################################################################
+
+name: fog_captureWorkflow
+entry_point: workflows/fog_captureWorkflow.yaml
+runner_type: action-chain
+enabled: true
+parameters:
+ host:
+ type: string
+ required: true
diff --git a/laas-fog/pharoslaas/actions/fog_changeImage.py b/laas-fog/pharoslaas/actions/fog_changeImage.py
new file mode 100644
index 0000000..3586a75
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fog_changeImage.py
@@ -0,0 +1,38 @@
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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 fogAction import FogAction
+import requests
+
+
+class ChangeImageAction(FogAction):
+ def __init__(self, config):
+ super(ChangeImageAction, self).__init__(config=config)
+
+ def run(self, host=None, image=None, os=None):
+ """
+ Sets the image to be used during ghosting to the image
+ with id imgNum. host can either be a hostname or number.
+ """
+ imgNum = self.getImageID(img=image, os=os, host=host)
+ if imgNum < 0:
+ return
+ host = self.getFogHost(host)
+ hostnum = self.getHostNumber(host)
+ url = self.baseURL+"host/"+str(hostnum)
+ host_conf = requests.get(url, headers=self.header).json()
+ host_conf['imageID'] = str(imgNum)
+ requests.put(url+"/edit", headers=self.header, json=host_conf)
diff --git a/laas-fog/pharoslaas/actions/fog_changeImage.yaml b/laas-fog/pharoslaas/actions/fog_changeImage.yaml
new file mode 100644
index 0000000..36deff9
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fog_changeImage.yaml
@@ -0,0 +1,31 @@
+---
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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. #
+##############################################################################
+
+name: "fog_changeImage"
+enabled: true
+runner_type: python-script
+entry_point: "fog_changeImage.py"
+parameters:
+ host:
+ type: string
+ required: true
+ image:
+ required: false
+ type: string
+ os:
+ required: false
+ type: string
diff --git a/laas-fog/pharoslaas/actions/fog_imageWorkflow.yaml b/laas-fog/pharoslaas/actions/fog_imageWorkflow.yaml
new file mode 100644
index 0000000..f8c4aef
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fog_imageWorkflow.yaml
@@ -0,0 +1,31 @@
+---
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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. #
+##############################################################################
+
+name: "fog_imageWorkflow"
+entry_point: "workflows/fog_imageWorkflow.yaml"
+runner_type: "action-chain"
+enabled: true
+parameters:
+ host:
+ type: "string"
+ required: true
+ image:
+ required: false
+ type: "string"
+ os:
+ required: false
+ type: "string"
diff --git a/laas-fog/pharoslaas/actions/fog_startImaging.py b/laas-fog/pharoslaas/actions/fog_startImaging.py
new file mode 100644
index 0000000..f775efe
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fog_startImaging.py
@@ -0,0 +1,55 @@
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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 fogAction import FogAction
+import requests
+import sys
+
+
+class StartImagingAction(FogAction):
+ def __init__(self, config=None):
+ super(StartImagingAction, self).__init__(config=config)
+
+ def run(self, host=None):
+ """
+ Schedules an imaging task for the given host.
+ This automatically uses the "associated" disk image.
+ """
+ host = self.getFogHost(host)
+ num = str(self.getHostNumber(host))
+ url = self.baseURL+'host/'+num+'/task'
+ try:
+ req = requests.post(
+ url,
+ headers=self.header,
+ json={"taskTypeID": 1}
+ )
+ if req.status_code == 200:
+ # self.logger.info("%s", "Scheduled image task for host")
+ pass
+ except Exception:
+ # self.logger.warning("%s", "Failed to schedule host imaging")
+ # self.logger.warning("%s", "Trying to delete existing image task")
+ self.delTask(num)
+ req = requests.post(
+ url,
+ headers=self.header,
+ json={"taskTypeID": 1}
+ )
+ if req.status_code == 200:
+ # self.logger.info("%s", "Scheduled image task for host")
+ pass
+ sys.exit(0)
diff --git a/laas-fog/pharoslaas/actions/fog_startImaging.yaml b/laas-fog/pharoslaas/actions/fog_startImaging.yaml
new file mode 100644
index 0000000..2a24f4d
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fog_startImaging.yaml
@@ -0,0 +1,27 @@
+---
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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. #
+##############################################################################
+
+name: "fog_startImaging"
+description: "This will use FOG to image the given host"
+runner_type: "python-script"
+enabled: true
+entry_point: "fog_startImaging.py"
+parameters:
+ host:
+ type: "string"
+ description: "the hostname of the host (eg pod2)"
+ required: true
diff --git a/laas-fog/pharoslaas/actions/fog_waitForCapture.py b/laas-fog/pharoslaas/actions/fog_waitForCapture.py
new file mode 100644
index 0000000..7f7c488
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fog_waitForCapture.py
@@ -0,0 +1,37 @@
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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 fogAction import FogAction
+import sys
+
+
+class waitForCaptureAction(FogAction):
+ def __init__(self, config=None):
+ super(waitForCaptureAction, self).__init__(config=config)
+
+ def run(self, host=None):
+ host = self.getFogHost(host)
+ captureTaskID = self.getCaptureTaskID(host)
+ if(captureTaskID < 0):
+ sys.exit(1)
+ self.waitForTask(captureTaskID)
+
+ def getCaptureTaskID(self, host=None):
+ for task in self.getAllTasks():
+ hostname = str(task['host']['name'])
+ if hostname == host and int(task['typeID']) == 2:
+ return task['id']
+ return -1
diff --git a/laas-fog/pharoslaas/actions/fog_waitForCapture.yaml b/laas-fog/pharoslaas/actions/fog_waitForCapture.yaml
new file mode 100644
index 0000000..2d0364e
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fog_waitForCapture.yaml
@@ -0,0 +1,25 @@
+---
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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. #
+##############################################################################
+
+name: fog_waitForCapture
+enabled: true
+runner_type: python-script
+entry_point: fog_waitForCapture.py
+parameters:
+ host:
+ type: string
+ required: true
diff --git a/laas-fog/pharoslaas/actions/fog_waitForImaging.py b/laas-fog/pharoslaas/actions/fog_waitForImaging.py
new file mode 100644
index 0000000..ea73f8f
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fog_waitForImaging.py
@@ -0,0 +1,44 @@
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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 fogAction import FogAction
+import sys
+
+
+class WaitForImagingAction(FogAction):
+ def __init__(self, config=None):
+ super(WaitForImagingAction, self).__init__(config=config)
+
+ def run(self, host):
+ """
+ tracks the imaging task to completion.
+ """
+ host = self.getFogHost(host)
+ imageTaskID = self.getImagingTaskID(host)
+ if(imageTaskID < 0):
+ sys.exit(1)
+ self.waitForTask(imageTaskID)
+
+ def getImagingTaskID(self, host):
+ """
+ Sorts through all current tasks to find the image task
+ associated with the given host.
+ """
+ for task in self.getAllTasks():
+ hostname = str(task['host']['name'])
+ if hostname == host and int(task['typeID']) == 1:
+ return task['id']
+ return -1
diff --git a/laas-fog/pharoslaas/actions/fog_waitForImaging.yaml b/laas-fog/pharoslaas/actions/fog_waitForImaging.yaml
new file mode 100644
index 0000000..4be325c
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/fog_waitForImaging.yaml
@@ -0,0 +1,25 @@
+---
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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. #
+##############################################################################
+
+name: "fog_waitForImaging"
+entry_point: "fog_waitForImaging.py"
+runner_type: "python-script"
+enabled: true
+parameters:
+ host:
+ required: true
+ type: "string"
diff --git a/laas-fog/pharoslaas/actions/restartHost.sh b/laas-fog/pharoslaas/actions/restartHost.sh
new file mode 100644
index 0000000..b6842d1
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/restartHost.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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. #
+##############################################################################
+
+ssh -o userknownhostsfile=/dev/null -o stricthostkeychecking=false root@"$1" "shutdown -r now"
+
+exit 0
diff --git a/laas-fog/pharoslaas/actions/restartHost.yaml b/laas-fog/pharoslaas/actions/restartHost.yaml
new file mode 100644
index 0000000..f274caf
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/restartHost.yaml
@@ -0,0 +1,27 @@
+---
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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. #
+##############################################################################
+
+name: restartHost
+description: restarts given host imediately and returns 0
+runner_type: local-shell-script
+entry_point: restartHost.sh
+parameters:
+ host:
+ type: string
+ required: true
+ description: host to restart
+ position: 0
diff --git a/laas-fog/pharoslaas/actions/waitForBoot.sh b/laas-fog/pharoslaas/actions/waitForBoot.sh
new file mode 100644
index 0000000..399795e
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/waitForBoot.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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. #
+##############################################################################
+
+ping -c 1 "$1"
+
+while [ $? -gt 0 ] ; do
+ ping -c 1 "$1" && sleep 5
+done
+
+false
+
+while [ $? -gt 0 ] ; do
+ ping -c 1 "$1" && sleep 5
+done
+exit 0
diff --git a/laas-fog/pharoslaas/actions/waitForBoot.yaml b/laas-fog/pharoslaas/actions/waitForBoot.yaml
new file mode 100644
index 0000000..0700980
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/waitForBoot.yaml
@@ -0,0 +1,26 @@
+---
+##############################################################################
+# Copyright 2017 Parker Berberian and Others #
+# #
+# 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. #
+##############################################################################
+
+name: waitForBoot
+entry_point: waitForBoot.sh
+runner_type: local-shell-script
+enabled: true
+parameters:
+ host:
+ type: string
+ required: true
+ position: 0
diff --git a/laas-fog/pharoslaas/actions/workflows/fog_captureWorkflow.yaml b/laas-fog/pharoslaas/actions/workflows/fog_captureWorkflow.yaml
new file mode 100644
index 0000000..0f2fece
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/workflows/fog_captureWorkflow.yaml
@@ -0,0 +1,27 @@
+---
+chain:
+ -
+ name: "startCapture"
+ ref: "pharoslaas.fog_captureHost"
+ parameters:
+ host: "{{host}}"
+ on-success: "restartHost"
+ -
+ name: "restartHost"
+ ref: "pharoslaas.restartHost"
+ parameters:
+ host: "{{host}}"
+ on-success: "waitForCapture"
+ -
+ name: "waitForCapture"
+ ref: "pharoslaas.fog_waitForCapture"
+ parameters:
+ host: "{{host}}"
+ on-success: "waitForBoot"
+
+ -
+ name: "waitForBoot"
+ ref: pharoslaas.waitForBoot
+ parameters:
+ host: "{{host}}"
+ timeout: 60
diff --git a/laas-fog/pharoslaas/actions/workflows/fog_imageWorkflow.yaml b/laas-fog/pharoslaas/actions/workflows/fog_imageWorkflow.yaml
new file mode 100644
index 0000000..52eff63
--- /dev/null
+++ b/laas-fog/pharoslaas/actions/workflows/fog_imageWorkflow.yaml
@@ -0,0 +1,39 @@
+---
+chain:
+ -
+ name: "changeImage"
+ ref: "pharoslaas.fog_changeImage"
+ parameters:
+ image: "{{image}}"
+ host: "{{host}}"
+ os: "{{os}}"
+ on-success: "startImaging"
+
+ -
+ name: "startImaging"
+ ref: pharoslaas.fog_startImaging
+ parameters:
+ host: "{{host}}"
+ on-success: "restartHost"
+
+ -
+ name: "restartHost"
+ ref: pharoslaas.restartHost
+ parameters:
+ host: "{{host}}"
+ on-success: "waitForImaging"
+
+ -
+ name: "waitForImaging"
+ ref: pharoslaas.fog_waitForImaging
+ parameters:
+ host: "{{host}}"
+ timeout: 180
+ on-success: "waitForBoot"
+
+ -
+ name: "waitForBoot"
+ ref: pharoslaas.waitForBoot
+ parameters:
+ host: "{{host}}"
+ timeout: 60