Merge pull request #74 from xarses/stages

Fixes for stage commit processing
This commit is contained in:
Łukasz Oleś 2015-06-03 14:56:46 +02:00
commit 354ea71fdd
11 changed files with 99 additions and 49 deletions

20
cli.py
View File

@ -92,19 +92,13 @@ def init_cli_resource():
resource.add_command(show)
@click.command()
@click.argument('path')
@click.argument('name')
@click.argument('args')
def update(args, path):
print 'Update', path, args
def update(name, args):
args = json.loads(args)
# Need to load all resources for bubbling effect to take place
# TODO: resources can be scattered around, this is a simple
# situation when we assume resources are all in one directory
base_path, name = os.path.split(path)
all = xr.load_all(base_path)
all = xr.load_all()
r = all[name]
r.update(args)
resource.add_command(update)
@ -154,8 +148,12 @@ def init_changes():
changes.add_command(stage)
@click.command()
def commit():
operations.commit_changes()
@click.option('--one', is_flag=True, default=False)
def commit(one):
if one:
operations.commit_one()
else:
operations.commit_changes()
changes.add_command(commit)

View File

@ -202,11 +202,15 @@ def ensure_endpoint_present(keystone, name, public_url, internal_url,
def ensure_service_absent(keystone, name, check_mode):
""" Ensure the service is absent"""
raise NotImplementedError()
service = get_service(keystone, name)
keystone.services.delete(service.id)
return True
def ensure_endpoint_absent(keystone, name, check_mode):
""" Ensure the service endpoint """
raise NotImplementedError()
endpoint = get_endpoint(keystone, name)
keystone.endpoints.delete(endpoint.id)
return True
def dispatch(keystone, name, service_type, description, public_url,

View File

@ -15,6 +15,5 @@
- {{ admin_port }}:35357
volumes:
- {{ config_dir }}:/etc/keystone
- name: wait for keystone
wait_for: host={{ip}} port={{port}} timeout=20

View File

@ -4,7 +4,7 @@ version: 1.0.0
input:
image:
schema: str!
value: kollaglue/centos-rdo-j-keystone
value: kollaglue/centos-rdo-k-keystone
config_dir:
schema: str!
value: /etc/solar/keystone

View File

@ -1,6 +1,20 @@
- hosts: [{{ ip }}]
sudo: yes
vars:
ip: {{ip}}
port: {{port}}
admin_port: {{admin_port}}
tasks:
- name: keystone service and endpoint
#TODO: not implemented in module
pause: seconds=1
- name: remove keystone service and endpoint
keystone_service:
token: {{admin_token}}
name: {{name}}
type: {{type}}
description: {{description}}
publicurl: {{publicurl}}
internalurl: {{internalurl}}
adminurl: {{adminurl}}
region: "RegionOne"
state: present
endpoint: http://{{keystone_host}}:{{keystone_port}}/v2.0/

View File

@ -16,3 +16,4 @@
until: result.rc == 0
retries: 30
delay: 0.5

View File

@ -5,7 +5,7 @@ import handlers
def resource_action(resource, action):
handler = resource.metadata['handler']
with handlers.get(handler)([resource]) as h:
h.action(resource, action)
return h.action(resource, action)
def tag_action(tag, action):

View File

@ -3,6 +3,7 @@ import os
import subprocess
from solar.core.handlers.base import BaseHandler
from solar.state import STATES
class Ansible(BaseHandler):
@ -13,6 +14,7 @@ class Ansible(BaseHandler):
print 'playbook_file', playbook_file
call_args = ['ansible-playbook', '--module-path', '/vagrant/library', '-i', inventory_file, playbook_file]
print 'EXECUTING: ', ' '.join(call_args)
try:
subprocess.check_output(call_args)
except subprocess.CalledProcessError as e:

View File

@ -121,9 +121,10 @@ def disconnect(emitter, receiver):
for destination in destinations:
receiver_input = destination[1]
if receiver.args[receiver_input].type_ != 'list':
print 'Removing input {} from {}'.format(receiver_input, receiver.name)
emitter.args[src].unsubscribe(receiver.args[receiver_input])
if receiver_input in receiver.args:
if receiver.args[receiver_input].type_ != 'list':
print 'Removing input {} from {}'.format(receiver_input, receiver.name)
emitter.args[src].unsubscribe(receiver.args[receiver_input])
def disconnect_receiver_by_input(receiver, input):

View File

@ -11,6 +11,7 @@ db = get_db()
from dictdiffer import diff, patch, revert
import networkx as nx
import subprocess
def guess_action(from_, to):
@ -78,6 +79,55 @@ def stage_changes():
return log
def execute(res, action):
try:
actions.resource_action(res, action)
return state.STATES.success
except subprocess.CalledProcessError:
return state.STATES.error
def commit(li, resources):
commited = state.CD()
history = state.CL()
staged = state.SL()
staged_res = resources[li.res]
staged_data = patch(li.diff, commited.get(li.res, {}))
# TODO(dshulyak) think about this hack for update
if li.action == 'update':
commited_res = resource.Resource(
staged_res.name,
staged_res.metadata,
commited[li.res]['args'],
commited[li.res]['tags'])
result_state = execute(commited_res, 'remove')
if result_state is state.STATES.success:
result_state = execute(staged_res, 'run')
else:
result_state = execute(staged_res, li.action)
# resource_action return None in case there is no actions
result_state = result_state or state.STATES.success
commited[li.res] = staged_data
li.state = result_state
history.add(li)
if result_state is state.STATES.error:
raise Exception('Failed')
def commit_one():
staged = state.SL()
resources = resource.load_all()
commit(staged.popleft(), resources)
def commit_changes():
# just shortcut to test stuff
commited = state.CD()
@ -86,25 +136,7 @@ def commit_changes():
resources = resource.load_all()
while staged:
l = staged.popleft()
wrapper = resources[l.res]
staged_data = patch(l.diff, commited.get(l.res, {}))
# TODO(dshulyak) think about this hack for update
if l.action == 'update':
commited_args = commited[l.res]['args']
wrapper.update(commited_args)
actions.resource_action(wrapper, 'remove')
wrapper.update(staged_data.get('args', {}))
actions.resource_action(wrapper, 'run')
else:
actions.resource_action(wrapper, l.action)
commited[l.res] = staged_data
l.state = state.STATES.success
history.add(l)
commit(staged.popleft(), resources)
def rollback(log_item):
@ -128,7 +160,7 @@ def rollback(log_item):
log_item.res, df, guess_action(commited, staged))
log.add(log_item)
res = resource.wrap_resource(db.get_resource(log_item.res))
res = db.get_obj_resource(log_item.res)
res.update(staged.get('args', {}))
res.save()
@ -136,7 +168,7 @@ def rollback(log_item):
def rollback_uid(uid):
item = next(l for l in state.CL() if l.uuid == uid)
item = next(l for l in state.CL() if l.uid == uid)
return rollback(item)

View File

@ -75,10 +75,10 @@ class Log(object):
def __init__(self, path):
self.path = path
items = []
if path in db:
items = db[path]
else:
items = []
items = db[path] or items
self.items = deque([LogItem(
l['uid'], l['res'],
l['diff'], l['action'],
@ -120,10 +120,9 @@ class Data(collections.MutableMapping):
def __init__(self, path):
self.path = path
self.store = {}
if path in db:
self.store = db[path]
else:
self.store = {}
self.store = db[path] or self.store
def __getitem__(self, key):
return self.store[key]