github.com/dustinrc/deis@v1.10.1-0.20150917223407-0894a5fb979e/swarm/swarm.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"log"
     9  	"net/http"
    10  	"net/url"
    11  	"os"
    12  	"os/exec"
    13  	"strings"
    14  	"text/template"
    15  	"time"
    16  
    17  	"github.com/coreos/go-etcd/etcd"
    18  	"github.com/deis/deis/tests/utils"
    19  )
    20  
    21  // EtcdCluster information about the nodes in the etcd cluster
    22  type EtcdCluster struct {
    23  	Members []etcd.Member `json:"members"`
    24  }
    25  
    26  // NodeStat information about the local node in etcd
    27  type NodeStats struct {
    28  	LeaderInfo struct {
    29  		Name      string    `json:"leader"`
    30  		Uptime    string    `json:"uptime"`
    31  		StartTime time.Time `json:"startTime"`
    32  	} `json:"leaderInfo"`
    33  }
    34  
    35  const (
    36  	swarmpath               = "/deis/scheduler/swarm/node"
    37  	swarmetcd               = "/deis/scheduler/swarm/host"
    38  	etcdport                = "4001"
    39  	timeout   time.Duration = 3 * time.Second
    40  	ttl       time.Duration = timeout * 2
    41  )
    42  
    43  func run(cmd string) {
    44  	var cmdBuf bytes.Buffer
    45  	tmpl := template.Must(template.New("cmd").Parse(cmd))
    46  	if err := tmpl.Execute(&cmdBuf, nil); err != nil {
    47  		log.Fatal(err)
    48  	}
    49  	cmdString := cmdBuf.String()
    50  	fmt.Println(cmdString)
    51  	var cmdl *exec.Cmd
    52  	cmdl = exec.Command("sh", "-c", cmdString)
    53  	if _, _, err := utils.RunCommandWithStdoutStderr(cmdl); err != nil {
    54  		log.Fatal(err)
    55  	} else {
    56  		fmt.Println("ok")
    57  	}
    58  }
    59  
    60  func getleaderHost() string {
    61  	var nodeStats NodeStats
    62  	client := &http.Client{}
    63  	resp, _ := client.Get("http://" + os.Getenv("HOST") + ":2379/v2/stats/self")
    64  
    65  	body, _ := ioutil.ReadAll(resp.Body)
    66  	json.Unmarshal(body, &nodeStats)
    67  
    68  	etcdLeaderID := nodeStats.LeaderInfo.Name
    69  
    70  	var etcdCluster EtcdCluster
    71  	resp, _ = client.Get("http://" + os.Getenv("HOST") + ":2379/v2/members")
    72  	defer resp.Body.Close()
    73  
    74  	body, _ = ioutil.ReadAll(resp.Body)
    75  	json.Unmarshal(body, &etcdCluster)
    76  
    77  	for _, node := range etcdCluster.Members {
    78  		if node.ID == etcdLeaderID {
    79  			u, err := url.Parse(node.ClientURLs[0])
    80  			if err == nil {
    81  				return u.Host
    82  			}
    83  		}
    84  	}
    85  
    86  	return ""
    87  }
    88  
    89  func publishService(client *etcd.Client, host string, ttl uint64) {
    90  	for {
    91  		setEtcd(client, swarmetcd, host, ttl)
    92  		time.Sleep(timeout)
    93  	}
    94  }
    95  
    96  func setEtcd(client *etcd.Client, key, value string, ttl uint64) {
    97  	_, err := client.Set(key, value, ttl)
    98  	if err != nil && !strings.Contains(err.Error(), "Key already exists") {
    99  		log.Println(err)
   100  	}
   101  }
   102  
   103  func main() {
   104  	etcdproto := "etcd://" + getleaderHost() + swarmpath
   105  	etcdhost := os.Getenv("HOST")
   106  	addr := "--addr=" + etcdhost + ":2375"
   107  	client := etcd.NewClient([]string{"http://" + etcdhost + ":" + etcdport})
   108  	switch os.Args[1] {
   109  	case "join":
   110  		run("./deis-swarm join " + addr + " " + etcdproto)
   111  	case "manage":
   112  		go publishService(client, etcdhost, uint64(ttl.Seconds()))
   113  		run("./deis-swarm manage " + etcdproto)
   114  	}
   115  }