Exemple #1
0
func main() {
	fixListenPid()

	listeners, _ := activation.Listeners(false)

	if len(listeners) == 0 {
		panic("No listeners")
	}

	if os.Getenv("LISTEN_PID") == "" || os.Getenv("LISTEN_FDS") == "" {
		panic("Should not unset envs")
	}

	listeners, err := activation.Listeners(true)
	if err != nil {
		panic(err)
	}

	if os.Getenv("LISTEN_PID") != "" || os.Getenv("LISTEN_FDS") != "" {
		panic("Can not unset envs")
	}

	c0, _ := listeners[0].Accept()
	c1, _ := listeners[1].Accept()

	// Write out the expected strings to the two pipes
	c0.Write([]byte("Hello world"))
	c1.Write([]byte("Goodbye world"))

	return
}
Exemple #2
0
// Init sets up the Daemon's internal workings.
// Don't call more than once.
func (d *Daemon) Init() error {
	t0 := time.Now()
	listeners, err := activation.Listeners(false)
	if err != nil {
		return err
	}

	listenerMap := make(map[string]net.Listener)

	for _, listener := range listeners {
		listenerMap[listener.Addr().String()] = listener
	}

	// The SnapdSocket is required-- without it, die.
	if listener, ok := listenerMap[dirs.SnapdSocket]; ok {
		d.snapdListener = &ucrednetListener{listener}
	} else {
		return fmt.Errorf("daemon is missing the listener for %s", dirs.SnapdSocket)
	}

	// Note that the SnapSocket listener does not use ucrednet. We use the lack
	// of remote information as an indication that the request originated with
	// this socket. This listener may also be nil if that socket wasn't among
	// the listeners, so check it before using it.
	d.snapListener = listenerMap[dirs.SnapSocket]

	d.addRoutes()

	logger.Debugf("init done in %s", time.Now().Sub(t0))

	return nil
}
Exemple #3
0
func fdListener(addr string) (net.Listener, error) {
	fdOffset := 0
	if addr != "" {
		fd, err := strconv.Atoi(addr)
		if err != nil {
			return nil, fmt.Errorf("fd index is not a number")
		}
		fdOffset = fd - 3
	}

	listeners, err := activation.Listeners(false)
	if err != nil {
		return nil, err
	}

	if fdOffset >= len(listeners) {
		return nil, fmt.Errorf("fd %v is out of range (%v)", addr, len(listeners)+3)
	}

	if listeners[fdOffset] == nil {
		return nil, fmt.Errorf("fd %v was not socket activated", addr)
	}

	return listeners[fdOffset], nil
}
Exemple #4
0
// ListenFD returns the specified socket activated files as a slice of
// net.Listeners or all of the activated files if "*" is given.
func ListenFD(addr string) ([]net.Listener, error) {
	// socket activation
	listeners, err := activation.Listeners(false)
	if err != nil {
		return nil, err
	}

	if listeners == nil || len(listeners) == 0 {
		return nil, errors.New("No sockets found")
	}

	// default to all fds just like unix:// and tcp://
	if addr == "" {
		addr = "*"
	}

	fdNum, _ := strconv.Atoi(addr)
	fdOffset := fdNum - 3
	if (addr != "*") && (len(listeners) < int(fdOffset)+1) {
		return nil, errors.New("Too few socket activated files passed in")
	}

	if addr == "*" {
		return listeners, nil
	}

	return []net.Listener{listeners[fdOffset]}, nil
}
func main() {

	log.SetFlags(0)
	flag.Parse()

	os.Setenv("DISCOVERY_URL", url)

	if os.Getenv("DISCOVERY_ADDR") != "" {
		http.ListenAndServe(os.Getenv("DISCOVERY_ADDR"), nil)
	} else {
		if *addr != "" {
			http.ListenAndServe(*addr, nil)
		}
	}

	listeners, err := activation.Listeners(true)
	if err != nil {
		panic(err)
	}

	if len(listeners) != 1 {
		log.Print(len(listeners))
		panic("Unexpected number of socket activation fds:")
	}

	http.Serve(listeners[0], nil)
}
Exemple #6
0
func socketActivationListener() net.Listener {
	listeners, err := activation.Listeners(true)
	if err != nil {
		panic(err)
	}

	if len(listeners) != 1 {
		panic(fmt.Sprintf("Unexpected number of socket activation fds, got: %d listeners, expected 1!", len(listeners)))
	}

	return listeners[0]
}
func main() {
	listeners, err := activation.Listeners(true)
	if err != nil {
		panic(err)
	}

	if len(listeners) != 1 {
		panic("Unexpected number of socket activation fds")
	}

	http.HandleFunc("/", HelloServer)
	http.Serve(listeners[0], nil)
}
Exemple #8
0
func (s *Server) systemdServe() {
	// We will usually have at least one TCP socket and one UDP socket.
	// PacketConns are UDP sockets, Listeners are TCP sockets.
	// To make things more annoying, both can (and usually will) have nil
	// entries for the file descriptors that don't match.
	pconns, err := activation.PacketConns(false)
	if err != nil {
		glog.Fatalf("Error getting systemd packet conns: %v", err)
	}

	listeners, err := activation.Listeners(false)
	if err != nil {
		glog.Fatalf("Error getting systemd listeners: %v", err)
	}

	var wg sync.WaitGroup

	for _, pconn := range pconns {
		if pconn == nil {
			continue
		}

		wg.Add(1)
		go func(c net.PacketConn) {
			defer wg.Done()
			glog.Infof("Activate on packet connection (UDP)")
			err := dns.ActivateAndServe(nil, c, dns.HandlerFunc(s.Handler))
			glog.Fatalf("Exiting UDP listener: %v", err)
		}(pconn)
	}

	for _, lis := range listeners {
		if lis == nil {
			continue
		}

		wg.Add(1)
		go func(l net.Listener) {
			defer wg.Done()
			glog.Infof("Activate on listening socket (TCP)")
			err := dns.ActivateAndServe(l, nil, dns.HandlerFunc(s.Handler))
			glog.Fatalf("Exiting TCP listener: %v", err)
		}(lis)
	}

	wg.Wait()

	// We should only get here if there were no useful sockets.
	glog.Fatalf("No systemd sockets, did you forget the .socket?")
}
Exemple #9
0
// Serve either serves on the previously opened sockets if started with systemd-compatible protocol, or:
//  - opens sockets and starts /proc/self/exe in a subprocess with systemd-compatible protocol
//  - gracefully terminates subprocess on SIGTERM
//  - gracefully restarts subprocess on SIGUSR2
func Serve(servers ...*http.Server) error {
	// Simplify LISTEN_PID protocol because it is harder to set PID between
	// fork and exec in Golang.
	pid := os.Getenv(listenPID)
	initActivated := len(pid) != 0 && pid != "0"
	if pid == "0" {
		if err := os.Setenv(listenPID, strconv.Itoa(os.Getpid())); err != nil {
			return err
		}
	}

	listeners, _ := activation.Listeners(true) // ignore error: always nil
	didInherit := len(listeners) != 0

	if *verbose {
		if didInherit {
			if initActivated {
				log.Printf("Listening on init activated %s", pprintAddr(servers))
			} else {
				const msg = "Graceful handoff of %s with new pid %d"
				log.Printf(msg, pprintAddr(servers), os.Getpid())
			}
		} else {
			const msg = "Serving %s with pid %d"
			log.Printf(msg, pprintAddr(servers), os.Getpid())
		}
	}

	if didInherit {
		// Serve.
		return serve(listeners, servers)
	}

	// Listen and fork&exec to serve.
	fds := make([]*os.File, len(servers))
	for i, srv := range servers {
		l, err := net.Listen("tcp", srv.Addr)
		if err != nil {
			return err
		}

		fds[i], err = l.(*net.TCPListener).File()
		if err != nil {
			return err
		}
		defer fds[i].Close() // ignore error
	}

	return runServer(fds)
}
Exemple #10
0
func cmdRunSa(c *cli.Context) error {
	s, err := openAndCheck(c)
	if err != nil {
		return cli.NewExitError(err.Error(), 3)
	}

	listeners, err := activation.Listeners(true)
	if err != nil {
		return cli.NewExitError(fmt.Sprintf("fetching socket listeners from systemd failed: %s", err), 2)
	}

	fmt.Printf("got %d sockets from systemd\n", len(listeners))
	if len(listeners) == 0 {
		return cli.NewExitError("shutting down since there are no sockets to lissten on.", 2)
	}

	var wg sync.WaitGroup
	for idx, listener := range listeners {
		switch listener.(type) {
		case *net.UnixListener:
			fmt.Printf("listener[%d]: is a UNIX socket (-> saslauthd)\n", idx)
			wg.Add(1)
			ln := listener.(*net.UnixListener)
			go func() {
				defer wg.Done()
				if err := runSaslAuthSocketListener(ln, s.GetInterface()); err != nil {
					fmt.Printf("warning running auth agent failed: %s\n", err)
				}
			}()
		case *net.TCPListener:
			fmt.Printf("listener[%d]: is a TCP socket (-> HTTP)\n", idx)
			wg.Add(1)
			ln := listener.(*net.TCPListener)
			go func() {
				defer wg.Done()
				if err := runWebListener(ln, s.GetInterface(), c.GlobalString("web-static-dir")); err != nil {
					fmt.Printf("error running web-api: %s", err)
				}
			}()
		default:
			fmt.Printf("listener[%d]: has type %T (ingnoring)\n", idx, listener)
		}
	}
	wg.Wait()

	return cli.NewExitError(fmt.Sprintf("shutting down since all auth sockets have closed."), 0)
}
// listenFD returns the specified socket activated files as a slice of
// net.Listeners or all of the activated files if "*" is given.
func listenFD(addr string, tlsConfig *tls.Config) ([]net.Listener, error) {
	var (
		err       error
		listeners []net.Listener
	)
	// socket activation
	if tlsConfig != nil {
		listeners, err = activation.TLSListeners(false, tlsConfig)
	} else {
		listeners, err = activation.Listeners(false)
	}
	if err != nil {
		return nil, err
	}

	if len(listeners) == 0 {
		return nil, fmt.Errorf("no sockets found via socket activation: make sure the service was started by systemd")
	}

	// default to all fds just like unix:// and tcp://
	if addr == "" || addr == "*" {
		return listeners, nil
	}

	fdNum, err := strconv.Atoi(addr)
	if err != nil {
		return nil, fmt.Errorf("failed to parse systemd fd address: should be a number: %v", addr)
	}
	fdOffset := fdNum - 3
	if len(listeners) < int(fdOffset)+1 {
		return nil, fmt.Errorf("too few socket activated files passed in by systemd")
	}
	if listeners[fdOffset] == nil {
		return nil, fmt.Errorf("failed to listen on systemd activated file: fd %d", fdOffset+3)
	}
	for i, ls := range listeners {
		if i == fdOffset || ls == nil {
			continue
		}
		if err := ls.Close(); err != nil {
			// TODO: We shouldn't log inside a library. Remove this or error out.
			logrus.Errorf("failed to close systemd activated file: fd %d: %v", fdOffset+3, err)
		}
	}
	return []net.Listener{listeners[fdOffset]}, nil
}
Exemple #12
0
// listenFD returns the specified socket activated files as a slice of
// net.Listeners or all of the activated files if "*" is given.
func listenFD(addr string, tlsConfig *tls.Config) ([]net.Listener, error) {
	var (
		err       error
		listeners []net.Listener
	)
	// socket activation
	if tlsConfig != nil {
		listeners, err = systemdActivation.TLSListeners(false, tlsConfig)
	} else {
		listeners, err = systemdActivation.Listeners(false)
	}
	if err != nil {
		return nil, err
	}

	if len(listeners) == 0 {
		return nil, fmt.Errorf("No sockets found")
	}

	// default to all fds just like unix:// and tcp://
	if addr == "" || addr == "*" {
		return listeners, nil
	}

	fdNum, err := strconv.Atoi(addr)
	if err != nil {
		return nil, fmt.Errorf("failed to parse systemd address, should be number: %v", err)
	}
	fdOffset := fdNum - 3
	if len(listeners) < int(fdOffset)+1 {
		return nil, fmt.Errorf("Too few socket activated files passed in")
	}
	if listeners[fdOffset] == nil {
		return nil, fmt.Errorf("failed to listen on systemd activated file at fd %d", fdOffset+3)
	}
	for i, ls := range listeners {
		if i == fdOffset || ls == nil {
			continue
		}
		if err := ls.Close(); err != nil {
			logrus.Errorf("Failed to close systemd activated file at fd %d: %v", fdOffset+3, err)
		}
	}
	return []net.Listener{listeners[fdOffset]}, nil
}
func main() {
	log.SetFlags(0)
	flag.Parse()

	if *addr != "" {
		http.ListenAndServe(*addr, nil)
	}

	listeners, err := activation.Listeners(true)
	if err != nil {
		panic(err)
	}

	if len(listeners) != 1 {
		panic("Unexpected number of socket activation fds")
	}

	http.Serve(listeners[0], nil)
}
Exemple #14
0
// Init sets up the Daemon's internal workings.
// Don't call more than once.
func (d *Daemon) Init() error {
	t0 := time.Now()
	listeners, err := activation.Listeners(false)
	if err != nil {
		return err
	}

	if len(listeners) != 1 {
		return fmt.Errorf("daemon does not handle %d listeners right now, just one", len(listeners))
	}

	d.listener = listeners[0]

	d.addRoutes()

	logger.Debugf("init done in %s", time.Now().Sub(t0))

	return nil
}
Exemple #15
0
func getListener() (net.Listener, error) {
	l, err := activation.Listeners(true)
	if err != nil {
		return nil, err
	}

	switch {
	case len(l) == 0:
		if err := os.MkdirAll(filepath.Dir(socketPath), 0700); err != nil {
			return nil, err
		}
		return net.Listen("unix", socketPath)

	case len(l) == 1:
		if l[0] == nil {
			return nil, fmt.Errorf("LISTEN_FDS=1 but no FD found")
		}
		return l[0], nil

	default:
		return nil, fmt.Errorf("Too many (%v) FDs passed through socket activation", len(l))
	}
}
Exemple #16
0
// Run is a blocking operation that starts the server listening on the DNS ports.
func (s *server) Run() error {
	mux := dns.NewServeMux()
	mux.Handle(".", s)

	dnsReadyMsg := func(addr, net string) {
		if s.config.DNSSEC == "" {
			log.Printf("skydns: ready for queries on %s for %s://%s [rcache %d]", s.config.Domain, net, addr, s.config.RCache)
		} else {
			log.Printf("skydns: ready for queries on %s for %s://%s [rcache %d], signing with %s [scache %d]", s.config.Domain, net, addr, s.config.RCache, s.config.DNSSEC, s.config.SCache)
		}
	}

	if s.config.Systemd {
		packetConns, err := activation.PacketConns(false)
		if err != nil {
			return err
		}
		listeners, err := activation.Listeners(true)
		if err != nil {
			return err
		}
		if len(packetConns) == 0 && len(listeners) == 0 {
			return fmt.Errorf("no UDP or TCP sockets supplied by systemd")
		}
		for _, p := range packetConns {
			if u, ok := p.(*net.UDPConn); ok {
				s.group.Add(1)
				go func() {
					defer s.group.Done()
					if err := dns.ActivateAndServe(nil, u, mux); err != nil {
						log.Fatalf("skydns: %s", err)
					}
				}()
				dnsReadyMsg(u.LocalAddr().String(), "udp")
			}
		}
		for _, l := range listeners {
			if t, ok := l.(*net.TCPListener); ok {
				s.group.Add(1)
				go func() {
					defer s.group.Done()
					if err := dns.ActivateAndServe(t, nil, mux); err != nil {
						log.Fatalf("skydns: %s", err)
					}
				}()
				dnsReadyMsg(t.Addr().String(), "tcp")
			}
		}
	} else {
		s.group.Add(1)
		go func() {
			defer s.group.Done()
			if err := dns.ListenAndServe(s.config.DnsAddr, "tcp", mux); err != nil {
				log.Fatalf("skydns: %s", err)
			}
		}()
		dnsReadyMsg(s.config.DnsAddr, "tcp")
		s.group.Add(1)
		go func() {
			defer s.group.Done()
			if err := dns.ListenAndServe(s.config.DnsAddr, "udp", mux); err != nil {
				log.Fatalf("skydns: %s", err)
			}
		}()
		dnsReadyMsg(s.config.DnsAddr, "udp")
	}

	s.group.Wait()
	return nil
}
Exemple #17
0
// Run is a blocking operation that starts the server listening on the DNS ports.
func (s *server) Run() error {
	mux := dns.NewServeMux()
	mux.Handle(".", s)

	dnsReadyMsg := func(addr, net string) {
		rCacheState := "disabled"
		if s.config.RCache > 0 {
			rCacheState = fmt.Sprintf("capacity: %d", s.config.RCache)
		}
		log.Infof("Ready for queries on %s://%s [cache: %s]", net, addr, rCacheState)
	}

	if s.config.Systemd {
		packetConns, err := activation.PacketConns(false)
		if err != nil {
			return err
		}
		listeners, err := activation.Listeners(true)
		if err != nil {
			return err
		}
		if len(packetConns) == 0 && len(listeners) == 0 {
			return fmt.Errorf("No UDP or TCP sockets supplied by systemd")
		}
		for _, p := range packetConns {
			if u, ok := p.(*net.UDPConn); ok {
				s.group.Add(1)
				go func() {
					defer s.group.Done()
					if err := dns.ActivateAndServe(nil, u, mux); err != nil {
						log.Fatalf("%s", err)
					}
				}()
				dnsReadyMsg(u.LocalAddr().String(), "udp")
			}
		}
		for _, l := range listeners {
			if t, ok := l.(*net.TCPListener); ok {
				s.group.Add(1)
				go func() {
					defer s.group.Done()
					if err := dns.ActivateAndServe(t, nil, mux); err != nil {
						log.Fatalf("%s", err)
					}
				}()
				dnsReadyMsg(t.Addr().String(), "tcp")
			}
		}
	} else {
		s.group.Add(1)
		go func() {
			defer s.group.Done()
			if err := dns.ListenAndServe(s.config.DnsAddr, "tcp", mux); err != nil {
				log.Fatalf("%s", err)
			}
		}()
		dnsReadyMsg(s.config.DnsAddr, "tcp")
		s.group.Add(1)
		go func() {
			defer s.group.Done()
			if err := dns.ListenAndServe(s.config.DnsAddr, "udp", mux); err != nil {
				log.Fatalf("%s", err)
			}
		}()
		dnsReadyMsg(s.config.DnsAddr, "udp")
	}

	s.group.Wait()
	return nil
}
Exemple #18
0
func (d *Daemon) Init() error {
	/* Initialize some variables */
	d.imagesDownloading = map[string]chan bool{}

	d.readyChan = make(chan bool)
	d.shutdownChan = make(chan bool)

	/* Set the executable path */
	absPath, err := os.Readlink("/proc/self/exe")
	if err != nil {
		return err
	}
	d.execPath = absPath

	/* Set the LVM environment */
	err = os.Setenv("LVM_SUPPRESS_FD_WARNINGS", "1")
	if err != nil {
		return err
	}

	/* Setup logging if that wasn't done before */
	if shared.Log == nil {
		shared.Log, err = logging.GetLogger("", "", true, true, nil)
		if err != nil {
			return err
		}
	}

	/* Print welcome message */
	if d.MockMode {
		shared.Log.Info("LXD is starting in mock mode",
			log.Ctx{"path": shared.VarPath("")})
	} else if d.SetupMode {
		shared.Log.Info("LXD is starting in setup mode",
			log.Ctx{"path": shared.VarPath("")})
	} else {
		shared.Log.Info("LXD is starting in normal mode",
			log.Ctx{"path": shared.VarPath("")})
	}

	/* Detect user namespaces */
	runningInUserns = shared.RunningInUserNS()

	/* Detect AppArmor support */
	if aaAvailable && os.Getenv("LXD_SECURITY_APPARMOR") == "false" {
		aaAvailable = false
		aaAdmin = false
		shared.Log.Warn("AppArmor support has been manually disabled")
	}

	if aaAvailable && !shared.IsDir("/sys/kernel/security/apparmor") {
		aaAvailable = false
		aaAdmin = false
		shared.Log.Warn("AppArmor support has been disabled because of lack of kernel support")
	}

	_, err = exec.LookPath("apparmor_parser")
	if aaAvailable && err != nil {
		aaAvailable = false
		aaAdmin = false
		shared.Log.Warn("AppArmor support has been disabled because 'apparmor_parser' couldn't be found")
	}

	/* Detect AppArmor admin support */
	if aaAdmin && !haveMacAdmin() {
		aaAdmin = false
		shared.Log.Warn("Per-container AppArmor profiles are disabled because the mac_admin capability is missing.")
	}

	if aaAdmin && runningInUserns {
		aaAdmin = false
		shared.Log.Warn("Per-container AppArmor profiles are disabled because LXD is running in an unprivileged container.")
	}

	/* Detect AppArmor confinment */
	if !aaConfined {
		profile := aaProfile()
		if profile != "unconfined" && profile != "" {
			aaConfined = true
			shared.Log.Warn("Per-container AppArmor profiles are disabled because LXD is already protected by AppArmor.")
		}
	}

	/* Detect CGroup support */
	cgBlkioController = shared.PathExists("/sys/fs/cgroup/blkio/")
	if !cgBlkioController {
		shared.Log.Warn("Couldn't find the CGroup blkio controller, I/O limits will be ignored.")
	}

	cgCpuController = shared.PathExists("/sys/fs/cgroup/cpu/")
	if !cgCpuController {
		shared.Log.Warn("Couldn't find the CGroup CPU controller, CPU time limits will be ignored.")
	}

	cgCpusetController = shared.PathExists("/sys/fs/cgroup/cpuset/")
	if !cgCpusetController {
		shared.Log.Warn("Couldn't find the CGroup CPUset controller, CPU pinning will be ignored.")
	}

	cgDevicesController = shared.PathExists("/sys/fs/cgroup/devices/")
	if !cgDevicesController {
		shared.Log.Warn("Couldn't find the CGroup devices controller, device access control won't work.")
	}

	cgMemoryController = shared.PathExists("/sys/fs/cgroup/memory/")
	if !cgMemoryController {
		shared.Log.Warn("Couldn't find the CGroup memory controller, memory limits will be ignored.")
	}

	cgNetPrioController = shared.PathExists("/sys/fs/cgroup/net_prio/")
	if !cgNetPrioController {
		shared.Log.Warn("Couldn't find the CGroup network class controller, network limits will be ignored.")
	}

	cgPidsController = shared.PathExists("/sys/fs/cgroup/pids/")
	if !cgPidsController {
		shared.Log.Warn("Couldn't find the CGroup pids controller, process limits will be ignored.")
	}

	cgSwapAccounting = shared.PathExists("/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes")
	if !cgSwapAccounting {
		shared.Log.Warn("CGroup memory swap accounting is disabled, swap limits will be ignored.")
	}

	/* Get the list of supported architectures */
	var architectures = []int{}

	architectureName, err := shared.ArchitectureGetLocal()
	if err != nil {
		return err
	}

	architecture, err := shared.ArchitectureId(architectureName)
	if err != nil {
		return err
	}
	architectures = append(architectures, architecture)

	personalities, err := shared.ArchitecturePersonalities(architecture)
	if err != nil {
		return err
	}
	for _, personality := range personalities {
		architectures = append(architectures, personality)
	}
	d.architectures = architectures

	/* Set container path */
	d.lxcpath = shared.VarPath("containers")

	/* Make sure all our directories are available */
	if err := os.MkdirAll(shared.VarPath("containers"), 0711); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("devices"), 0711); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("devlxd"), 0755); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("images"), 0700); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.LogPath(), 0700); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("security"), 0700); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("shmounts"), 0711); err != nil {
		return err
	}
	if err := os.MkdirAll(shared.VarPath("snapshots"), 0700); err != nil {
		return err
	}

	/* Detect the filesystem */
	d.BackingFs, err = filesystemDetect(d.lxcpath)
	if err != nil {
		shared.Log.Error("Error detecting backing fs", log.Ctx{"err": err})
	}

	/* Read the uid/gid allocation */
	d.IdmapSet, err = shared.DefaultIdmapSet()
	if err != nil {
		shared.Log.Warn("Error reading idmap", log.Ctx{"err": err.Error()})
		shared.Log.Warn("Only privileged containers will be able to run")
	} else {
		shared.Log.Info("Default uid/gid map:")
		for _, lxcmap := range d.IdmapSet.ToLxcString() {
			shared.Log.Info(strings.TrimRight(" - "+lxcmap, "\n"))
		}
	}

	/* Initialize the database */
	err = initializeDbObject(d, shared.VarPath("lxd.db"))
	if err != nil {
		return err
	}

	/* Setup the storage driver */
	if !d.MockMode {
		err = d.SetupStorageDriver()
		if err != nil {
			return fmt.Errorf("Failed to setup storage: %s", err)
		}
	}

	/* Load all config values from the database */
	_, err = d.ConfigValuesGet()
	if err != nil {
		return err
	}

	/* set the initial proxy function based on config values in the DB */
	d.updateProxy()

	/* Setup /dev/lxd */
	d.devlxd, err = createAndBindDevLxd()
	if err != nil {
		return err
	}

	if err := setupSharedMounts(); err != nil {
		return err
	}

	if !d.MockMode {
		/* Start the scheduler */
		go deviceEventListener(d)

		/* Setup the TLS authentication */
		certf, keyf, err := readMyCert()
		if err != nil {
			return err
		}

		cert, err := tls.LoadX509KeyPair(certf, keyf)
		if err != nil {
			return err
		}

		tlsConfig := &tls.Config{
			InsecureSkipVerify: true,
			ClientAuth:         tls.RequestClientCert,
			Certificates:       []tls.Certificate{cert},
			MinVersion:         tls.VersionTLS12,
			MaxVersion:         tls.VersionTLS12,
			CipherSuites: []uint16{
				tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
			PreferServerCipherSuites: true,
		}
		tlsConfig.BuildNameToCertificate()

		d.tlsConfig = tlsConfig

		readSavedClientCAList(d)
	}

	/* Setup the web server */
	d.mux = mux.NewRouter()
	d.mux.StrictSlash(false)

	d.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		SyncResponse(true, []string{"/1.0"}).Render(w)
	})

	for _, c := range api10 {
		d.createCmd("1.0", c)
	}

	for _, c := range apiInternal {
		d.createCmd("internal", c)
	}

	d.mux.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		shared.Log.Debug("Sending top level 404", log.Ctx{"url": r.URL})
		w.Header().Set("Content-Type", "application/json")
		NotFound.Render(w)
	})

	listeners, err := activation.Listeners(false)
	if err != nil {
		return err
	}

	if len(listeners) > 0 {
		shared.Log.Info("LXD is socket activated")

		for _, listener := range listeners {
			if shared.PathExists(listener.Addr().String()) {
				d.UnixSocket = &Socket{Socket: listener, CloseOnExit: false}
			} else {
				tlsListener := tls.NewListener(listener, d.tlsConfig)
				d.TCPSocket = &Socket{Socket: tlsListener, CloseOnExit: false}
			}
		}
	} else {
		shared.Log.Info("LXD isn't socket activated")

		localSocketPath := shared.VarPath("unix.socket")

		// If the socket exists, let's try to connect to it and see if there's
		// a lxd running.
		if shared.PathExists(localSocketPath) {
			_, err := lxd.NewClient(&lxd.DefaultConfig, "local")
			if err != nil {
				shared.Log.Debug("Detected stale unix socket, deleting")
				// Connecting failed, so let's delete the socket and
				// listen on it ourselves.
				err = os.Remove(localSocketPath)
				if err != nil {
					return err
				}
			} else {
				return fmt.Errorf("LXD is already running.")
			}
		}

		unixAddr, err := net.ResolveUnixAddr("unix", localSocketPath)
		if err != nil {
			return fmt.Errorf("cannot resolve unix socket address: %v", err)
		}

		unixl, err := net.ListenUnix("unix", unixAddr)
		if err != nil {
			return fmt.Errorf("cannot listen on unix socket: %v", err)
		}

		if err := os.Chmod(localSocketPath, 0660); err != nil {
			return err
		}

		var gid int
		if d.group != "" {
			gid, err = shared.GroupId(d.group)
			if err != nil {
				return err
			}
		} else {
			gid = os.Getgid()
		}

		if err := os.Chown(localSocketPath, os.Getuid(), gid); err != nil {
			return err
		}

		d.UnixSocket = &Socket{Socket: unixl, CloseOnExit: true}
	}

	listenAddr, err := d.ConfigValueGet("core.https_address")
	if err != nil {
		return err
	}

	if listenAddr != "" {
		_, _, err := net.SplitHostPort(listenAddr)
		if err != nil {
			listenAddr = fmt.Sprintf("%s:%s", listenAddr, shared.DefaultPort)
		}

		tcpl, err := tls.Listen("tcp", listenAddr, d.tlsConfig)
		if err != nil {
			shared.Log.Error("cannot listen on https socket, skipping...", log.Ctx{"err": err})
		} else {
			if d.TCPSocket != nil {
				shared.Log.Info("Replacing systemd TCP socket by configure one")
				d.TCPSocket.Socket.Close()
			}
			d.TCPSocket = &Socket{Socket: tcpl, CloseOnExit: true}
		}
	}

	d.tomb.Go(func() error {
		shared.Log.Info("REST API daemon:")
		if d.UnixSocket != nil {
			shared.Log.Info(" - binding Unix socket", log.Ctx{"socket": d.UnixSocket.Socket.Addr()})
			d.tomb.Go(func() error { return http.Serve(d.UnixSocket.Socket, &lxdHttpServer{d.mux, d}) })
		}

		if d.TCPSocket != nil {
			shared.Log.Info(" - binding TCP socket", log.Ctx{"socket": d.TCPSocket.Socket.Addr()})
			d.tomb.Go(func() error { return http.Serve(d.TCPSocket.Socket, &lxdHttpServer{d.mux, d}) })
		}

		d.tomb.Go(func() error {
			server := devLxdServer(d)
			return server.Serve(d.devlxd)
		})
		return nil
	})

	if !d.MockMode && !d.SetupMode {
		err := d.Ready()
		if err != nil {
			return err
		}
	}

	return nil
}
Exemple #19
0
func main() {
	var patterns []matcher
	var n int

	if len(os.Args) < 2 {
		usage()
	}

	for n = 1; ; n += 1 {
		if bytes.Equal([]byte(os.Args[n])[:2], []byte("--")) {
			break
		}

		if n == len(os.Args)-1 {
			usage()
		}
	}

	firstFilterArg := n

	for ; n < len(os.Args)-1; n += 2 {
		if bytes.Equal([]byte(os.Args[n]), []byte("--regex")) {
			if len(os.Args) < n+2 {
				fmt.Println("Not enough arguments to --regex")
				os.Exit(1)
			}
			host, port, err := parseHostPort(os.Args[n+2])
			if err != nil {
				fmt.Println("Bad host:port specification:", os.Args[n+2], host, port, err)
				os.Exit(1)
			}

			r, err := regexp.Compile(os.Args[n+1])
			if err != nil {
				fmt.Println("Failed to compile regular expression:", os.Args[n+1], err)
				os.Exit(1)
			}

			patterns = append(patterns, (func(packet []byte, length int) (h string, p int) {
				h = host
				if r.Match(packet) {
					p = port
				}
				return
			}))

			n += 1
			continue
		}

		host, port, err := parseHostPort(os.Args[n+1])
		if err != nil {
			fmt.Println("Bad host:port specification:", os.Args[n+1], host, port, err)
			os.Exit(1)
		}
		if bytes.Equal([]byte(os.Args[n]), []byte("--ssh")) {
			patterns = append(patterns, (func(packet []byte, length int) (h string, p int) {
				h = host
				if bytes.Equal(packet[:4], []byte("SSH-")) {
					p = port
				}
				return
			}))
		} else if bytes.Equal([]byte(os.Args[n]), []byte("--ssl")) {
			patterns = append(patterns, (func(pack []byte, length int) (h string, p int) {
				h = host
				if bytes.Equal(pack[:2], []byte{0x16, 0x03}) && pack[3] >= 0x00 && pack[3] <= 0x03 {
					p = port
				}
				return
			}))
		} else if bytes.Equal([]byte(os.Args[n]), []byte("--openvpn")) {
			patterns = append(patterns, (func(pack []byte, length int) (h string, p int) {
				var l uint16
				h = host
				binary.Read(bytes.NewReader(pack), binary.BigEndian, &l)
				if l == uint16(length-2) {
					p = port
				}
				return
			}))
		}
	}

	listeners, err := activation.Listeners(true)

	if err != nil {
		panic(err)
	}

	// If we recieved any sockets from systemd do not open our own listeners
	if len(listeners) > 0 {
		for _, ln := range listeners {
			go handleListener(ln, patterns)
		}
	} else {
		if firstFilterArg == 1 {
			fmt.Println("No listen port(s) specified and did not recieve and not being systemd socket activated")
			os.Exit(1)
		}

		for n = 1; n < firstFilterArg; n += 1 {
			host, port, err := parseHostPort(os.Args[n])

			if err != nil {
				fmt.Println("Bad Listen host:port:", os.Args[n])
				break
			}

			if bytes.Compare([]byte(host), []byte("localhost")) == 0 {
				host = "0.0.0.0"
			}

			ln, err := net.Listen("tcp", fmt.Sprint(host, ":", port))
			if err != nil {
				fmt.Println("Listen failed:", err)
				break
			}

			go handleListener(ln, patterns)
		}
	}
}
Exemple #20
0
func New(cfg config.Config, listeners []net.Listener) (*Server, error) {
	agentTTL, err := time.ParseDuration(cfg.AgentTTL)
	if err != nil {
		return nil, err
	}

	mgr, err := systemd.NewSystemdUnitManager(systemd.DefaultUnitsDirectory)
	if err != nil {
		return nil, err
	}

	mach, err := newMachineFromConfig(cfg, mgr)
	if err != nil {
		return nil, err
	}

	tlsConfig, err := pkg.ReadTLSConfigFiles(cfg.EtcdCAFile, cfg.EtcdCertFile, cfg.EtcdKeyFile)
	if err != nil {
		return nil, err
	}

	eCfg := etcd.Config{
		Transport:               &http.Transport{TLSClientConfig: tlsConfig},
		Endpoints:               cfg.EtcdServers,
		HeaderTimeoutPerRequest: (time.Duration(cfg.EtcdRequestTimeout*1000) * time.Millisecond),
	}
	eClient, err := etcd.New(eCfg)
	if err != nil {
		return nil, err
	}

	kAPI := etcd.NewKeysAPI(eClient)
	reg := registry.NewEtcdRegistry(kAPI, cfg.EtcdKeyPrefix)

	pub := agent.NewUnitStatePublisher(reg, mach, agentTTL)
	gen := unit.NewUnitStateGenerator(mgr)

	a := agent.New(mgr, gen, reg, mach, agentTTL)

	var rStream pkg.EventStream
	if !cfg.DisableWatches {
		rStream = registry.NewEtcdEventStream(kAPI, cfg.EtcdKeyPrefix)
	}
	lManager := lease.NewEtcdLeaseManager(kAPI, cfg.EtcdKeyPrefix)

	ar := agent.NewReconciler(reg, rStream)

	e := engine.New(reg, lManager, rStream, mach)

	if len(listeners) == 0 {
		listeners, err = activation.Listeners(false)
		if err != nil {
			return nil, err
		}
	}

	hrt := heart.New(reg, mach)
	mon := NewMonitor(agentTTL)

	apiServer := api.NewServer(listeners, api.NewServeMux(reg, cfg.TokenLimit))
	apiServer.Serve()

	eIval := time.Duration(cfg.EngineReconcileInterval*1000) * time.Millisecond

	srv := Server{
		agent:       a,
		aReconciler: ar,
		usGen:       gen,
		usPub:       pub,
		engine:      e,
		mach:        mach,
		hrt:         hrt,
		mon:         mon,
		api:         apiServer,
		killc:       make(chan struct{}),
		stopc:       nil,
		engineReconcileInterval: eIval,
		disableEngine:           cfg.DisableEngine,
		reconfigServer:          false,
		restartServer:           false,
	}

	return &srv, nil
}
Exemple #21
0
// NewServer starts an HTTPS server the handles the redoctober JSON
// API. Each of the URIs in the functions map above is setup with a
// separate HandleFunc. Each HandleFunc is an instance of queueRequest
// above.
//
// Returns a valid http.Server handling redoctober JSON requests (and
// its associated listener) or an error
func NewServer(process chan<- userRequest, staticPath, addr, caPath string, certPaths, keyPaths []string, useSystemdSocket bool) (*http.Server, *net.Listener, error) {
	config := &tls.Config{
		PreferServerCipherSuites: true,
		SessionTicketsDisabled:   true,
	}
	for i, certPath := range certPaths {
		cert, err := tls.LoadX509KeyPair(certPath, keyPaths[i])
		if err != nil {
			return nil, nil, fmt.Errorf("Error loading certificate (%s, %s): %s", certPath, keyPaths[i], err)
		}
		config.Certificates = append(config.Certificates, cert)
	}
	config.BuildNameToCertificate()

	// If a caPath has been specified then a local CA is being used
	// and not the system configuration.

	if caPath != "" {
		pemCert, err := ioutil.ReadFile(caPath)
		if err != nil {
			return nil, nil, fmt.Errorf("Error reading %s: %s\n", caPath, err)
		}

		derCert, _ := pem.Decode(pemCert)
		if derCert == nil {
			return nil, nil, fmt.Errorf("No PEM data was found in the CA certificate file\n")
		}

		cert, err := x509.ParseCertificate(derCert.Bytes)
		if err != nil {
			return nil, nil, fmt.Errorf("Error parsing CA certificate: %s\n", err)
		}

		rootPool := x509.NewCertPool()
		rootPool.AddCert(cert)

		config.ClientAuth = tls.RequireAndVerifyClientCert
		config.ClientCAs = rootPool
	}

	var lstnr net.Listener
	if useSystemdSocket {
		listenFDs, err := activation.Listeners(true)
		if err != nil {
			log.Fatal(err)
		}
		if len(listenFDs) != 1 {
			log.Fatalf("Unexpected number of socket activation FDs! (%d)", len(listenFDs))
		}
		lstnr = tls.NewListener(listenFDs[0], config)
	} else {
		conn, err := net.Listen("tcp", addr)
		if err != nil {
			return nil, nil, fmt.Errorf("Error starting TCP listener on %s: %s\n", addr, err)
		}

		lstnr = tls.NewListener(conn, config)

	}
	mux := http.NewServeMux()

	// queue up post URIs
	for current := range functions {
		// copy this so reference does not get overwritten
		requestType := current
		mux.HandleFunc(requestType, func(w http.ResponseWriter, r *http.Request) {
			log.Printf("http.server: endpoint=%s remote=%s", requestType, r.RemoteAddr)
			queueRequest(process, requestType, w, r)
		})
	}

	// queue up web frontend
	idxHandler := &indexHandler{staticPath}
	mux.HandleFunc("/index", idxHandler.handle)
	mux.HandleFunc("/", idxHandler.handle)

	srv := http.Server{
		Addr:    addr,
		Handler: mux,
	}

	return &srv, &lstnr, nil
}
Exemple #22
0
func New(cfg config.Config, listeners []net.Listener) (*Server, error) {
	agentTTL, err := time.ParseDuration(cfg.AgentTTL)
	if err != nil {
		return nil, err
	}

	mgr, err := systemd.NewSystemdUnitManager(cfg.UnitsDirectory, cfg.SystemdUser)
	if err != nil {
		return nil, err
	}

	mach, err := newMachineFromConfig(cfg, mgr)
	if err != nil {
		return nil, err
	}

	tlsConfig, err := pkg.ReadTLSConfigFiles(cfg.EtcdCAFile, cfg.EtcdCertFile, cfg.EtcdKeyFile)
	if err != nil {
		return nil, err
	}

	eCfg := etcd.Config{
		Transport:               &http.Transport{TLSClientConfig: tlsConfig},
		Endpoints:               cfg.EtcdServers,
		HeaderTimeoutPerRequest: (time.Duration(cfg.EtcdRequestTimeout*1000) * time.Millisecond),
		Username:                cfg.EtcdUsername,
		Password:                cfg.EtcdPassword,
	}

	eClient, err := etcd.New(eCfg)
	if err != nil {
		return nil, err
	}

	kAPI := etcd.NewKeysAPI(eClient)

	var (
		reg        engine.CompleteRegistry
		genericReg interface{}
	)
	lManager := lease.NewEtcdLeaseManager(kAPI, cfg.EtcdKeyPrefix)

	if !cfg.EnableGRPC {
		genericReg = registry.NewEtcdRegistry(kAPI, cfg.EtcdKeyPrefix)
		if obj, ok := genericReg.(engine.CompleteRegistry); ok {
			reg = obj
		}
	} else {
		etcdReg := registry.NewEtcdRegistry(kAPI, cfg.EtcdKeyPrefix)
		genericReg = rpc.NewRegistryMux(etcdReg, mach, lManager)
		if obj, ok := genericReg.(engine.CompleteRegistry); ok {
			reg = obj
		}
	}

	pub := agent.NewUnitStatePublisher(reg, mach, agentTTL)
	gen := unit.NewUnitStateGenerator(mgr)

	a := agent.New(mgr, gen, reg, mach, agentTTL)

	var rStream pkg.EventStream
	if !cfg.DisableWatches {
		rStream = registry.NewEtcdEventStream(kAPI, cfg.EtcdKeyPrefix)
	}

	ar := agent.NewReconciler(reg, rStream)

	var e *engine.Engine
	if !cfg.EnableGRPC {
		e = engine.New(reg, lManager, rStream, mach, nil)
	} else {
		regMux := genericReg.(*rpc.RegistryMux)
		e = engine.New(reg, lManager, rStream, mach, regMux.EngineChanged)
		if cfg.DisableEngine {
			go regMux.ConnectToRegistry(e)
		}
	}

	if len(listeners) == 0 {
		listeners, err = activation.Listeners(false)
		if err != nil {
			return nil, err
		}
	}

	hrt := heart.New(reg, mach)
	mon := NewMonitor(agentTTL)

	apiServer := api.NewServer(listeners, api.NewServeMux(reg, cfg.TokenLimit))
	apiServer.Serve()

	eIval := time.Duration(cfg.EngineReconcileInterval*1000) * time.Millisecond

	srv := Server{
		agent:       a,
		aReconciler: ar,
		usGen:       gen,
		usPub:       pub,
		engine:      e,
		mach:        mach,
		hrt:         hrt,
		mon:         mon,
		api:         apiServer,
		killc:       make(chan struct{}),
		stopc:       nil,
		engineReconcileInterval: eIval,
		disableEngine:           cfg.DisableEngine,
		reconfigServer:          false,
		restartServer:           false,
	}

	return &srv, nil
}