garage_2: init at 2.0.0, move tests to runTest (#417549)

authored by Adam C. Stephens and committed by GitHub 0e6feffe 0acbb41a

+203 -231
+8 -1
nixos/tests/all-tests.nix
··· 543 mimir = runTest ./mimir.nix; 544 galene = discoverTests (import ./galene.nix); 545 gancio = runTest ./gancio.nix; 546 - garage = handleTest ./garage { }; 547 gatus = runTest ./gatus.nix; 548 getaddrinfo = runTest ./getaddrinfo.nix; 549 gemstash = handleTest ./gemstash.nix { };
··· 543 mimir = runTest ./mimir.nix; 544 galene = discoverTests (import ./galene.nix); 545 gancio = runTest ./gancio.nix; 546 + garage_1 = import ./garage { 547 + inherit runTest; 548 + package = pkgs.garage_1; 549 + }; 550 + garage_2 = import ./garage { 551 + inherit runTest; 552 + package = pkgs.garage_2; 553 + }; 554 gatus = runTest ./gatus.nix; 555 getaddrinfo = runTest ./getaddrinfo.nix; 556 gemstash = handleTest ./gemstash.nix { };
+27 -93
nixos/tests/garage/basic.nix
··· 1 - args@{ mkNode, ver, ... }: 2 - (import ../make-test-python.nix ( 3 - { pkgs, ... }: 4 - { 5 - name = "garage-basic"; 6 - meta = { 7 - maintainers = with pkgs.lib.maintainers; [ raitobezarius ]; 8 - }; 9 10 - nodes = { 11 - single_node = mkNode { replicationMode = "none"; }; 12 }; 13 - 14 - testScript = '' 15 - from typing import List 16 - from dataclasses import dataclass 17 - import re 18 - 19 - start_all() 20 - 21 - cur_version_regex = re.compile('Current cluster layout version: (?P<ver>\d*)') 22 - key_creation_regex = re.compile('Key name: (?P<key_name>.*)\nKey ID: (?P<key_id>.*)\nSecret key: (?P<secret_key>.*)') 23 - 24 - @dataclass 25 - class S3Key: 26 - key_name: str 27 - key_id: str 28 - secret_key: str 29 - 30 - @dataclass 31 - class GarageNode: 32 - node_id: str 33 - host: str 34 - 35 - def get_node_fqn(machine: Machine) -> GarageNode: 36 - node_id, host = machine.succeed("garage node id").split('@') 37 - return GarageNode(node_id=node_id, host=host) 38 - 39 - def get_node_id(machine: Machine) -> str: 40 - return get_node_fqn(machine).node_id 41 - 42 - def get_layout_version(machine: Machine) -> int: 43 - version_data = machine.succeed("garage layout show") 44 - m = cur_version_regex.search(version_data) 45 - if m and m.group('ver') is not None: 46 - return int(m.group('ver')) + 1 47 - else: 48 - raise ValueError('Cannot find current layout version') 49 - 50 - def apply_garage_layout(machine: Machine, layouts: List[str]): 51 - for layout in layouts: 52 - machine.succeed(f"garage layout assign {layout}") 53 - version = get_layout_version(machine) 54 - machine.succeed(f"garage layout apply --version {version}") 55 - 56 - def create_api_key(machine: Machine, key_name: str) -> S3Key: 57 - output = machine.succeed(f"garage key ${ 58 - if ver == "0_8" then "new --name" else "create" 59 - } {key_name}") 60 - m = key_creation_regex.match(output) 61 - if not m or not m.group('key_id') or not m.group('secret_key'): 62 - raise ValueError('Cannot parse API key data') 63 - return S3Key(key_name=key_name, key_id=m.group('key_id'), secret_key=m.group('secret_key')) 64 - 65 - def get_api_key(machine: Machine, key_pattern: str) -> S3Key: 66 - output = machine.succeed(f"garage key info {key_pattern}") 67 - m = key_creation_regex.match(output) 68 - if not m or not m.group('key_name') or not m.group('key_id') or not m.group('secret_key'): 69 - raise ValueError('Cannot parse API key data') 70 - return S3Key(key_name=m.group('key_name'), key_id=m.group('key_id'), secret_key=m.group('secret_key')) 71 - 72 - def test_bucket_writes(node): 73 - node.succeed("garage bucket create test-bucket") 74 - s3_key = create_api_key(node, "test-api-key") 75 - node.succeed("garage bucket allow --read --write test-bucket --key test-api-key") 76 - other_s3_key = get_api_key(node, 'test-api-key') 77 - assert other_s3_key.secret_key == other_s3_key.secret_key 78 - node.succeed( 79 - f"mc alias set test-garage http://[::1]:3900 {s3_key.key_id} {s3_key.secret_key} --api S3v4" 80 - ) 81 - node.succeed("echo test | mc pipe test-garage/test-bucket/test.txt") 82 - assert node.succeed("mc cat test-garage/test-bucket/test.txt").strip() == "test" 83 - 84 - def test_bucket_over_http(node, bucket='test-bucket', url=None): 85 - if url is None: 86 - url = f"{bucket}.web.garage" 87 88 - node.succeed(f'garage bucket website --allow {bucket}') 89 - node.succeed(f'echo hello world | mc pipe test-garage/{bucket}/index.html') 90 - assert (node.succeed(f"curl -H 'Host: {url}' http://localhost:3902")).strip() == 'hello world' 91 92 with subtest("Garage works as a single-node S3 storage"): 93 single_node.wait_for_unit("garage.service") 94 single_node.wait_for_open_port(3900) 95 # Now Garage is initialized. 96 single_node_id = get_node_id(single_node) 97 - apply_garage_layout(single_node, [f'-z qemutest -c ${ 98 - if ver == "0_8" then "1" else "1G" 99 - } "{single_node_id}"']) 100 # Now Garage is operational. 101 test_bucket_writes(single_node) 102 test_bucket_over_http(single_node) 103 ''; 104 - } 105 - )) 106 - args
··· 1 + { 2 + lib, 3 + mkNode, 4 + package, 5 + testScriptSetup, 6 + ... 7 + }: 8 + { 9 + name = "garage-basic"; 10 11 + nodes = { 12 + single_node = mkNode { 13 + extraSettings = 14 + if (lib.versionAtLeast package.version "2") then 15 + { 16 + replication_factor = 1; 17 + consistency_mode = "consistent"; 18 + } 19 + else 20 + { 21 + replication_mode = "none"; 22 + }; 23 }; 24 + }; 25 26 + testScript = # python 27 + '' 28 + ${testScriptSetup} 29 30 with subtest("Garage works as a single-node S3 storage"): 31 single_node.wait_for_unit("garage.service") 32 single_node.wait_for_open_port(3900) 33 # Now Garage is initialized. 34 single_node_id = get_node_id(single_node) 35 + apply_garage_layout(single_node, [f'-z qemutest -c 1G "{single_node_id}"']) 36 # Now Garage is operational. 37 test_bucket_writes(single_node) 38 test_bucket_over_http(single_node) 39 ''; 40 + }
+85
nixos/tests/garage/common.nix
···
··· 1 + { ... }: 2 + { 3 + _module.args.testScriptSetup = # python 4 + '' 5 + from typing import List 6 + from dataclasses import dataclass 7 + import re 8 + 9 + start_all() 10 + 11 + cur_version_regex = re.compile(r'Current cluster layout version: (?P<ver>\d*)') 12 + 13 + @dataclass 14 + class S3Key: 15 + key_name: str 16 + key_id: str 17 + secret_key: str 18 + 19 + @dataclass 20 + class GarageNode: 21 + node_id: str 22 + host: str 23 + 24 + def get_node_fqn(machine: Machine) -> GarageNode: 25 + node_id, host = machine.succeed("garage node id").split('@') 26 + return GarageNode(node_id=node_id, host=host) 27 + 28 + def get_node_id(machine: Machine) -> str: 29 + return get_node_fqn(machine).node_id 30 + 31 + def get_layout_version(machine: Machine) -> int: 32 + version_data = machine.succeed("garage layout show") 33 + m = cur_version_regex.search(version_data) 34 + if m and m.group('ver') is not None: 35 + return int(m.group('ver')) + 1 36 + else: 37 + raise ValueError('Cannot find current layout version') 38 + 39 + def apply_garage_layout(machine: Machine, layouts: List[str]): 40 + for layout in layouts: 41 + machine.succeed(f"garage layout assign {layout}") 42 + version = get_layout_version(machine) 43 + machine.succeed(f"garage layout apply --version {version}") 44 + 45 + def create_api_key(machine: Machine, key_name: str) -> S3Key: 46 + output = machine.succeed(f"garage key create {key_name}") 47 + return parse_api_key_data(output) 48 + 49 + def get_api_key(machine: Machine, key_pattern: str) -> S3Key: 50 + output = machine.succeed(f"garage key info {key_pattern}") 51 + return parse_api_key_data(output) 52 + 53 + def parse_api_key_data(text) -> S3Key: 54 + key_creation_regex = re.compile(r'Key name: \s*(?P<key_name>.*)|' r'Key ID: \s*(?P<key_id>.*)|' r'Secret key: \s*(?P<secret_key>.*)', re.IGNORECASE) 55 + fields = {} 56 + for match in key_creation_regex.finditer(text): 57 + for key, value in match.groupdict().items(): 58 + if value: 59 + fields[key] = value.strip() 60 + try: 61 + return S3Key(**fields) 62 + except TypeError as e: 63 + raise ValueError(f"Cannot parse API key data. Missing required field(s): {e}") 64 + 65 + def test_bucket_writes(node): 66 + node.succeed("garage bucket create test-bucket") 67 + s3_key = create_api_key(node, "test-api-key") 68 + node.succeed("garage bucket allow --read --write test-bucket --key test-api-key") 69 + other_s3_key = get_api_key(node, 'test-api-key') 70 + assert other_s3_key.secret_key == other_s3_key.secret_key 71 + node.succeed( 72 + f"mc alias set test-garage http://[::1]:3900 {s3_key.key_id} {s3_key.secret_key} --api S3v4" 73 + ) 74 + node.succeed("echo test | mc pipe test-garage/test-bucket/test.txt") 75 + assert node.succeed("mc cat test-garage/test-bucket/test.txt").strip() == "test" 76 + 77 + def test_bucket_over_http(node, bucket='test-bucket', url=None): 78 + if url is None: 79 + url = f"{bucket}.web.garage" 80 + 81 + node.succeed(f'garage bucket website --allow {bucket}') 82 + node.succeed(f'echo hello world | mc pipe test-garage/{bucket}/index.html') 83 + assert (node.succeed(f"curl -H 'Host: {url}' http://localhost:3902")).strip() == 'hello world' 84 + ''; 85 + }
+25 -31
nixos/tests/garage/default.nix
··· 1 { 2 - system ? builtins.currentSystem, 3 - config ? { }, 4 - pkgs ? import ../../.. { inherit system config; }, 5 }: 6 - with pkgs.lib; 7 - 8 let 9 mkNode = 10 - package: 11 { 12 - replicationMode, 13 publicV6Address ? "::1", 14 }: 15 { pkgs, ... }: 16 { ··· 30 enable = true; 31 inherit package; 32 settings = { 33 - replication_mode = replicationMode; 34 - 35 rpc_bind_addr = "[::]:3901"; 36 rpc_public_addr = "[${publicV6Address}]:3901"; 37 rpc_secret = "5c1915fa04d0b6739675c61bf5907eb0fe3d9c69850c83820f51b4d25d13868c"; ··· 47 root_domain = ".web.garage"; 48 index = "index.html"; 49 }; 50 - }; 51 }; 52 environment.systemPackages = [ pkgs.minio-client ]; 53 ··· 55 virtualisation.diskSize = 2 * 1024; 56 }; 57 in 58 - foldl 59 - ( 60 - matrix: ver: 61 - matrix 62 - // { 63 - "basic${toString ver}" = import ./basic.nix { 64 - inherit system pkgs ver; 65 - mkNode = mkNode pkgs."garage_${ver}"; 66 - }; 67 - "with-3node-replication${toString ver}" = import ./with-3node-replication.nix { 68 - inherit system pkgs ver; 69 - mkNode = mkNode pkgs."garage_${ver}"; 70 - }; 71 - } 72 - ) 73 - { } 74 - [ 75 - "0_8" 76 - "0_9" 77 - "1_x" 78 - ]
··· 1 { 2 + runTest, 3 + package, 4 }: 5 let 6 mkNode = 7 { 8 publicV6Address ? "::1", 9 + extraSettings ? { }, 10 }: 11 { pkgs, ... }: 12 { ··· 26 enable = true; 27 inherit package; 28 settings = { 29 rpc_bind_addr = "[::]:3901"; 30 rpc_public_addr = "[${publicV6Address}]:3901"; 31 rpc_secret = "5c1915fa04d0b6739675c61bf5907eb0fe3d9c69850c83820f51b4d25d13868c"; ··· 41 root_domain = ".web.garage"; 42 index = "index.html"; 43 }; 44 + } // extraSettings; 45 }; 46 environment.systemPackages = [ pkgs.minio-client ]; 47 ··· 49 virtualisation.diskSize = 2 * 1024; 50 }; 51 in 52 + { 53 + basic = runTest { 54 + imports = [ 55 + ./common.nix 56 + ./basic.nix 57 + ]; 58 + _module.args = { 59 + inherit mkNode package; 60 + }; 61 + }; 62 + 63 + with-3node-replication = runTest { 64 + imports = [ 65 + ./common.nix 66 + ./with-3node-replication.nix 67 + ]; 68 + _module.args = { 69 + inherit mkNode package; 70 + }; 71 + }; 72 + }
+43 -105
nixos/tests/garage/with-3node-replication.nix
··· 1 - args@{ mkNode, ver, ... }: 2 - (import ../make-test-python.nix ( 3 - { pkgs, ... }: 4 - { 5 - name = "garage-3node-replication"; 6 - meta = { 7 - maintainers = with pkgs.lib.maintainers; [ raitobezarius ]; 8 - }; 9 - 10 - nodes = { 11 - node1 = mkNode { 12 - replicationMode = "3"; 13 - publicV6Address = "fc00:1::1"; 14 - }; 15 - node2 = mkNode { 16 - replicationMode = "3"; 17 - publicV6Address = "fc00:1::2"; 18 - }; 19 - node3 = mkNode { 20 - replicationMode = "3"; 21 - publicV6Address = "fc00:1::3"; 22 - }; 23 - node4 = mkNode { 24 - replicationMode = "3"; 25 - publicV6Address = "fc00:1::4"; 26 }; 27 - }; 28 - 29 - testScript = '' 30 - from typing import List 31 - from dataclasses import dataclass 32 - import re 33 - start_all() 34 - 35 - cur_version_regex = re.compile('Current cluster layout version: (?P<ver>\d*)') 36 - key_creation_regex = re.compile('Key name: (?P<key_name>.*)\nKey ID: (?P<key_id>.*)\nSecret key: (?P<secret_key>.*)') 37 - 38 - @dataclass 39 - class S3Key: 40 - key_name: str 41 - key_id: str 42 - secret_key: str 43 - 44 - @dataclass 45 - class GarageNode: 46 - node_id: str 47 - host: str 48 - 49 - def get_node_fqn(machine: Machine) -> GarageNode: 50 - node_id, host = machine.succeed("garage node id").split('@') 51 - return GarageNode(node_id=node_id, host=host) 52 - 53 - def get_node_id(machine: Machine) -> str: 54 - return get_node_fqn(machine).node_id 55 - 56 - def get_layout_version(machine: Machine) -> int: 57 - version_data = machine.succeed("garage layout show") 58 - m = cur_version_regex.search(version_data) 59 - if m and m.group('ver') is not None: 60 - return int(m.group('ver')) + 1 61 - else: 62 - raise ValueError('Cannot find current layout version') 63 - 64 - def apply_garage_layout(machine: Machine, layouts: List[str]): 65 - for layout in layouts: 66 - machine.succeed(f"garage layout assign {layout}") 67 - version = get_layout_version(machine) 68 - machine.succeed(f"garage layout apply --version {version}") 69 - 70 - def create_api_key(machine: Machine, key_name: str) -> S3Key: 71 - output = machine.succeed(f"garage key ${ 72 - if ver == "0_8" then "new --name" else "create" 73 - } {key_name}") 74 - m = key_creation_regex.match(output) 75 - if not m or not m.group('key_id') or not m.group('secret_key'): 76 - raise ValueError('Cannot parse API key data') 77 - return S3Key(key_name=key_name, key_id=m.group('key_id'), secret_key=m.group('secret_key')) 78 - 79 - def get_api_key(machine: Machine, key_pattern: str) -> S3Key: 80 - output = machine.succeed(f"garage key info {key_pattern}") 81 - m = key_creation_regex.match(output) 82 - if not m or not m.group('key_name') or not m.group('key_id') or not m.group('secret_key'): 83 - raise ValueError('Cannot parse API key data') 84 - return S3Key(key_name=m.group('key_name'), key_id=m.group('key_id'), secret_key=m.group('secret_key')) 85 - 86 - def test_bucket_writes(node): 87 - node.succeed("garage bucket create test-bucket") 88 - s3_key = create_api_key(node, "test-api-key") 89 - node.succeed("garage bucket allow --read --write test-bucket --key test-api-key") 90 - other_s3_key = get_api_key(node, 'test-api-key') 91 - assert other_s3_key.secret_key == other_s3_key.secret_key 92 - node.succeed( 93 - f"mc alias set test-garage http://[::1]:3900 {s3_key.key_id} {s3_key.secret_key} --api S3v4" 94 - ) 95 - node.succeed("echo test | mc pipe test-garage/test-bucket/test.txt") 96 - assert node.succeed("mc cat test-garage/test-bucket/test.txt").strip() == "test" 97 98 - def test_bucket_over_http(node, bucket='test-bucket', url=None): 99 - if url is None: 100 - url = f"{bucket}.web.garage" 101 102 - node.succeed(f'garage bucket website --allow {bucket}') 103 - node.succeed(f'echo hello world | mc pipe test-garage/{bucket}/index.html') 104 - assert (node.succeed(f"curl -H 'Host: {url}' http://localhost:3902")).strip() == 'hello world' 105 106 with subtest("Garage works as a multi-node S3 storage"): 107 nodes = ('node1', 'node2', 'node3', 'node4') ··· 125 zones = ["nixcon", "nixcon", "paris_meetup", "fosdem"] 126 apply_garage_layout(node1, 127 [ 128 - f'{ndata.node_id} -z {zones[index]} -c ${if ver == "0_8" then "1" else "1G"}' 129 for index, ndata in enumerate(node_ids.values()) 130 ]) 131 # Now Garage is operational. ··· 133 for node in nodes: 134 test_bucket_over_http(get_machine(node)) 135 ''; 136 - } 137 - )) 138 - args
··· 1 + { 2 + lib, 3 + mkNode, 4 + package, 5 + testScriptSetup, 6 + ... 7 + }: 8 + let 9 + extraSettings = 10 + if (lib.versionAtLeast package.version "2") then 11 + { 12 + replication_factor = 3; 13 + consistency_mode = "consistent"; 14 + } 15 + else 16 + { 17 + replication_mode = "3"; 18 }; 19 + in 20 + { 21 + name = "garage-3node-replication"; 22 23 + nodes = { 24 + node1 = mkNode { 25 + inherit extraSettings; 26 + publicV6Address = "fc00:1::1"; 27 + }; 28 + node2 = mkNode { 29 + inherit extraSettings; 30 + publicV6Address = "fc00:1::2"; 31 + }; 32 + node3 = mkNode { 33 + inherit extraSettings; 34 + publicV6Address = "fc00:1::3"; 35 + }; 36 + node4 = mkNode { 37 + inherit extraSettings; 38 + publicV6Address = "fc00:1::4"; 39 + }; 40 + }; 41 42 + testScript = # python 43 + '' 44 + ${testScriptSetup} 45 46 with subtest("Garage works as a multi-node S3 storage"): 47 nodes = ('node1', 'node2', 'node3', 'node4') ··· 65 zones = ["nixcon", "nixcon", "paris_meetup", "fosdem"] 66 apply_garage_layout(node1, 67 [ 68 + f'{ndata.node_id} -z {zones[index]} -c 1G' 69 for index, ndata in enumerate(node_ids.values()) 70 ]) 71 # Now Garage is operational. ··· 73 for node in nodes: 74 test_bucket_over_http(get_machine(node)) 75 ''; 76 + }
+10 -1
pkgs/tools/filesystems/garage/default.nix
··· 92 "k2v::poll::test_poll_item" 93 ]; 94 95 - passthru.tests = nixosTests.garage; 96 97 meta = { 98 description = "S3-compatible object store for small self-hosted geo-distributed deployments"; ··· 137 cargoHash = "sha256-vcvD0Fn/etnAuXrM3+rj16cqpEmW2nzRmrjXsftKTFE="; 138 }; 139 140 garage_0_8 = garage_0_8_7; 141 142 garage_0_9 = garage_0_9_4; 143 144 garage_1_x = garage_1_2_0; 145 146 garage = garage_1_x; 147 }
··· 92 "k2v::poll::test_poll_item" 93 ]; 94 95 + passthru.tests = nixosTests."garage_${lib.versions.major version}"; 96 97 meta = { 98 description = "S3-compatible object store for small self-hosted geo-distributed deployments"; ··· 137 cargoHash = "sha256-vcvD0Fn/etnAuXrM3+rj16cqpEmW2nzRmrjXsftKTFE="; 138 }; 139 140 + garage_2_0_0 = generic { 141 + version = "2.0.0"; 142 + hash = "sha256-dn7FoouF+5qmW6fcC20bKQSc6D2G9yrWdBK3uN3bF58="; 143 + cargoHash = "sha256-6VM/EesrUIaQOeDGqzb0kOqMz4hW7zBJUnaRQ9C3cqc="; 144 + }; 145 + 146 garage_0_8 = garage_0_8_7; 147 148 garage_0_9 = garage_0_9_4; 149 150 garage_1_x = garage_1_2_0; 151 + garage_1 = garage_1_x; 152 + 153 + garage_2 = garage_2_0_0; 154 155 garage = garage_1_x; 156 }
+5
pkgs/top-level/all-packages.nix
··· 3029 garage_0_9 3030 garage_0_8_7 3031 garage_0_9_4 3032 garage_1_2_0 3033 garage_1_x 3034 ; 3035 3036 gaugePlugins = recurseIntoAttrs (callPackage ../by-name/ga/gauge/plugins { });
··· 3029 garage_0_9 3030 garage_0_8_7 3031 garage_0_9_4 3032 + 3033 garage_1_2_0 3034 garage_1_x 3035 + garage_1 3036 + 3037 + garage_2_0_0 3038 + garage_2 3039 ; 3040 3041 gaugePlugins = recurseIntoAttrs (callPackage ../by-name/ga/gauge/plugins { });