func (s *Server) authHTTPWrapper(handler http.HandlerFunc) http.HandlerFunc {
	if s.secret != "" {
		return func(w http.ResponseWriter, req *http.Request) {
			secret := req.Header.Get("Authorization")
			if err := s.authenticate(secret); err != nil {
				http.Error(w, err.Error(), http.StatusUnauthorized)
				return
			}
			handler(w, req)
		}
	}
	return handler
}
authHTTPWrapper will wrap a standard handler
if the secret is specified for the server.
package server
import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"math"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"strings"
	"sync"
	"time"
	"github.com/goraft/raft"
	"github.com/gorilla/mux"
	"github.com/miekg/dns"
	"github.com/skynetservices/skydns1/msg"
	"github.com/skynetservices/skydns1/registry"
	"github.com/skynetservices/skydns1/stats"
)
const (
	raftElectionTimeout = 200 * time.Millisecond
)
func init() {
	raft.RegisterCommand(&AddServiceCommand{})
	raft.RegisterCommand(&UpdateTTLCommand{})
	raft.RegisterCommand(&RemoveServiceCommand{})
	raft.RegisterCommand(&AddCallbackCommand{})
}
type Server struct {
	members     []string  
	nameservers []string  
	domain       string
	domainLabels int
	dnsAddr      string
	httpAddr     string
	readTimeout  time.Duration
	writeTimeout time.Duration
	waiter       *sync.WaitGroup
	registry registry.Registry
	dnsUDPServer *dns.Server
	dnsTCPServer *dns.Server
	dnsHandler   *dns.ServeMux
	httpServer *http.Server
	router     *mux.Router
	raftServer raft.Server
	dataDir    string
	secret     string
	dnsKey  *dns.DNSKEY
	keyTag  uint16
	privKey dns.PrivateKey
	roundrobin bool
	tlskey string
	tlspem string
}
func NewServer(members []string, domain string, dnsAddr string, httpAddr string, dataDir string, rt, wt time.Duration, secret string, nameservers []string, roundrobin bool, tlskey string, tlspem string) (s *Server) {
	s = &Server{
		members:      members,
		domain:       strings.ToLower(domain),
		domainLabels: dns.CountLabel(dns.Fqdn(domain)),
		dnsAddr:      dnsAddr,
		httpAddr:     httpAddr,
		readTimeout:  rt,
		writeTimeout: wt,
		router:       mux.NewRouter(),
		registry:     registry.New(),
		dataDir:      dataDir,
		dnsHandler:   dns.NewServeMux(),
		waiter:       new(sync.WaitGroup),
		secret:       secret,
		nameservers:  nameservers,
		roundrobin:   roundrobin,
		tlskey:       tlskey,
		tlspem:       tlspem,
	}
	if _, err := os.Stat(s.dataDir); os.IsNotExist(err) {
		log.Fatal("Data directory does not exist: ", dataDir)
		return
	}
	s.dnsHandler.Handle(".", s)
	authWrapper := s.authHTTPWrapper
	s.router.HandleFunc("/skydns/services/{uuid}", authWrapper(s.addServiceHTTPHandler)).Methods("PUT")
	s.router.HandleFunc("/skydns/services/{uuid}", authWrapper(s.getServiceHTTPHandler)).Methods("GET")
	s.router.HandleFunc("/skydns/services/{uuid}", authWrapper(s.removeServiceHTTPHandler)).Methods("DELETE")
	s.router.HandleFunc("/skydns/services/{uuid}", authWrapper(s.updateServiceHTTPHandler)).Methods("PATCH")
	s.router.HandleFunc("/skydns/callbacks/{uuid}", authWrapper(s.addCallbackHTTPHandler)).Methods("PUT")
	s.router.HandleFunc("/skydns/services/", authWrapper(s.getServicesHTTPHandler)).Methods("GET")
	s.router.HandleFunc("/skydns/regions/", authWrapper(s.getRegionsHTTPHandler)).Methods("GET")
	s.router.HandleFunc("/skydns/environments/", authWrapper(s.getEnvironmentsHTTPHandler)).Methods("GET")
	s.router.HandleFunc("/raft/join", s.joinHandler).Methods("POST")
	return
}
func (s *Server) DNSAddr() string { return s.dnsAddr }
func (s *Server) HTTPAddr() string { return s.httpAddr }
func (s *Server) PublicKey() *dns.DNSKEY { return s.dnsKey }
func (s *Server) KeyTag() uint16 { return s.keyTag }
func (s *Server) PrivateKey() dns.PrivateKey { return s.privKey }
func (s *Server) Start() (*sync.WaitGroup, error) {
	var err error
	log.Printf("Initializing Server. DNS Addr: %q, HTTP Addr: %q, Data Dir: %q, Forwarders: %q", s.dnsAddr, s.httpAddr, s.dataDir, s.nameservers)
	transporter := raft.NewHTTPTransporter("/raft", raftElectionTimeout)
	s.raftServer, err = raft.NewServer(s.HTTPAddr(), s.dataDir, transporter, nil, s.registry, "")
	if err != nil {
		log.Fatal(err)
	}
	transporter.Install(s.raftServer, s)
	s.raftServer.Start()
	if len(s.members) > 0 {
		log.Println("Joining cluster:", strings.Join(s.members, ","))
		if !s.raftServer.IsLogEmpty() {
			log.Fatal("Cannot join with an existing log")
		}
		if err := s.Join(s.members); err != nil {
			return nil, err
		}
		log.Println("Joined cluster")
	} else if s.raftServer.IsLogEmpty() {
		log.Println("Initializing new cluster")
		_, err := s.raftServer.Do(&raft.DefaultJoinCommand{
			Name:             s.raftServer.Name(),
			ConnectionString: s.connectionString(),
		})
		if err != nil {
			log.Fatal(err)
			return nil, err
		}
	} else {
		log.Println("Recovered from log")
	}
	s.dnsTCPServer = &dns.Server{
		Addr:         s.DNSAddr(),
		Net:          "tcp",
		Handler:      s.dnsHandler,
		ReadTimeout:  s.readTimeout,
		WriteTimeout: s.writeTimeout,
	}
	s.dnsUDPServer = &dns.Server{
		Addr:         s.DNSAddr(),
		Net:          "udp",
		Handler:      s.dnsHandler,
		UDPSize:      65535,
		ReadTimeout:  s.readTimeout,
		WriteTimeout: s.writeTimeout,
	}
	s.httpServer = &http.Server{
		Addr:           s.HTTPAddr(),
		Handler:        s.router,
		ReadTimeout:    s.readTimeout,
		WriteTimeout:   s.writeTimeout,
		MaxHeaderBytes: 1 << 20,
	}
	go s.listenAndServe()
	s.waiter.Add(1)
	go s.run()
	return s.waiter, nil
}
func (s *Server) Stop() {
	log.Println("Stopping server")
	s.waiter.Done()
}
func (s *Server) Leader() string {
	l := s.raftServer.Leader()
	if l == "" {
		return s.raftServer.Name()
	}
	return l
}
func (s *Server) IsLeader() bool {
	return s.raftServer.State() == raft.Leader
}
func (s *Server) Members() (members []string) {
	peers := s.raftServer.Peers()
	for _, p := range peers {
		members = append(members, strings.TrimPrefix(p.ConnectionString, "http://"))
	}
	return
}
func (s *Server) run() {
	var (
		tick = time.NewTicker(1 * time.Second)
		sig  = make(chan os.Signal)
	)
	signal.Notify(sig, os.Interrupt)
	defer tick.Stop()
	for {
		select {
		case <-tick.C:
			if s.IsLeader() {
				expired := s.registry.GetExpired()
				for _, uuid := range expired {
					stats.ExpiredCount.Inc(1)
					s.raftServer.Do(NewRemoveServiceCommand(uuid))
				}
			}
		case <-sig:
			s.Stop()
			return
		}
	}
}
func (s *Server) Join(members []string) error {
	command := &raft.DefaultJoinCommand{
		Name:             s.raftServer.Name(),
		ConnectionString: s.connectionString(),
	}
	var b bytes.Buffer
	json.NewEncoder(&b).Encode(command)
	for _, m := range members {
		log.Println("Attempting to connect to:", m)
		resp, err := http.Post(fmt.Sprintf("http://%s/raft/join", strings.TrimSpace(m)), "application/json", &b)
		log.Println("Post returned")
		if err != nil {
			if _, ok := err.(*url.Error); ok {
				continue
			}
			return err
		}
		resp.Body.Close()
		return nil
	}
	return errors.New("Could not connect to any cluster members")
}
func (s *Server) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
	s.router.HandleFunc(pattern, handler)
}
func (s *Server) joinHandler(w http.ResponseWriter, req *http.Request) {
	log.Println("Processing incoming join")
	command := &raft.DefaultJoinCommand{}
	if err := json.NewDecoder(req.Body).Decode(&command); err != nil {
		log.Println("Error decoding json message:", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if _, err := s.raftServer.Do(command); err != nil {
		switch err {
		case raft.NotLeaderError:
			log.Println("Redirecting to leader")
			s.redirectToLeader(w, req)
		default:
			log.Println("Error processing join:", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}
func (s *Server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) {
	stats.RequestCount.Inc(1)
	q := req.Question[0]
	q.Name = strings.ToLower(q.Name)
	log.Printf("Received DNS Request for %q from %q with type %d", q.Name, w.RemoteAddr(), q.Qtype)
	if !strings.HasSuffix(q.Name, dns.Fqdn(s.domain)) {
		s.ServeDNSForward(w, req)
		return
	}
	m := new(dns.Msg)
	m.SetReply(req)
	m.Authoritative = true
	m.RecursionAvailable = true
	m.Answer = make([]dns.RR, 0, 10)
	defer func() {
		if s.PublicKey() != nil {
			if opt := req.IsEdns0(); opt != nil && opt.Do() {
				s.nsec(m)
				s.sign(m, opt.UDPSize())
			}
		}
		w.WriteMsg(m)
	}()
	if q.Name == dns.Fqdn(s.domain) {
		switch q.Qtype {
		case dns.TypeDNSKEY:
			if s.PublicKey() != nil {
				m.Answer = append(m.Answer, s.PublicKey())
				return
			}
		case dns.TypeSOA:
			m.Answer = s.createSOA()
			return
		}
	}
	if q.Qtype == dns.TypeA || q.Qtype == dns.TypeAAAA {
		records, err := s.getARecords(q)
		if err != nil {
			m.SetRcode(req, dns.RcodeNameError)
			m.Ns = s.createSOA()
			return
		}
		if s.roundrobin {
			switch l := uint16(len(records)); l {
			case 1:
			case 2:
				if dns.Id()%2 == 0 {
					records[0], records[1] = records[1], records[0]
				}
			default:
				for j := 0; j < int(l*(dns.Id()%4+1)); j++ {
					q := dns.Id() % l
					p := dns.Id() % l
					if q == p {
						p = (p + 1) % l
					}
					records[q], records[p] = records[p], records[q]
				}
			}
		}
		m.Answer = append(m.Answer, records...)
	}
	records, extra, err := s.getSRVRecords(q)
	if err != nil && len(m.Answer) == 0 {
		m.SetRcode(req, dns.RcodeNameError)
		m.Ns = s.createSOA()
		return
	}
	if q.Qtype == dns.TypeANY || q.Qtype == dns.TypeSRV {
		m.Answer = append(m.Answer, records...)
		m.Extra = append(m.Extra, extra...)
	}
	if len(m.Answer) == 0 {  
		m.Ns = s.createSOA()
	}
}
func (s *Server) ServeDNSForward(w dns.ResponseWriter, req *dns.Msg) {
	if len(s.nameservers) == 0 {
		log.Printf("Error: Failure to Forward DNS Request, no servers configured %q", dns.ErrServ)
		m := new(dns.Msg)
		m.SetReply(req)
		m.SetRcode(req, dns.RcodeServerFailure)
		m.Authoritative = false      
		m.RecursionAvailable = true  
		w.WriteMsg(m)
		return
	}
	network := "udp"
	if _, ok := w.RemoteAddr().(*net.TCPAddr); ok {
		network = "tcp"
	}
	c := &dns.Client{Net: network, ReadTimeout: 5 * time.Second}
	nsid := int(req.Id) % len(s.nameservers)
	try := 0
Redo:
	r, _, err := c.Exchange(req, s.nameservers[nsid])
	if err == nil {
		log.Printf("Forwarded DNS Request %q to %q", req.Question[0].Name, s.nameservers[nsid])
		w.WriteMsg(r)
		return
	}
	if try < len(s.nameservers) {
		log.Printf("Error: Failure to Forward DNS Request %q to %q", err, s.nameservers[nsid])
		try++
		nsid = (nsid + 1) % len(s.nameservers)
		goto Redo
	}
	log.Printf("Error: Failure to Forward DNS Request %q", err)
	m := new(dns.Msg)
	m.SetReply(req)
	m.SetRcode(req, dns.RcodeServerFailure)
	w.WriteMsg(m)
}
func (s *Server) getARecords(q dns.Question) (records []dns.RR, err error) {
	var h string
	name := strings.TrimSuffix(q.Name, ".")
	if name == s.domain {
		for _, m := range s.Members() {
			h, _, err = net.SplitHostPort(m)
			if err != nil {
				return
			}
			if q.Qtype == dns.TypeA {
				records = append(records, &dns.A{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 15}, A: net.ParseIP(h)})
			}
		}
	}
	if name == "leader."+s.domain || name == "master."+s.domain || name == s.domain {
		h, _, err = net.SplitHostPort(s.Leader())
		if err != nil {
			return
		}
		if q.Qtype == dns.TypeA {
			records = append(records, &dns.A{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 15}, A: net.ParseIP(h)})
		}
		return
	}
	var (
		services []msg.Service
		key      = strings.TrimSuffix(q.Name, s.domain+".")
	)
	services, err = s.registry.Get(key)
	if len(services) == 0 && len(key) > 1 {
		service, e := s.registry.GetUUID(key[:len(key)-1])
		if e == nil {
			services = append(services, service)
			err = nil
		}
	}
	for _, serv := range services {
		ip := net.ParseIP(serv.Host)
		switch {
		case ip == nil:
			continue
		case ip.To4() != nil && q.Qtype == dns.TypeA:
			records = append(records, &dns.A{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: serv.TTL}, A: ip.To4()})
		case ip.To4() == nil && q.Qtype == dns.TypeAAAA:
			records = append(records, &dns.AAAA{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: serv.TTL}, AAAA: ip.To16()})
		}
	}
	return
}
func (s *Server) getSRVRecords(q dns.Question) (records []dns.RR, extra []dns.RR, err error) {
	var weight uint16
	services := make([]msg.Service, 0)
	key := strings.TrimSuffix(q.Name, s.domain+".")
	services, err = s.registry.Get(key)
	if err != nil {
		return
	}
	weight = 0
	if len(services) > 0 {
		weight = uint16(math.Floor(float64(100 / len(services))))
	}
	for _, serv := range services {
		ip := net.ParseIP(serv.Host)
		switch {
		case ip == nil:
			records = append(records, &dns.SRV{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: serv.TTL},
				Priority: 10, Weight: weight, Port: serv.Port, Target: serv.Host + "."})
			continue
		case ip.To4() != nil:
			extra = append(extra, &dns.A{Hdr: dns.RR_Header{Name: serv.UUID + "." + s.domain + ".", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: serv.TTL}, A: ip.To4()})
			records = append(records, &dns.SRV{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: serv.TTL},
				Priority: 10, Weight: weight, Port: serv.Port, Target: serv.UUID + "." + s.domain + "."})
		case ip.To16() != nil:
			extra = append(extra, &dns.AAAA{Hdr: dns.RR_Header{Name: serv.UUID + "." + s.domain + ".", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: serv.TTL}, AAAA: ip.To16()})
			records = append(records, &dns.SRV{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: serv.TTL},
				Priority: 10, Weight: weight, Port: serv.Port, Target: serv.UUID + "." + s.domain + "."})
		default:
			panic("skydns: internal error")
		}
	}
	labels := dns.SplitDomainName(key)
	pos := len(labels) - 4
	if len(labels) >= 4 && labels[pos] != "*" {
		region := labels[pos]
		labels[pos] = "*"
		additionalServices := make([]msg.Service, len(services))
		additionalServices, err = s.registry.Get(strings.Join(labels, "."))
		if err != nil {
			return
		}
		weight = 0
		if len(additionalServices) <= len(services) {
			return
		}
		weight = uint16(math.Floor(float64(100 / (len(additionalServices) - len(services)))))
		for _, serv := range additionalServices {
			if strings.ToLower(serv.Region) == region {
				continue
			}
			ip := net.ParseIP(serv.Host)
			switch {
			case ip == nil:
				records = append(records, &dns.SRV{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: serv.TTL},
					Priority: 20, Weight: weight, Port: serv.Port, Target: serv.Host + "."})
				continue
			case ip.To4() != nil:
				extra = append(extra, &dns.A{Hdr: dns.RR_Header{Name: serv.UUID + "." + s.domain + ".", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: serv.TTL}, A: ip.To4()})
				records = append(records, &dns.SRV{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: serv.TTL},
					Priority: 20, Weight: weight, Port: serv.Port, Target: serv.UUID + "." + s.domain + "."})
			case ip.To16() != nil:
				extra = append(extra, &dns.AAAA{Hdr: dns.RR_Header{Name: serv.UUID + "." + s.domain + ".", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: serv.TTL}, AAAA: ip.To16()})
				records = append(records, &dns.SRV{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: serv.TTL},
					Priority: 20, Weight: weight, Port: serv.Port, Target: serv.UUID + "." + s.domain + "."})
			default:
				panic("skydns: internal error")
			}
		}
	}
	return
}
func (s *Server) connectionString() string {
	return fmt.Sprintf("http://%s", s.httpAddr)
}
func (s *Server) listenAndServe() {
	go func() {
		err := s.dnsTCPServer.ListenAndServe()
		if err != nil {
			log.Fatalf("Start %s listener on %s failed:%s", s.dnsTCPServer.Net, s.dnsTCPServer.Addr, err.Error())
		}
	}()
	go func() {
		err := s.dnsUDPServer.ListenAndServe()
		if err != nil {
			log.Fatalf("Start %s listener on %s failed:%s", s.dnsUDPServer.Net, s.dnsUDPServer.Addr, err.Error())
		}
	}()
	go func() {
		if s.tlskey != "" {
			log.Print("Starting http server with tls")
			var err error
			config := &tls.Config{}
			if s.httpServer.TLSConfig != nil {
				*config = *s.httpServer.TLSConfig
			}
			if config.NextProtos == nil {
				config.NextProtos = []string{"http/1.1"}
			}
			config.Certificates = make([]tls.Certificate, 1)
			config.Certificates[0], err = tls.LoadX509KeyPair(s.tlspem, s.tlskey)
			if err != nil {
				log.Fatal(err)
			}
			config.BuildNameToCertificate()
			conn, err := net.Listen("tcp", s.httpAddr)
			if err != nil {
				log.Fatal(err)
			}
			tlsListener := tls.NewListener(conn, config)
			s.httpServer.Serve(tlsListener)
		} else {
			log.Print("Starting http server without tls")
			err := s.httpServer.ListenAndServe()
			if err != nil {
				log.Fatalf("Start http listener on %s failed:%s", s.httpServer.Addr, err.Error())
			}
		}
	}()
}
func (s *Server) redirectToLeader(w http.ResponseWriter, req *http.Request) {
	if s.Leader() != "" {
		http.Redirect(w, req, "http://"+s.Leader()+req.URL.Path, http.StatusMovedPermanently)
	} else {
		log.Println("Error: Leader Unknown")
		http.Error(w, "Leader unknown", http.StatusInternalServerError)
	}
}
func (s *Server) authenticate(secret string) (err error) {
	if s.secret != "" && secret != s.secret {
		err = errors.New("Unauthorized")
	}
	return
}
func (s *Server) addServiceHTTPHandler(w http.ResponseWriter, req *http.Request) {
	stats.AddServiceCount.Inc(1)
	vars := mux.Vars(req)
	var uuid string
	var ok bool
	if uuid, ok = vars["uuid"]; !ok {
		http.Error(w, "UUID required", http.StatusBadRequest)
		return
	}
	var serv msg.Service
	if err := json.NewDecoder(req.Body).Decode(&serv); err != nil {
		log.Println("Error: ", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if serv.Host == "" || serv.Port == 0 {
		http.Error(w, "Host and Port required", http.StatusBadRequest)
		return
	}
	serv.UUID = uuid
	if _, err := s.raftServer.Do(NewAddServiceCommand(serv)); err != nil {
		switch err {
		case registry.ErrExists:
			http.Error(w, err.Error(), http.StatusConflict)
		case raft.NotLeaderError:
			s.redirectToLeader(w, req)
		default:
			log.Println("Error: ", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}
	w.WriteHeader(http.StatusCreated)
}
func (s *Server) removeServiceHTTPHandler(w http.ResponseWriter, req *http.Request) {
	stats.RemoveServiceCount.Inc(1)
	vars := mux.Vars(req)
	var (
		uuid string
		ok   bool
	)
	if uuid, ok = vars["uuid"]; !ok {
		http.Error(w, "UUID required", http.StatusBadRequest)
		return
	}
	if _, err := s.raftServer.Do(NewRemoveServiceCommand(uuid)); err != nil {
		switch err {
		case registry.ErrNotExists:
			http.Error(w, err.Error(), http.StatusNotFound)
		case raft.NotLeaderError:
			s.redirectToLeader(w, req)
		default:
			log.Println("Error: ", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}
}
func (s *Server) updateServiceHTTPHandler(w http.ResponseWriter, req *http.Request) {
	stats.UpdateTTLCount.Inc(1)
	vars := mux.Vars(req)
	var uuid string
	var ok bool
	if uuid, ok = vars["uuid"]; !ok {
		http.Error(w, "UUID required", http.StatusBadRequest)
		return
	}
	var serv msg.Service
	if err := json.NewDecoder(req.Body).Decode(&serv); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if _, err := s.raftServer.Do(NewUpdateTTLCommand(uuid, serv.TTL)); err != nil {
		switch err {
		case registry.ErrNotExists:
			http.Error(w, err.Error(), http.StatusNotFound)
		case raft.NotLeaderError:
			s.redirectToLeader(w, req)
		default:
			log.Println("Error: ", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}
func (s *Server) getServiceHTTPHandler(w http.ResponseWriter, req *http.Request) {
	stats.GetServiceCount.Inc(1)
	vars := mux.Vars(req)
	var uuid string
	var ok bool
	if uuid, ok = vars["uuid"]; !ok {
		http.Error(w, "UUID required", http.StatusBadRequest)
		return
	}
	log.Println("Retrieving Service ", uuid)
	serv, err := s.registry.GetUUID(uuid)
	if err != nil {
		switch err {
		case registry.ErrNotExists:
			http.Error(w, err.Error(), http.StatusNotFound)
		default:
			log.Println("Error: ", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}
	if err := json.NewEncoder(w).Encode(serv); err != nil {
		log.Println("Error: ", err)
	}
}