Beispiel #1
0
// InstallBufferedLogWriter creates a new BufferedLogWriter, registers
// it with Loggo and returns its output channel.
func InstallBufferedLogWriter(maxLen int) (LogRecordCh, error) {
	if !feature.IsDbLogEnabled() {
		return nil, nil
	}

	writer := NewBufferedLogWriter(maxLen)
	err := loggo.RegisterWriter(writerName, writer, loggo.TRACE)
	if err != nil {
		return nil, errors.Annotate(err, "failed to set up log buffering")
	}
	return writer.Logs(), nil
}
Beispiel #2
0
// UninstallBufferedLogWriter removes the BufferedLogWriter previously
// installed by InstallBufferedLogWriter and closes it.
func UninstallBufferedLogWriter() error {
	if !feature.IsDbLogEnabled() {
		return nil
	}

	writer, _, err := loggo.RemoveWriter(writerName)
	if err != nil {
		return errors.Annotate(err, "failed to uninstall log buffering")
	}
	bufWriter, ok := writer.(*BufferedLogWriter)
	if !ok {
		return errors.New("unexpected writer installed as buffered log writer")
	}
	bufWriter.Close()
	return nil
}
Beispiel #3
0
// Manifold returns a dependency manifold that runs a logger
// worker, using the resource names defined in the supplied config.
func Manifold(config ManifoldConfig) dependency.Manifold {
	return dependency.Manifold{
		Inputs: []string{
			config.APICallerName,
		},
		Start: func(getResource dependency.GetResourceFunc) (worker.Worker, error) {
			if !feature.IsDbLogEnabled() {
				logger.Warningf("log sender manifold disabled by feature flag")
				return nil, dependency.ErrMissing
			}

			var apiCaller base.APICaller
			if err := getResource(config.APICallerName, &apiCaller); err != nil {
				return nil, err
			}
			return New(config.LogSource, logsender.NewAPI(apiCaller)), nil
		},
	}
}
Beispiel #4
0
// Manifold returns a dependency manifold that runs a logger
// worker, using the resource names defined in the supplied config.
func Manifold(config ManifoldConfig) dependency.Manifold {
	return dependency.Manifold{
		Inputs: []string{
			config.AgentName,
			config.APIInfoGateName,
		},
		Start: func(getResource dependency.GetResourceFunc) (worker.Worker, error) {
			if !feature.IsDbLogEnabled() {
				logger.Warningf("log sender manifold disabled by feature flag")
				return nil, dependency.ErrMissing
			}

			var gate gate.Waiter
			if err := getResource(config.APIInfoGateName, &gate); err != nil {
				return nil, err
			}
			var agent agent.Agent
			if err := getResource(config.AgentName, &agent); err != nil {
				return nil, err
			}
			return New(config.LogSource, gate, agent), nil
		},
	}
}
Beispiel #5
0
func (srv *Server) run(lis net.Listener) {
	defer func() {
		srv.state.HackLeadership() // Break deadlocks caused by BlockUntil... calls.
		srv.wg.Wait()              // wait for any outstanding requests to complete.
		srv.tomb.Done()
		srv.statePool.Close()
	}()

	srv.wg.Add(1)
	go func() {
		err := srv.mongoPinger()
		// Before killing the tomb, inform the API handlers that
		// Mongo is unavailable. API handlers can use this to decide
		// not to perform non-critical Mongo-related operations when
		// tearing down.
		atomic.AddUint32(&srv.mongoUnavailable, 1)
		srv.tomb.Kill(err)
		srv.wg.Done()
	}()

	// for pat based handlers, they are matched in-order of being
	// registered, first match wins. So more specific ones have to be
	// registered first.
	mux := pat.New()

	srvDying := srv.tomb.Dying()
	httpCtxt := httpContext{
		srv: srv,
	}
	if feature.IsDbLogEnabled() {
		handleAll(mux, "/environment/:envuuid/logsink",
			newLogSinkHandler(httpCtxt, srv.logDir))
		handleAll(mux, "/environment/:envuuid/log",
			newDebugLogDBHandler(httpCtxt, srvDying))
	} else {
		handleAll(mux, "/environment/:envuuid/log",
			newDebugLogFileHandler(httpCtxt, srvDying, srv.logDir))
	}
	handleAll(mux, "/environment/:envuuid/charms",
		&charmsHandler{
			ctxt:    httpCtxt,
			dataDir: srv.dataDir},
	)
	// TODO: We can switch from handleAll to mux.Post/Get/etc for entries
	// where we only want to support specific request methods. However, our
	// tests currently assert that errors come back as application/json and
	// pat only does "text/plain" responses.
	handleAll(mux, "/environment/:envuuid/tools",
		&toolsUploadHandler{
			ctxt: httpCtxt,
		},
	)
	handleAll(mux, "/environment/:envuuid/tools/:version",
		&toolsDownloadHandler{
			ctxt: httpCtxt,
		},
	)
	strictCtxt := httpCtxt
	strictCtxt.strictValidation = true
	strictCtxt.stateServerEnvOnly = true
	handleAll(mux, "/environment/:envuuid/backups",
		&backupHandler{
			ctxt: strictCtxt,
		},
	)
	handleAll(mux, "/environment/:envuuid/api", http.HandlerFunc(srv.apiHandler))

	handleAll(mux, "/environment/:envuuid/images/:kind/:series/:arch/:filename",
		&imagesDownloadHandler{
			ctxt:    httpCtxt,
			dataDir: srv.dataDir,
			state:   srv.state,
		},
	)
	// For backwards compatibility we register all the old paths

	if feature.IsDbLogEnabled() {
		handleAll(mux, "/log", newDebugLogDBHandler(httpCtxt, srvDying))
	} else {
		handleAll(mux, "/log", newDebugLogFileHandler(httpCtxt, srvDying, srv.logDir))
	}

	handleAll(mux, "/charms",
		&charmsHandler{
			ctxt:    httpCtxt,
			dataDir: srv.dataDir,
		},
	)
	handleAll(mux, "/tools",
		&toolsUploadHandler{
			ctxt: httpCtxt,
		},
	)
	handleAll(mux, "/tools/:version",
		&toolsDownloadHandler{
			ctxt: httpCtxt,
		},
	)
	handleAll(mux, "/", http.HandlerFunc(srv.apiHandler))

	go func() {
		// The error from http.Serve is not interesting.
		http.Serve(lis, mux)
	}()

	<-srv.tomb.Dying()
	lis.Close()
}
Beispiel #6
0
func (a *UnitAgent) APIWorkers() (_ worker.Worker, err error) {
	agentConfig := a.CurrentConfig()
	dataDir := agentConfig.DataDir()
	hookLock, err := cmdutil.HookExecutionLock(dataDir)
	if err != nil {
		return nil, err
	}
	st, entity, err := OpenAPIState(agentConfig, a)
	if err != nil {
		return nil, err
	}
	unitTag, err := names.ParseUnitTag(entity.Tag())
	if err != nil {
		return nil, errors.Trace(err)
	}
	// Ensure that the environment uuid is stored in the agent config.
	// Luckily the API has it recorded for us after we connect.
	if agentConfig.Environment().Id() == "" {
		err := a.ChangeConfig(func(setter agent.ConfigSetter) error {
			environTag, err := st.EnvironTag()
			if err != nil {
				return errors.Annotate(err, "no environment uuid set on api")
			}

			return setter.Migrate(agent.MigrateParams{
				Environment: environTag,
			})
		})
		if err != nil {
			logger.Warningf("unable to save environment uuid: %v", err)
			// Not really fatal, just annoying.
		}
	}

	defer func() {
		if err != nil {
			st.Close()
			reportClosedUnitAPI(st)
		}
	}()

	// Before starting any workers, ensure we record the Juju version this unit
	// agent is running.
	currentTools := &tools.Tools{Version: version.Current}
	apiStateUpgrader := a.getUpgrader(st)
	if err := apiStateUpgrader.SetVersion(agentConfig.Tag().String(), currentTools.Version); err != nil {
		return nil, errors.Annotate(err, "cannot set unit agent version")
	}

	runner := worker.NewRunner(cmdutil.ConnectionIsFatal(logger, st), cmdutil.MoreImportant)

	// start proxyupdater first to ensure proxy settings are correct
	runner.StartWorker("proxyupdater", func() (worker.Worker, error) {
		return proxyupdater.New(st.Environment(), false), nil
	})
	if feature.IsDbLogEnabled() {
		runner.StartWorker("logsender", func() (worker.Worker, error) {
			return logsender.New(a.bufferedLogs, agentConfig.APIInfo()), nil
		})
	}
	runner.StartWorker("upgrader", func() (worker.Worker, error) {
		return upgrader.NewAgentUpgrader(
			st.Upgrader(),
			agentConfig,
			agentConfig.UpgradedToVersion(),
			func() bool { return false },
			a.initialAgentUpgradeCheckComplete,
		), nil
	})
	runner.StartWorker("logger", func() (worker.Worker, error) {
		return workerlogger.NewLogger(st.Logger(), agentConfig), nil
	})
	runner.StartWorker("uniter", func() (worker.Worker, error) {
		uniterFacade, err := st.Uniter()
		if err != nil {
			return nil, errors.Trace(err)
		}
		uniterParams := uniter.UniterParams{
			uniterFacade,
			unitTag,
			leadership.NewClient(st),
			dataDir,
			hookLock,
			uniter.NewMetricsTimerChooser(),
			uniter.NewUpdateStatusTimer(),
			nil,
		}
		return uniter.NewUniter(&uniterParams), nil
	})

	runner.StartWorker("apiaddressupdater", func() (worker.Worker, error) {
		uniterFacade, err := st.Uniter()
		if err != nil {
			return nil, errors.Trace(err)
		}
		return apiaddressupdater.NewAPIAddressUpdater(uniterFacade, a), nil
	})
	if !featureflag.Enabled(feature.DisableRsyslog) {
		runner.StartWorker("rsyslog", func() (worker.Worker, error) {
			return cmdutil.NewRsyslogConfigWorker(st.Rsyslog(), agentConfig, rsyslog.RsyslogModeForwarding)
		})
	}
	return cmdutil.NewCloseWorker(logger, runner, st), nil
}