Skip to content

Commit

Permalink
mgr/volumes: add operation state machine table
Browse files Browse the repository at this point in the history
... and fetch creation state from state machine table.

Signed-off-by: Venky Shankar <vshankar@redhat.com>
  • Loading branch information
vshankar committed Jan 31, 2020
1 parent 90eb673 commit 46f29bf
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 3 deletions.
8 changes: 8 additions & 0 deletions src/pybind/mgr/volumes/fs/exception.py
Expand Up @@ -16,3 +16,11 @@ def __init__(self, error_code, error_message):

def __str__(self):
return "{0} ({1})".format(self.errno, self.error_str)

class OpSmException(Exception):
def __init__(self, error_code, error_message):
self.errno = error_code
self.error_str = error_message

def __str__(self):
return "{0} ({1})".format(self.errno, self.error_str)
50 changes: 50 additions & 0 deletions src/pybind/mgr/volumes/fs/operations/op_sm.py
@@ -0,0 +1,50 @@
from ..exception import OpSmException

class OpSm(object):
INIT_STATE_KEY = 'init'

FAILED_STATE = 'failed'
FINAL_STATE = 'complete'

OP_SM_SUBVOLUME = {
INIT_STATE_KEY : FINAL_STATE,
}

OP_SM_CLONE = {
INIT_STATE_KEY : 'pending',
'pending' : ('in-progress', FAILED_STATE),
'in-progress' : (FINAL_STATE, FAILED_STATE),
}

STATE_MACHINES_TYPES = {
"subvolume" : OP_SM_SUBVOLUME,
"clone" : OP_SM_CLONE,
}

@staticmethod
def is_final_state(state):
return state == OpSm.FINAL_STATE

@staticmethod
def is_failed_state(state):
return state == OpSm.FAILED_STATE

@staticmethod
def get_init_state(stm_type):
stm = OpSm.STATE_MACHINES_TYPES.get(stm_type, None)
if not stm:
raise OpSmException(-errno.ENOENT, "state machine type '{0}' not found".format(stm_type))
init_state = stm.get(OpSm.INIT_STATE_KEY, None)
if not init_state:
raise OpSmException(-errno.ENOENT, "initial state unavailable for state machine '{0}'".format(stm_type))
return init_state

@staticmethod
def get_next_state(stm_type, current_state, ret):
stm = OpSm.STATE_MACHINES_TYPES.get(stm_type, None)
if not stm:
raise OpSmException(-errno.ENOENT, "state machine type '{0}' not found".format(stm_type))
next_state = stm.get(current_state, None)
if not next_state:
raise OpSmException(-errno.EINVAL, "invalid current state '{0}'".format(current_state))
return next_state[0] if ret == 0 else next_state[1]
8 changes: 7 additions & 1 deletion src/pybind/mgr/volumes/fs/operations/versions/__init__.py
Expand Up @@ -5,6 +5,7 @@
import cephfs

from .subvolume_base import SubvolumeBase
from ..op_sm import OpSm
from ...exception import VolumeException, MetadataMgrException

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -49,8 +50,13 @@ def upgrade_legacy_subvolume(self, fs, subvolume):
fs.mkdirs(subvolume.legacy_dir, 0o700)
except cephfs.Error as e:
raise VolumeException(-e.args[0], "error accessing subvolume")
subvolume_type = SubvolumeBase.SUBVOLUME_TYPE_NORMAL
try:
initial_state = OpSm.get_init_state(subvolume_type)
except OpSmException as oe:
raise VolumeException(-errno.EINVAL, "subvolume creation failed: internal error")
qpath = subvolume.base_path.decode('utf-8')
subvolume.init_config(self.max_version, SubvolumeBase.SUBVOLUME_TYPE_NORMAL, qpath, "complete")
subvolume.init_config(self.max_version, subvolume_type, qpath, initial_state)

def get_subvolume_object(self, fs, vol_spec, group, subvolname, upgrade=True):
subvolume = SubvolumeBase(fs, vol_spec, group, subvolname)
Expand Down
11 changes: 9 additions & 2 deletions src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py
Expand Up @@ -6,9 +6,10 @@
import cephfs

from .subvolume_base import SubvolumeBase
from ..op_sm import OpSm
from ..template import SubvolumeTemplate
from ..snapshot_util import mksnap, rmsnap
from ...exception import VolumeException, MetadataMgrException
from ...exception import OpSmException, VolumeException, MetadataMgrException
from ...fs_util import listdir

log = logging.getLogger(__name__)
Expand All @@ -29,6 +30,12 @@ def path(self):
raise VolumeException(-errno.EINVAL, "error fetching subvolume metadata")

def create(self, size, isolate_nspace, pool, mode, uid, gid):
subvolume_type = SubvolumeBase.SUBVOLUME_TYPE_NORMAL
try:
initial_state = OpSm.get_init_state(subvolume_type)
except OpSmException as oe:
raise VolumeException(-errno.EINVAL, "subvolume creation failed: internal error")

subvol_path = os.path.join(self.base_path, str(uuid.uuid4()).encode('utf-8'))
try:
# create directory and set attributes
Expand All @@ -37,7 +44,7 @@ def create(self, size, isolate_nspace, pool, mode, uid, gid):

# persist subvolume metadata
qpath = subvol_path.decode('utf-8')
self.init_config(SubvolumeV1.VERSION, "subvolume", qpath, "complete")
self.init_config(SubvolumeV1.VERSION, subvolume_type, qpath, initial_state)
except (VolumeException, MetadataMgrException, cephfs.Error) as e:
try:
log.info("cleaning up subvolume with path: {0}".format(self.subvolname))
Expand Down

0 comments on commit 46f29bf

Please sign in to comment.