diff options
| -rw-r--r-- | cli/src/cli-cmd-parser.c | 3 | ||||
| -rwxr-xr-x | ufo/bin/gluster-swift-gen-builders | 39 | ||||
| -rw-r--r-- | ufo/gluster/swift/common/Glusterfs.py | 2 | ||||
| -rw-r--r-- | ufo/gluster/swift/common/constraints.py | 9 | ||||
| -rw-r--r-- | ufo/gluster/swift/common/ring.py | 82 | ||||
| -rw-r--r-- | ufo/test/unit/common/test_ring.py | 43 | 
6 files changed, 168 insertions, 10 deletions
diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 8725b79f6f7..c09aa6260fa 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -166,7 +166,8 @@ cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options                                  NULL };          char    *invalid_volnames[] = {"volume", "type", "subvolumes", "option", -                                      "end-volume", "all", NULL}; +                                       "end-volume", "all", "volume_not_in_ring", +                                       NULL};          char    *w = NULL;          int      op_count = 0;          int32_t  replica_count = 1; diff --git a/ufo/bin/gluster-swift-gen-builders b/ufo/bin/gluster-swift-gen-builders index b89cd15fb00..37ed50dc302 100755 --- a/ufo/bin/gluster-swift-gen-builders +++ b/ufo/bin/gluster-swift-gen-builders @@ -1,9 +1,25 @@  #!/bin/bash +# Note that these port numbers must match the configured values for the +# various servers in their configuration files. +declare -A port=(["account.builder"]=6012 ["container.builder"]=6011 \ +    ["object.builder"]=6010) + +builder_files="account.builder container.builder object.builder" +  function create { -    swift-ring-builder $1 create 0 1 1 -    swift-ring-builder $1 add z1-127.0.0.1:$2/$3_ 100.0 +    swift-ring-builder $1 create 1 1 1 >> /tmp/out +} + +function add { +    swift-ring-builder $1 add z$2-127.0.0.1:$3/$4_ 100.0 +} + +function rebalance {      swift-ring-builder $1 rebalance +} + +function build {      swift-ring-builder $1  } @@ -12,8 +28,17 @@ if [ "$1x" = "x" ]; then      exit 1  fi -# Note that these port numbers must match the configured values for the -# various servers in their configuration files. -create account.builder 6012 $1 -create container.builder 6011 $1 -create object.builder 6010 $1 +for builder_file in $builder_files +do +    create $builder_file + +    zone=1 +    for volname in $@ +    do +	add $builder_file $zone ${port[$builder_file]} $volname +	zone=$(expr $zone + 1) +    done + +    rebalance $builder_file +    build $builder_file +done diff --git a/ufo/gluster/swift/common/Glusterfs.py b/ufo/gluster/swift/common/Glusterfs.py index 5b49e743d97..ce2c8e1aa59 100644 --- a/ufo/gluster/swift/common/Glusterfs.py +++ b/ufo/gluster/swift/common/Glusterfs.py @@ -67,7 +67,7 @@ def mount(root, drive):          if drive == export:              break      else: -        logging.error('No export found in %r matching drive %s', el, drive) +        logging.error('No export found in %r matching drive, %s', el, drive)          return False      # NOTE: root is typically the default value of /mnt/gluster-object diff --git a/ufo/gluster/swift/common/constraints.py b/ufo/gluster/swift/common/constraints.py index a4fc8008c7e..dd8662a9d43 100644 --- a/ufo/gluster/swift/common/constraints.py +++ b/ufo/gluster/swift/common/constraints.py @@ -16,7 +16,8 @@  from webob.exc import HTTPBadRequest  import swift.common.constraints -from gluster.swift.common import Glusterfs +import swift.common.ring as _ring +from gluster.swift.common import Glusterfs, ring  MAX_OBJECT_NAME_COMPONENT_LENGTH = swift.common.constraints.constraints_conf_int( @@ -80,3 +81,9 @@ def gluster_check_mount(root, drive):  # Replace the original check mount with ours  swift.common.constraints.check_mount = gluster_check_mount + +# Save the original Ring class +__Ring = _ring.Ring + +# Replace the original Ring class +_ring.Ring = ring.Ring diff --git a/ufo/gluster/swift/common/ring.py b/ufo/gluster/swift/common/ring.py new file mode 100644 index 00000000000..9bac39c751b --- /dev/null +++ b/ufo/gluster/swift/common/ring.py @@ -0,0 +1,82 @@ +# Copyright (c) 2013 Red Hat, Inc. +# +# 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 ConfigParser import ConfigParser +from swift.common.ring import ring +from swift.common.utils import search_tree +from gluster.swift.common.Glusterfs import SWIFT_DIR + +reseller_prefix = "AUTH_" +conf_files = search_tree(SWIFT_DIR, "proxy-server*", 'conf') +if conf_files: +    conf_file = conf_files[0] + +_conf = ConfigParser() +if conf_files and _conf.read(conf_file): +    if _conf.defaults().get("reseller_prefix", None): +        reseller_prefix = _conf.defaults().get("reseller_prefix") +    else: +        for key, value in _conf._sections.items(): +            if value.get("reseller_prefix", None): +                reseller_prefix = value["reseller_prefix"] +                break + +if not reseller_prefix.endswith('_'): +    reseller_prefix = reseller_prefix + '_' + +class Ring(ring.Ring): +    def get_nodes(self, account, container=None, obj=None): +        """ +        Get the partition and nodes for an account/container/object. +        If a node is responsible for more than one replica, it will +        only appear in the output once. +        :param account: account name +        :param container: container name +        :param obj: object name +        :returns: a tuple of (partition, list of node dicts) + +        Each node dict will have at least the following keys: +        ======  =============================================================== +        id      unique integer identifier amongst devices +        weight  a float of the relative weight of this device as compared to +                others; this indicates how many partitions the builder will try +                to assign to this device +        zone    integer indicating which zone the device is in; a given +                partition will not be assigned to multiple devices within the +                same zone +        ip      the ip address of the device +        port    the tcp port of the device +        device  the device's name on disk (sdb1, for example) +        meta    general use 'extra' field; for example: the online date, the +                hardware description +        ======  =============================================================== +        """ +        false_node = [{'zone': 1, 'weight': 100.0, 'ip': '127.0.0.1', 'id': 0, \ +                           'meta': '', 'device': 'volume_not_in_ring', \ +                           'port': 6012}] +        if account.startswith(reseller_prefix): +            acc_name = account.replace(reseller_prefix, '', 1) +        else: +            acc_name = account + +        part = 0 +        seen_ids = set() +        nodes = [dev for dev in self._devs \ +                     if dev['device'] == acc_name \ +                     and not (dev['id'] in seen_ids \ +                                  or seen_ids.add(dev['id']))] +        if not nodes: +            nodes = false_node +        return part, nodes diff --git a/ufo/test/unit/common/test_ring.py b/ufo/test/unit/common/test_ring.py new file mode 100644 index 00000000000..d3dac609c59 --- /dev/null +++ b/ufo/test/unit/common/test_ring.py @@ -0,0 +1,43 @@ +# Copyright (c) 2013 Red Hat, Inc. +# +# 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 unittest +import gluster.swift.common.constraints +from gluster.swift.common.ring import * +from gluster.swift.common.Glusterfs import SWIFT_DIR + +def _mock_ring_data(): +    return [{'zone': 1, 'weight': 100.0, 'ip': '127.0.0.1', 'port': 6012, \ +                 'meta': '', 'device': 'test', 'id': 0}, +            {'zone': 2, 'weight': 100.0, 'ip': '127.0.0.1', 'id': 1, \ +                 'meta': '', 'device': 'iops', 'port': 6012}] + +class TestRing(unittest.TestCase): +    """ Tests for common.utils """ + +    def setUp(self): +        self.ring = Ring(SWIFT_DIR, ring_name='object') + +    def test_get_notes(self): +        try: +            __devs = self.ring._devs +            self.ring._devs = _mock_ring_data() +            part, node = self.ring.get_nodes('test') +            assert node[0]['device'] == 'test' +            part, node = self.ring.get_nodes('test2') +            assert node +            assert node[0]['device'] == 'volume' +        finally: +            self.ring._devs = __devs  | 
