Skip to content

Commit

Permalink
feat: cross configmap state movement
Browse files Browse the repository at this point in the history
  • Loading branch information
davidgiga1993 committed Jun 22, 2023
1 parent 2c6fa7e commit bb939a3
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 27 deletions.
26 changes: 13 additions & 13 deletions octoploy/octoploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from octoploy.config.Config import RootConfig, RunMode
from octoploy.deploy.AppDeploy import AppDeployment
from octoploy.processing.DecryptionProcessor import DecryptionProcessor
from octoploy.state.StateMover import StateMover
from octoploy.utils.Encryption import YmlEncrypter
from octoploy.utils.Log import Log

Expand Down Expand Up @@ -119,16 +120,13 @@ def list_state(args):


def move_state(args):
run_mode = RunMode()
source = args.items[0]
dest = args.items[1]
target_cm = args.to

root_config = load_project(args.config_dir)
root_config.initialize_state(run_mode)

state = root_config.get_state()
state.move(source, dest)
root_config.persist_state(run_mode)
mover = StateMover(root_config)
mover.move(source, dest, dest_configmap=target_cm)


def main():
Expand All @@ -155,14 +153,16 @@ def main():
state_list_parser = state_subparsers.add_parser('list')
state_list_parser.set_defaults(func=list_state)

state_list_parser = state_subparsers.add_parser('mv')
state_list_parser.set_defaults(func=move_state)
state_mv_parser = state_subparsers.add_parser('mv')
state_mv_parser.set_defaults(func=move_state)

state_list_parser.add_argument('items', help='Source and destination.\n'
'The format for an object is: octoployName/Namespace/k8sFqn\n'
'For example: "my-old-app/Namespace2/k8sFqn" '
'"my-new-app/Namespace2/k8sFqn"', nargs=2)
state_parser.set_defaults(func=move_state)
state_mv_parser.add_argument('items', help='Source and destination.\n'
'The format for an object is: octoployName/Namespace/k8sFqn\n'
'For example: "my-old-app/Namespace2/k8sFqn" '
'"my-new-app/Namespace2/k8sFqn"', nargs=2)
state_mv_parser.add_argument('--to', dest='to', help='Configmap where the state should be moved to (optional).'
'Format: configmapSuffix|namespace/configmapSuffix')
state_mv_parser.set_defaults(func=move_state)

encrypt_parser = subparsers.add_parser('encrypt', help='Encrypts k8s secrets objects')
encrypt_parser.add_argument('file', help='Yml file to be encrypted', nargs=1)
Expand Down
64 changes: 64 additions & 0 deletions octoploy/state/StateMover.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from typing import Optional, Tuple

from octoploy.config.Config import RootConfig, RunMode
from octoploy.state.StateTracking import StateTracking
from octoploy.utils.Log import Log


class StateMover(Log):
def __init__(self, source_config: RootConfig):
super().__init__(__name__)
self._sourceConfig = source_config

def move(self, source: str, dest: str, dest_configmap: Optional[str]):
"""
Moves the state from the given source to the given destination
:param source: Source
:param dest: Destination
:param dest_configmap: Different configmap which should receive the state
"""
if source.count('/') != dest.count('/'):
raise ValueError('Source and destination point to different path depths')

run_mode = RunMode()
self._sourceConfig.initialize_state(run_mode)
source_state = self._sourceConfig.get_state()

items_to_be_moved = source_state.get_items(source)
for item in items_to_be_moved:
key = item.get_key()
target = key.replace(source, dest)
self.log.info(f'Moving {key} to {target}')
item.update_from_key(target)
source_state.remove_key(key)

target_state = source_state
target_namespace = self._sourceConfig.get_namespace_name()
if dest_configmap is not None:
target_state, target_namespace = self._get_state_from_cm(dest_configmap)

for item in items_to_be_moved:
target_state.add(item)

if len(items_to_be_moved) == 0:
self.log.warning('No items moved')
return

# First persist the target to prevent data loss on error
if target_state != source_state:
target_state.store(target_namespace)
source_state.store(self._sourceConfig.get_namespace_name())

def _get_state_from_cm(self, configmap: str) -> Tuple[StateTracking, str]:
namespace = self._sourceConfig.get_namespace_name()
segments = configmap.split('/', 1)
if len(segments) == 2:
namespace = segments[0]
cm_suffix = segments[1]
else:
cm_suffix = segments[0]

api = self._sourceConfig.create_api()
state = StateTracking(api, name_suffix=cm_suffix)
state.restore(namespace)
return state, namespace
32 changes: 18 additions & 14 deletions octoploy/state/StateTracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,21 +111,28 @@ def store(self, namespace: str):
yml = YmlWriter.dump(data)
self._k8s_api.apply(yml, namespace=namespace)

def move(self, source: str, dest: str):
if source.count('/') != dest.count('/'):
raise ValueError('Source and destination point to different path depths')
def add(self, object_state: ObjectState):
self._state[object_state.get_key()] = object_state

def remove(self, object_state: ObjectState):
del self._state[object_state.get_key()]

def remove_key(self, key: str):
del self._state[key]

def get_items(self, prefix: str) -> List[ObjectState]:
"""
Returns all state items which start with the given prefix
:param prefix: Prefix
:return: Items
"""
items = []
for value in list(self._state.values()):
key = value.get_key()
if not key.startswith(source):
if not key.startswith(prefix):
continue
target = key.replace(source, dest)
self.log.info(f'Moving {key} to {target}')
value.update_from_key(target)

if key in self._state:
del self._state[key]
self._state[target] = value
items.append(value)
return items

def get_not_visited(self, context: str) -> List[ObjectState]:
"""
Expand Down Expand Up @@ -172,9 +179,6 @@ def visit_only(self, context_name: str, k8s_object):
if existing_state is not None:
existing_state.visited = True

def remove(self, object_state: ObjectState):
del self._state[object_state.get_key()]

def print(self):
self.log.info(f'State content of ConfigMap {self._cm_name}')
for key, value in self._state.items():
Expand Down

0 comments on commit bb939a3

Please sign in to comment.