github.com/coreos/mantle@v0.13.0/kola/tests/etcd/discovery.go (about)

     1  // Copyright 2015 CoreOS, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package etcd
    16  
    17  import (
    18  	"encoding/json"
    19  
    20  	"github.com/coreos/pkg/capnslog"
    21  
    22  	"github.com/coreos/mantle/kola/cluster"
    23  	"github.com/coreos/mantle/kola/register"
    24  	"github.com/coreos/mantle/platform/conf"
    25  )
    26  
    27  var plog = capnslog.NewPackageLogger("github.com/coreos/mantle", "kola/tests/etcd")
    28  
    29  func init() {
    30  	register.Register(&register.Test{
    31  		Run:         Discovery,
    32  		ClusterSize: 3,
    33  		Name:        "cl.etcd-member.discovery",
    34  		UserData: conf.ContainerLinuxConfig(`etcd:
    35    listen_client_urls:          http://0.0.0.0:2379
    36    advertise_client_urls:       http://{PRIVATE_IPV4}:2379
    37    listen_peer_urls:            http://{PRIVATE_IPV4}:2380
    38    initial_advertise_peer_urls: http://{PRIVATE_IPV4}:2380
    39    discovery:                   $discovery`),
    40  		Flags:   []register.Flag{register.RequiresInternetAccess}, // etcd-member requires networking
    41  		Distros: []string{"cl"},
    42  	})
    43  
    44  	register.Register(&register.Test{
    45  		Run:         etcdMemberV2BackupRestore,
    46  		ClusterSize: 1,
    47  		Name:        "cl.etcd-member.v2-backup-restore",
    48  		UserData: conf.ContainerLinuxConfig(`
    49  
    50  etcd:
    51    listen_client_urls:          http://0.0.0.0:4001,http://{PRIVATE_IPV4}:2379
    52    advertise_client_urls:       http://{PRIVATE_IPV4}:2379
    53    listen_peer_urls:            http://0.0.0.0:2380
    54    initial_advertise_peer_urls: http://{PRIVATE_IPV4}:2380
    55    discovery:                   $discovery
    56  `),
    57  		Flags:            []register.Flag{register.RequiresInternetAccess}, // etcd-member requires networking
    58  		ExcludePlatforms: []string{"esx"},                                  // etcd-member requires ct rendering
    59  		Distros:          []string{"cl"},
    60  	})
    61  
    62  	register.Register(&register.Test{
    63  		Run: etcdmemberEtcdctlV3,
    64  		// Clustersize of 1 to avoid needing private ips everywhere for clustering;
    65  		// this lets it run on more platforms, and also faster
    66  		ClusterSize: 1,
    67  		Name:        "cl.etcd-member.etcdctlv3",
    68  		UserData: conf.ContainerLinuxConfig(`
    69  
    70  etcd:
    71    listen_client_urls:          http://0.0.0.0:2379
    72    advertise_client_urls:       http://127.0.0.1:2379
    73    listen_peer_urls:            http://0.0.0.0:2380
    74    initial_advertise_peer_urls: http://127.0.0.1:2380
    75  `),
    76  		Flags:   []register.Flag{register.RequiresInternetAccess}, // networking to download etcd image
    77  		Distros: []string{"cl"},
    78  	})
    79  }
    80  
    81  func Discovery(c cluster.TestCluster) {
    82  	var err error
    83  
    84  	// NOTE(pb): this check makes the next code somewhat redundant
    85  	if err = GetClusterHealth(c, c.Machines()[0], len(c.Machines())); err != nil {
    86  		c.Fatalf("discovery failed cluster-health check: %v", err)
    87  	}
    88  
    89  	var keyMap map[string]string
    90  	keyMap, err = setKeys(c, 5)
    91  	if err != nil {
    92  		c.Fatalf("failed to set keys: %v", err)
    93  	}
    94  
    95  	if err = checkKeys(c, keyMap); err != nil {
    96  		c.Fatalf("failed to check keys: %v", err)
    97  	}
    98  
    99  }
   100  
   101  // etcdMemberV2BackupRestore tests that the basic etcdctl v2 operations (get,
   102  // put, rm) work. It verifies that a backup and restore, similar to the one
   103  // documented in
   104  // https://coreos.com/etcd/docs/latest/v2/admin_guide.html#disaster-recovery
   105  // works.
   106  // Note, this is a v2 backup/restore being performed against the current v3
   107  // etcd
   108  func etcdMemberV2BackupRestore(c cluster.TestCluster) {
   109  	m := c.Machines()[0]
   110  
   111  	if err := GetClusterHealth(c, c.Machines()[0], len(c.Machines())); err != nil {
   112  		c.Fatalf("failed cluster-health check: %v", err)
   113  	}
   114  
   115  	c.MustSSH(m, `
   116  	set -e
   117  
   118  	prefix=$RANDOM
   119  	etcdctl set /$prefix/test magic
   120  	res="$(etcdctl get /$prefix/test)"
   121  	if [[ "$res" != "magic" ]]; then
   122  		echo "Expected magic, got $res"
   123  		exit 1
   124  	fi
   125  
   126  	backup_to="$(mktemp -d)"
   127  
   128  	sudo etcdctl backup --data-dir=/var/lib/etcd \
   129  	               --backup-dir "${backup_to}"
   130  	
   131  	etcdctl rm /$prefix/test
   132  
   133  	if etcdctl get /$prefix/test 2>&1; then
   134  		echo "Expected rm'd key to error on get, didn't"
   135  		exit 1
   136  	fi
   137  
   138  	sudo systemctl stop etcd-member
   139  
   140  	# Note: this means we're now a new cluster of size 1 because of how etcd2
   141  	# backup/restore works.
   142  	sudo rm -rf /var/lib/etcd
   143  	sudo mv "${backup_to}" /var/lib/etcd/
   144  	sudo chown -R etcd:etcd /var/lib/etcd
   145  
   146  	sudo mkdir -p /run/systemd/system/etcd-member.service.d/
   147  	sudo tee /run/systemd/system/etcd-member.service.d/10-force-new.conf <<EOF
   148  [Service]
   149  Environment=ETCD_FORCE_NEW_CLUSTER=true
   150  EOF
   151  
   152  	sudo systemctl daemon-reload
   153  	sudo systemctl start etcd-member
   154  
   155  	res="$(etcdctl get /$prefix/test)"
   156  	if [[ "$res" != "magic" ]]; then
   157  		echo "Expected magic after backup-restore, got $res"
   158  		exit 1
   159  	fi
   160  `)
   161  }
   162  
   163  // etcdmemberEtcdctlV3 tests the basic operation of the ETCDCTL_API=3 behavior
   164  // of the etcdctl we ship.
   165  func etcdmemberEtcdctlV3(c cluster.TestCluster) {
   166  	m := c.Machines()[0]
   167  
   168  	type etcdMemberOutput struct {
   169  		Members []struct {
   170  			ID         uint64
   171  			Name       string
   172  			PeerURLs   []string
   173  			ClientURLs []string
   174  		}
   175  	}
   176  	memberJson := c.MustSSH(m, `ETCDCTL_API=3 etcdctl member list --write-out=json`)
   177  
   178  	members := etcdMemberOutput{}
   179  	if err := json.Unmarshal(memberJson, &members); err != nil {
   180  		c.Fatalf("could not unmarshal %s: %s", memberJson, err)
   181  	}
   182  
   183  	if len(members.Members) != len(c.Machines()) {
   184  		c.Fatalf("expected %v members; only got %v", len(c.Machines()), len(members.Members))
   185  	}
   186  
   187  	c.MustSSH(m, `
   188  	set -e
   189  	export ETCDCTL_API=3
   190  	if [[ "$(etcdctl put foo bar)" != "OK" ]]; then
   191  		echo "Put failed"
   192  		exit 1
   193  	fi
   194  
   195  	value="$(etcdctl get foo -w json | jq '.kvs[].value' -r | base64 -d)"
   196  
   197  	if [[ "${value}" != "bar" ]]; then
   198  		echo "Reading our put failed: expected bar, got ${value}"
   199  		exit 1
   200  	fi
   201  
   202  	backup_to="$(mktemp -d)"
   203  
   204  	sudo -E etcdctl snapshot save "${backup_to}/snapshot.db"
   205  	sudo -E etcdctl snapshot status "${backup_to}/snapshot.db"
   206  `)
   207  }