 17bf3db06a
			
		
	
	17bf3db06a
	
	
	
		
			
			Remove line containing comment - # vim: tabstop=4 shiftwidth=4 softtabstop=4 Change-Id: I7581cc88b8de433d5609ed06c6570b0b45c13573 Closes-Bug:#1229324
		
			
				
	
	
		
			164 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			164 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| #    Copyright (C) 2013 Yahoo! Inc. All Rights Reserved.
 | |
| #
 | |
| #    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 contextlib
 | |
| import hashlib
 | |
| import logging
 | |
| import os
 | |
| import random
 | |
| import sys
 | |
| import time
 | |
| 
 | |
| logging.basicConfig(level=logging.ERROR)
 | |
| 
 | |
| self_dir = os.path.abspath(os.path.dirname(__file__))
 | |
| top_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
 | |
|                                        os.pardir,
 | |
|                                        os.pardir))
 | |
| sys.path.insert(0, top_dir)
 | |
| sys.path.insert(0, self_dir)
 | |
| 
 | |
| from taskflow.patterns import graph_flow as gf
 | |
| from taskflow.patterns import linear_flow as lf
 | |
| 
 | |
| from taskflow import engines
 | |
| from taskflow import task
 | |
| 
 | |
| from taskflow.utils import persistence_utils as p_utils
 | |
| 
 | |
| import example_utils  # noqa
 | |
| 
 | |
| # INTRO: This examples shows how a hierarchy of flows can be used to create a
 | |
| # pseudo-volume in a reliable & resumable manner using taskflow + a miniature
 | |
| # version of what cinder does while creating a volume (very miniature).
 | |
| 
 | |
| 
 | |
| @contextlib.contextmanager
 | |
| def slow_down(how_long=0.5):
 | |
|     try:
 | |
|         yield how_long
 | |
|     finally:
 | |
|         print("** Ctrl-c me please!!! **")
 | |
|         time.sleep(how_long)
 | |
| 
 | |
| 
 | |
| def find_flow_detail(backend, book_id, flow_id):
 | |
|     # NOTE(harlowja): this is used to attempt to find a given logbook with
 | |
|     # a given id and a given flow details inside that logbook, we need this
 | |
|     # reference so that we can resume the correct flow (as a logbook tracks
 | |
|     # flows and a flow detail tracks a individual flow).
 | |
|     #
 | |
|     # Without a reference to the logbook and the flow details in that logbook
 | |
|     # we will not know exactly what we should resume and that would mean we
 | |
|     # can't resume what we don't know.
 | |
|     with contextlib.closing(backend.get_connection()) as conn:
 | |
|         lb = conn.get_logbook(book_id)
 | |
|         return lb.find(flow_id)
 | |
| 
 | |
| 
 | |
| class PrintText(task.Task):
 | |
|     def __init__(self, print_what, no_slow=False):
 | |
|         content_hash = hashlib.md5(print_what.encode('utf-8')).hexdigest()[0:8]
 | |
|         super(PrintText, self).__init__(name="Print: %s" % (content_hash))
 | |
|         self._text = print_what
 | |
|         self._no_slow = no_slow
 | |
| 
 | |
|     def execute(self):
 | |
|         if self._no_slow:
 | |
|             print("-" * (len(self._text)))
 | |
|             print(self._text)
 | |
|             print("-" * (len(self._text)))
 | |
|         else:
 | |
|             with slow_down():
 | |
|                 print("-" * (len(self._text)))
 | |
|                 print(self._text)
 | |
|                 print("-" * (len(self._text)))
 | |
| 
 | |
| 
 | |
| class CreateSpecForVolumes(task.Task):
 | |
|     def execute(self):
 | |
|         volumes = []
 | |
|         for i in range(0, random.randint(1, 10)):
 | |
|             volumes.append({
 | |
|                 'type': 'disk',
 | |
|                 'location': "/dev/vda%s" % (i + 1),
 | |
|             })
 | |
|         return volumes
 | |
| 
 | |
| 
 | |
| class PrepareVolumes(task.Task):
 | |
|     def execute(self, volume_specs):
 | |
|         for v in volume_specs:
 | |
|             with slow_down():
 | |
|                 print("Dusting off your hard drive %s" % (v))
 | |
|             with slow_down():
 | |
|                 print("Taking a well deserved break.")
 | |
|             print("Your drive %s has been certified." % (v))
 | |
| 
 | |
| 
 | |
| # Setup the set of things to do (mini-cinder).
 | |
| flow = lf.Flow("root").add(
 | |
|     PrintText("Starting volume create", no_slow=True),
 | |
|     gf.Flow('maker').add(
 | |
|         CreateSpecForVolumes("volume_specs", provides='volume_specs'),
 | |
|         PrintText("I need a nap, it took me a while to build those specs."),
 | |
|         PrepareVolumes(),
 | |
|     ),
 | |
|     PrintText("Finished volume create", no_slow=True))
 | |
| 
 | |
| # Setup the persistence & resumption layer.
 | |
| with example_utils.get_backend() as backend:
 | |
|     try:
 | |
|         book_id, flow_id = sys.argv[2].split("+", 1)
 | |
|     except (IndexError, ValueError):
 | |
|         book_id = None
 | |
|         flow_id = None
 | |
| 
 | |
|     if not all([book_id, flow_id]):
 | |
|         # If no 'tracking id' (think a fedex or ups tracking id) is provided
 | |
|         # then we create one by creating a logbook (where flow details are
 | |
|         # stored) and creating a flow detail (where flow and task state is
 | |
|         # stored). The combination of these 2 objects unique ids (uuids) allows
 | |
|         # the users of taskflow to reassociate the workflows that were
 | |
|         # potentially running (and which may have partially completed) back
 | |
|         # with taskflow so that those workflows can be resumed (or reverted)
 | |
|         # after a process/thread/engine has failed in someway.
 | |
|         logbook = p_utils.temporary_log_book(backend)
 | |
|         flow_detail = p_utils.create_flow_detail(flow, logbook, backend)
 | |
|         print("!! Your tracking id is: '%s+%s'" % (logbook.uuid,
 | |
|                                                    flow_detail.uuid))
 | |
|         print("!! Please submit this on later runs for tracking purposes")
 | |
|     else:
 | |
|         flow_detail = find_flow_detail(backend, book_id, flow_id)
 | |
| 
 | |
|     # Load and run.
 | |
|     engine_conf = {
 | |
|         'engine': 'serial',
 | |
|     }
 | |
|     engine = engines.load(flow,
 | |
|                           flow_detail=flow_detail,
 | |
|                           backend=backend,
 | |
|                           engine_conf=engine_conf)
 | |
|     engine.run()
 | |
| 
 | |
| # How to use.
 | |
| #
 | |
| # 1. $ python me.py "sqlite:////tmp/cinder.db"
 | |
| # 2. ctrl-c before this finishes
 | |
| # 3. Find the tracking id (search for 'Your tracking id is')
 | |
| # 4. $ python me.py "sqlite:////tmp/cinder.db" "$tracking_id"
 | |
| # 5. Profit!
 |