Example #1
0
func (m *AttachManager) Attach(app *defines.Meta) {
	// Not Thread Safe
	if m.Attached(app.ID) {
		return
	}
	outrd, outwr := io.Pipe()
	errrd, errwr := io.Pipe()
	go func() {
		err := g.Docker.AttachToContainer(docker.AttachToContainerOptions{
			Container:    app.ID,
			OutputStream: outwr,
			ErrorStream:  errwr,
			Stdin:        false,
			Stdout:       true,
			Stderr:       true,
			Stream:       true,
		})
		outwr.Close()
		errwr.Close()
		logs.Debug("Lenz Attach", app.ID[:12], "finished")
		if err != nil {
			logs.Debug("Lenz Attach", app.ID, "failure:", err)
		}
		m.send(&defines.AttachEvent{Type: "detach", App: app})
		m.Lock()
		defer m.Unlock()
		delete(m.attached, app.ID)
	}()
	m.Lock()
	m.attached[app.ID] = NewLogPump(outrd, errrd, app)
	m.Unlock()
	m.send(&defines.AttachEvent{Type: "attach", App: app})
	logs.Debug("Lenz Attach", app.ID[:12], "success")
}
Example #2
0
func monitor() {
	for event := range events {
		switch event.Status {
		case common.STATUS_DIE:
			logs.Debug("Status", event.Status, event.ID[:12], event.From)
			app.Remove(event.ID)
			reportContainerDeath(event.ID)
		case common.STATUS_START:
			logs.Debug("Status", event.Status, event.ID[:12], event.From)
			// if not in watching list, just ignore it
			if meta := getContainerMeta(event.ID); meta != nil && !app.Valid(event.ID) {
				container, err := g.Docker.InspectContainer(event.ID)
				if err != nil {
					logs.Info("Status inspect docker failed", err)
					break
				}
				eruApp := app.NewEruApp(container, meta)
				if eruApp == nil {
					logs.Info("Create EruApp failed")
					break
				}
				lenz.Attacher.Attach(&eruApp.Meta)
				app.Add(eruApp)
				reportContainerCure(event.ID)
			}
		}
	}
}
Example #3
0
func load() {
	containers, err := g.Docker.ListContainers(docker.ListContainersOptions{All: true})
	if err != nil {
		logs.Assert(err, "List containers")
	}

	conn := g.GetRedisConn()
	defer g.ReleaseRedisConn(conn)
	containersKey := fmt.Sprintf("eru:agent:%s:containers:meta", g.Config.HostName)
	logs.Debug("Status get targets from", containersKey)
	rep, err := gore.NewCommand("HGETALL", containersKey).Run(conn)
	if err != nil {
		logs.Assert(err, "Status get targets")
	}

	if rep.IsNil() {
		return
	}

	targets, err := rep.Map()
	if err != nil {
		logs.Assert(err, "Status load targets")
	}

	logs.Debug("Status targets:", targets)
	logs.Info("Status load container")
	for _, container := range containers {
		if _, ok := targets[container.ID]; !ok {
			continue
		}

		status := getStatus(container.Status)
		if status != common.STATUS_START {
			reportContainerDeath(container.ID)
			continue
		}
		var meta map[string]interface{}
		if err := json.Unmarshal([]byte(targets[container.ID]), &meta); err != nil {
			logs.Info("Status load failed", err)
			continue
		}

		c, err := g.Docker.InspectContainer(container.ID)
		if err != nil {
			logs.Info("Status inspect docker failed", err)
			continue
		}

		if eruApp := app.NewEruApp(c, meta); eruApp != nil {
			lenz.Attacher.Attach(&eruApp.Meta)
			app.Add(eruApp)
			reportContainerCure(container.ID)
		}
	}
}
Example #4
0
func getClient(conn ssh.ConnMetadata) (*ssh.Client, error) {
	Lock.RLock()
	defer Lock.RUnlock()
	meta := MetaData[conn.RemoteAddr()]
	logs.Debug("Connection accepted from", conn.RemoteAddr())
	return meta.Client, nil
}
Example #5
0
func NewEruApp(container *docker.Container, extend map[string]interface{}) *EruApp {
	name, entrypoint, ident := utils.GetAppInfo(container.Name)
	if name == "" {
		logs.Info("Container name invaild", container.Name)
		return nil
	}
	logs.Debug("Eru App", name, entrypoint, ident)

	transfer, _ := g.Transfers.Get(container.ID, 0)
	client := falcon.CreateFalconClient(
		transfer,
		time.Duration(g.Config.Metrics.Timeout)*time.Millisecond,
	)

	step := time.Duration(g.Config.Metrics.Step) * time.Second
	extend["hostname"] = g.Config.HostName
	extend["cid"] = container.ID[:12]
	extend["ident"] = ident
	tag := []string{}
	for k, v := range extend {
		tag = append(tag, fmt.Sprintf("%s=%v", k, v))
	}
	endpoint := fmt.Sprintf("%s-%s", name, entrypoint)

	meta := defines.Meta{container.ID, container.State.Pid, name, entrypoint, ident, extend}
	metric := metric.CreateMetric(step, client, strings.Join(tag, ","), endpoint)
	eruApp := &EruApp{meta, metric}
	return eruApp
}
Example #6
0
func closeConn(conn ssh.ConnMetadata) error {
	Lock.Lock()
	defer Lock.Unlock()
	defer delete(MetaData, conn.RemoteAddr())
	logs.Debug("Clean sessions")
	return nil
}
Example #7
0
func NewLogPump(stdout, stderr io.Reader, app *defines.Meta) *LogPump {
	obj := &LogPump{
		app:      app,
		channels: make(map[chan *defines.Log]struct{}),
	}
	pump := func(typ string, source io.Reader) {
		buf := bufio.NewReader(source)
		for {
			data, err := buf.ReadBytes('\n')
			if err != nil {
				if err != io.EOF {
					logs.Debug("Lenz Pump:", app.ID, typ, err)
				}
				return
			}
			obj.send(&defines.Log{
				Data:       strings.TrimSuffix(string(data), "\n"),
				ID:         app.ID,
				Name:       app.Name,
				EntryPoint: app.EntryPoint,
				Ident:      app.Ident,
				Type:       typ,
				Datetime:   time.Now().Format(common.DATETIME_FORMAT),
			})
		}
	}
	go pump("stdout", stdout)
	go pump("stderr", stderr)
	return obj
}
Example #8
0
func InitLenz() {
	Attacher = NewAttachManager()
	Router = NewRouteManager(Attacher)
	Routefs = RouteFileStore(g.Config.Lenz.Routes)
	if len(g.Config.Lenz.Forwards) > 0 {
		logs.Debug("Lenz Routing all to", g.Config.Lenz.Forwards)
		target := defines.Target{Addrs: g.Config.Lenz.Forwards}
		route := defines.Route{ID: common.LENZ_DEFAULT, Target: &target}
		route.LoadBackends()
		Router.Add(&route)
	}
	if _, err := os.Stat(g.Config.Lenz.Routes); err == nil {
		logs.Debug("Loading and persisting routes in", g.Config.Lenz.Routes)
		logs.Assert(Router.Load(Routefs), "persistor")
	}
	logs.Info("Lenz initiated")
}
Example #9
0
func DoPut(url string) {
	req, err := http.NewRequest("PUT", url, nil)
	if err != nil {
		logs.Debug("Gen request failed", err)
		return
	}
	response, err := httpClient.Do(req)
	if err != nil {
		logs.Debug("Do request failed", err)
		return
	}
	defer response.Body.Close()
	data, err := ioutil.ReadAll(response.Body)
	if err != nil {
		logs.Debug("Read response failed", err)
		return
	}
	logs.Debug("Response:", string(data))
}
Example #10
0
func reportContainerDeath(cid string) {
	conn := g.GetRedisConn()
	defer g.ReleaseRedisConn(conn)

	flagKey := fmt.Sprintf("eru:agent:%s:container:flag", cid)
	rep, err := gore.NewCommand("GET", flagKey).Run(conn)
	if err != nil {
		logs.Info("Status failed in get flag", err)
		return
	}
	if !rep.IsNil() {
		gore.NewCommand("DEL", flagKey).Run(conn)
		logs.Debug(cid[:12], "Status flag set, ignore")
		return
	}

	url := fmt.Sprintf("%s/api/container/%s/kill/", g.Config.Eru.Endpoint, cid)
	utils.DoPut(url)
	logs.Debug(cid[:12], "dead, remove from watching list")
}
Example #11
0
func LoadKey(keyPath string) (ssh.Signer, error) {
	bytes, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return nil, err
	}

	logs.Debug(keyPath, GetFingerPrint(bytes))
	key, err := ssh.ParsePrivateKey(bytes)
	if err != nil {
		return nil, err
	}
	return key, nil
}
Example #12
0
func softOOMKill(cid string, rate float64) {
	logs.Debug("OOM killed", cid[:12])
	conn := g.GetRedisConn()
	defer g.ReleaseRedisConn(conn)

	key := fmt.Sprintf("eru:agent:%s:container:reason", cid)
	if _, err := gore.NewCommand("SET", key, common.OOM_KILLED).Run(conn); err != nil {
		logs.Info("OOM killed set flag", err)
	}
	if err := g.Docker.StopContainer(cid, 10); err != nil {
		logs.Info("OOM killed failed", cid[:12])
		return
	}
	logs.Info("OOM killed success", cid[:12])
}
Example #13
0
func load(configPath string) {
	if _, err := os.Stat(configPath); err != nil {
		logs.Assert(err, "config file invaild")
	}

	b, err := ioutil.ReadFile(configPath)
	if err != nil {
		logs.Assert(err, "Read config file failed")
	}

	if err := yaml.Unmarshal(b, &Config); err != nil {
		logs.Assert(err, "Load config file failed")
	}

	logs.Debug("Configure:", Config)
}
Example #14
0
func (self *UpStream) createTCPConn() error {
	self.scheme = "tcp"
	tcpAddr, err := net.ResolveTCPAddr("tcp", self.addr)
	if err != nil {
		logs.Info("Resolve", self.addr, "failed", err)
		return err
	}
	conn, err := net.DialTCP("tcp", nil, tcpAddr)
	if err != nil {
		logs.Debug("Connect backend failed", err)
		return err
	}
	self.conn = conn
	self.encoder = json.NewEncoder(conn)
	self.Close = conn.Close
	return nil
}
Example #15
0
func judgeMemoryUsage() {
	var totalUsage uint64 = 0
	var rate map[string]float64 = make(map[string]float64)
	for cid, usage := range usage {
		totalUsage = totalUsage + usage
		//TODO ugly
		if v, ok := Apps[cid].Extend["__memory__"]; !ok {
			rate[cid] = 0.0
			continue
		} else {
			define, _ := v.(float64)
			rate[cid] = float64(usage) / define
		}
	}
	logs.Debug("Current memory usage", totalUsage, "max", g.Config.Limit.Memory)
	for {
		if totalUsage < g.Config.Limit.Memory {
			return
		}
		var exceedRate float64 = 0.0
		var cid string = ""
		for k, v := range rate {
			if exceedRate >= v {
				continue
			}
			exceedRate = v
			cid = k
		}
		if cid == "" {
			logs.Info("MemLimit can not stop containers")
			break
		}
		softOOMKill(cid, exceedRate)
		totalUsage -= usage[cid]
		delete(rate, cid)
	}
	for k, _ := range usage {
		delete(usage, k)
	}
}
Example #16
0
func (self *SSHConn) serve() error {
	serverConn, chans, reqs, err := ssh.NewServerConn(self.Conn, self.config)
	if err != nil {
		return err
	}
	defer serverConn.Close()

	clientConn, err := getClient(serverConn)
	if err != nil {
		return err
	}
	defer clientConn.Close()

	go ssh.DiscardRequests(reqs)

	for newChannel := range chans {
		remoteChannel, remoteRequest, err := clientConn.OpenChannel(newChannel.ChannelType(), newChannel.ExtraData())
		if err != nil {
			return err
		}

		localChannel, localRequest, err := newChannel.Accept()
		if err != nil {
			return err
		}

		// connect requests
		go func() {
			logs.Debug("Waiting for request")
		r:
			for {
				var req *ssh.Request
				var dst ssh.Channel

				select {
				case req = <-localRequest:
					dst = remoteChannel
					logs.Debug("from local to remote")
				case req = <-remoteRequest:
					dst = localChannel
					logs.Debug("from remote to local")
				}

				if req == nil {
					break
				}

				logs.Debug("Request", req.Type, req.WantReply)
				b, err := dst.SendRequest(req.Type, req.WantReply, req.Payload)
				if err != nil {
					logs.Info(err)
				}
				if req.WantReply {
					req.Reply(b, nil)
				}
				switch req.Type {
				case "exit-status":
					break r
				}
			}
		}()

		// connect channels
		logs.Debug("Connecting channels")

		go func() {
			defer remoteChannel.Close()
			io.Copy(remoteChannel, localChannel)
			remoteChannel.SendRequest("exit-status", false, []byte{0, 0, 0, 0})
		}()
		go func() {
			defer localChannel.Close()
			io.Copy(localChannel, remoteChannel)
			localChannel.SendRequest("exit-status", false, []byte{0, 0, 0, 0})
		}()
	}

	closeConn(serverConn)
	return nil
}
Example #17
0
func reportContainerCure(cid string) {
	url := fmt.Sprintf("%s/api/container/%s/cure/", g.Config.Eru.Endpoint, cid)
	utils.DoPut(url)
	logs.Debug(cid[:12], "cured, added in watching list")
}
Example #18
0
func NewRequest(r *http.Request) *Request {
	req := &Request{*r, 0, 20}
	req.Init()
	logs.Debug("HTTP request", req.Method, req.URL.Path)
	return req
}
Example #19
0
func DelVlan(link netlink.Link) {
	if err := netlink.LinkDel(link); err != nil {
		logs.Debug("Delete device failed", err)
	}
}
Example #20
0
func Streamer(route *defines.Route, logstream chan *defines.Log) {
	var upstreams map[string]*UpStream = map[string]*UpStream{}
	var types map[string]struct{}
	var count int64 = 0
	if route.Source != nil {
		types = make(map[string]struct{})
		for _, t := range route.Source.Types {
			types[t] = struct{}{}
		}
	}
	defer func() {
		logs.Debug("Flush", route.ID, "cache logs")
		for _, remote := range upstreams {
			remote.Flush()
			for _, log := range remote.Tail() {
				logs.Info("Streamer can't send to remote", log)
			}
			remote.Close()
		}
		route.Done <- struct{}{}
	}()
	for logline := range logstream {
		if types != nil {
			if _, ok := types[logline.Type]; !ok {
				continue
			}
		}
		logline.Tag = route.Target.AppendTag
		logline.Count = count
		if g.Config.Lenz.Stdout {
			logs.Info("Debug Output", logline)
			continue
		}
		var f bool = false
		for offset := 0; offset < route.Backends.Len(); offset++ {
			addr, err := route.Backends.Get(logline.Name, offset)
			if err != nil {
				logs.Info("Get backend failed", err, logline.Name, logline.Data)
				break
			}
			if _, ok := upstreams[addr]; !ok {
				if ups, err := NewUpStream(addr); err != nil || ups == nil {
					route.Backends.Remove(addr)
					continue
				} else {
					upstreams[addr] = ups
				}
			}
			f = true
			if err := upstreams[addr].WriteData(logline); err != nil {
				logs.Info("Sent to remote failed", err)
				upstreams[addr].Close()
				go func(upstream *UpStream) {
					for _, log := range upstream.Tail() {
						logstream <- log
					}
				}(upstreams[addr])
				delete(upstreams, addr)
				continue
			}
			//logs.Debug("Lenz Send", logline.Name, logline.EntryPoint, logline.ID, "to", addr)
			break
		}
		if !f {
			logs.Info("Lenz failed", logline.ID[:12], logline.Name, logline.EntryPoint, logline.Data)
		}
		if count == math.MaxInt64 {
			count = 0
		} else {
			count++
		}
	}
}
Example #21
0
func InitSSHConfig() *ssh.ServerConfig {
	privKey, err := utils.LoadKey(g.Config.PrivKey)
	if err != nil {
		logs.Assert(err, "Failed to load priv key")
	}

	config := &ssh.ServerConfig{
		AuthLogCallback: func(conn ssh.ConnMetadata, method string, err error) {
			logs.Debug("Method type", method, "Error", err)
		},
		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			username := conn.User()
			clientAddr := conn.RemoteAddr()
			keyHex := utils.GetFingerPrint(key.Marshal())

			user, remote := utils.GetRealUserRemote(username)
			if user == "" || remote == "" {
				return nil, errors.New("Wrong info")
			}

			logs.Info("Login attempt", conn.RemoteAddr(), username, user, remote, keyHex)

			if !utils.CheckKey(user, keyHex) {
				return nil, errors.New("Wrong key")
			}

			meta := defines.Meta{
				Username: username,
				Pubkey:   key,
			}

			clientConfig := &ssh.ClientConfig{
				User: "******",
				Auth: []ssh.AuthMethod{
					ssh.PublicKeys(privKey),
				},
			}

			client, err := ssh.Dial("tcp", remote, clientConfig)
			if err != nil {
				return nil, err
			}
			logs.Info("Login success", remote)
			meta.Remote = remote
			meta.Client = client
			Lock.Lock()
			defer Lock.Unlock()
			MetaData[clientAddr] = meta
			return nil, nil
		},
		PasswordCallback: func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
			username := conn.User()
			clientAddr := conn.RemoteAddr()

			user, remote := utils.GetRealUserRemote(username)
			if user == "" || remote == "" {
				return nil, errors.New("Wrong info")
			}

			logs.Info("Login attempt", conn.RemoteAddr(), username, string(password))

			meta := defines.Meta{
				Username: username,
				Password: string(password),
			}

			clientConfig := &ssh.ClientConfig{
				User: "******",
				Auth: []ssh.AuthMethod{
					ssh.Password(string(password)),
				},
			}

			client, err := ssh.Dial("tcp", remote, clientConfig)
			if err != nil {
				return nil, err
			}
			logs.Info("Login success", remote)
			meta.Remote = remote
			meta.Client = client
			Lock.Lock()
			defer Lock.Unlock()
			MetaData[clientAddr] = meta
			return nil, nil
		},
	}

	hostKey, err := utils.LoadKey(g.Config.HostKey)
	if err != nil {
		logs.Assert(err, "Failed to load host key")
	}
	config.AddHostKey(hostKey)
	return config
}