func initContext() (err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("initContext() -> %v", e) } }() ctx.Channels.Log = make(chan mig.Log, 37) ctx.Logging, err = getLoggingConf() if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } ctx.Logging, err = mig.InitLogger(ctx.Logging, "mig-loader") if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } wg.Add(1) go func() { var stop bool for event := range ctx.Channels.Log { // Also write the message to stderr to ease debugging fmt.Fprintf(os.Stderr, "%v\n", event.Desc) stop, err = mig.ProcessLog(ctx.Logging, event) if err != nil { panic("unable to process log") } if stop { break } } wg.Done() }() logInfo("logging routine started") ctx.LoaderKey = LOADERKEY hints := agentcontext.AgentContextHints{ DiscoverPublicIP: DISCOVERPUBLICIP, DiscoverAWSMeta: DISCOVERAWSMETA, APIUrl: APIURL, Proxies: PROXIES[:], } actx, err := agentcontext.NewAgentContext(ctx.Channels.Log, hints) if err != nil { panic(err) } ctx.AgentIdentifier = actx.ToAgent() return }
func refreshAgentEnvironment(ctx *Context) { for { time.Sleep(REFRESHENV) ctx.Channels.Log <- mig.Log{Desc: "refreshing agent environment"}.Info() ctx.Agent.Lock() hints := agentcontext.AgentContextHints{ DiscoverPublicIP: DISCOVERPUBLICIP, DiscoverAWSMeta: DISCOVERAWSMETA, APIUrl: APIURL, Proxies: PROXIES[:], } actx, err := agentcontext.NewAgentContext(ctx.Channels.Log, hints) if err != nil { ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("error obtaining new agent context: %v", err)}.Err() } else { if ctx.updateVolatileFromAgentContext(actx) { ctx.Channels.Log <- mig.Log{Desc: "agent environment has changed"}.Info() } } ctx.Agent.Unlock() } }
// Init prepare the AMQP connections to the broker and launches the // goroutines that will process commands received by the MIG Scheduler func Init(foreground, upgrade bool) (ctx Context, err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("initAgent() -> %v", e) } if ctx.Channels.Log != nil { ctx.Channels.Log <- mig.Log{Desc: "leaving initAgent()"}.Debug() } }() // Pick up a lock on Context Agent field as we will be updating or reading it here and in // various functions called from here such as daemonize(). ctx.Agent.Lock() defer ctx.Agent.Unlock() ctx.Agent.Tags = TAGS ctx.Logging, err = mig.InitLogger(LOGGINGCONF, "mig-agent") if err != nil { panic(err) } // create the go channels ctx, err = initChannels(ctx) if err != nil { panic(err) } // Logging GoRoutine, go func() { for event := range ctx.Channels.Log { _, err := mig.ProcessLog(ctx.Logging, event) if err != nil { fmt.Println("Unable to process logs") } } }() ctx.Channels.Log <- mig.Log{Desc: "Logging routine initialized."}.Debug() // Gather new agent context information to use as the context for this // agent invocation hints := agentcontext.AgentContextHints{ DiscoverPublicIP: DISCOVERPUBLICIP, DiscoverAWSMeta: DISCOVERAWSMETA, APIUrl: APIURL, Proxies: PROXIES[:], } actx, err := agentcontext.NewAgentContext(ctx.Channels.Log, hints) if err != nil { panic(err) } // defines whether the agent should respawn itself or not // this value is overriden in the daemonize calls if the agent // is controlled by systemd, upstart or launchd ctx.Agent.Respawn = ISIMMORTAL // Do initial assignment of values which could change over the lifetime // of the agent process ctx.updateVolatileFromAgentContext(actx) // Set some other values obtained from the agent context which will not // change while the process is running. ctx.Agent.RunDir = actx.RunDir ctx.Agent.BinPath = actx.BinPath // get the agent ID ctx, err = initAgentID(ctx) if err != nil { panic(err) } // build the agent message queue location ctx.Agent.QueueLoc = fmt.Sprintf("%s.%s", ctx.Agent.Env.OS, ctx.Agent.UID) // daemonize if not in foreground mode if !foreground { // give one second for the caller to exit time.Sleep(time.Second) ctx, err = daemonize(ctx, upgrade) if err != nil { panic(err) } } ctx.Sleeper = HEARTBEATFREQ if err != nil { panic(err) } // parse the ACLs ctx, err = initACL(ctx) if err != nil { panic(err) } connected := false // connect to the message broker // // If any proxies have been configured, we try to use those first. If they fail, or // no proxies have been setup, just attempt a direct connection. for _, proxy := range PROXIES { ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Trying proxy %v for relay connection", proxy)}.Debug() ctx, err = initMQ(ctx, true, proxy) if err != nil { ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Failed to connect to relay using proxy %s: '%v'", proxy, err)}.Info() continue } connected = true goto mqdone } // Try and proxy that has been specified in the environment ctx.Channels.Log <- mig.Log{Desc: "Trying proxies from environment for relay connection"}.Debug() ctx, err = initMQ(ctx, true, "") if err == nil { connected = true goto mqdone } else { ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Failed to connect to relay using HTTP_PROXY: '%v'", err)}.Info() } // Fall back to a direct connection ctx.Channels.Log <- mig.Log{Desc: "Trying direct relay connection"}.Debug() ctx, err = initMQ(ctx, false, "") if err == nil { connected = true } else { ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Failed to connect to relay directly: '%v'", err)}.Info() } mqdone: if !connected { panic("Failed to connect to the relay") } // catch interrupts c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) go func() { sig := <-c ctx.Channels.Terminate <- sig.String() }() // try to connect the stat socket until it works // this may fail if one agent is already running if SOCKET != "" { go func() { for { ctx.Socket.Bind = SOCKET ctx, err = initSocket(ctx) if err == nil { ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Stat socket connected successfully on %s", ctx.Socket.Bind)}.Info() goto socketdone } ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Failed to connect stat socket: '%v'", err)}.Err() time.Sleep(60 * time.Second) } socketdone: return }() } return }