From ca8df4f485e7de5bb45f057499a9250602a9f10c Mon Sep 17 00:00:00 2001 From: Julien Vehent Date: Thu, 8 May 2014 14:51:49 -0400 Subject: [PATCH] [major] postgres migration, take 2 --- conf/mig-agent-conf.go.inc | 2 +- conf/mig-api.cfg.inc | 2 +- conf/mig-scheduler.cfg.inc | 1 + doc/.files/ER-diagram.png | Bin 50617 -> 49333 bytes doc/.files/createdb.sh | 172 ++++++++++++++++++++++++++++++ doc/data.rst | 28 ++++- src/mig/action.go | 2 +- src/mig/api/api.go | 6 +- src/mig/api/context.go | 4 +- src/mig/database/queries.go | 33 +++--- src/mig/scheduler/context.go | 2 +- src/mig/scheduler/flow.go | 2 +- src/mig/scheduler/multiagents.go | 99 ----------------- src/mig/scheduler/scheduler.go | 35 +++++- src/mig/scheduler/upgradeagent.go | 70 ++++++++++-- 15 files changed, 327 insertions(+), 131 deletions(-) create mode 100644 doc/.files/createdb.sh delete mode 100644 src/mig/scheduler/multiagents.go diff --git a/conf/mig-agent-conf.go.inc b/conf/mig-agent-conf.go.inc index a4509255..327fd989 100644 --- a/conf/mig-agent-conf.go.inc +++ b/conf/mig-agent-conf.go.inc @@ -54,7 +54,7 @@ var LOGGINGCONF = mig.Logging{ // location of the rabbitmq server var AMQPBROKER string = "amqp://guest:guest@localhost:5672/" -// firequency at which the agent sends heartbeat messages +// frequency at which the agent sends heartbeat messages var HEARTBEATFREQ time.Duration = 300 * time.Second // timeout after which a module run is killed diff --git a/conf/mig-api.cfg.inc b/conf/mig-api.cfg.inc index 9c47872f..3e04694c 100644 --- a/conf/mig-api.cfg.inc +++ b/conf/mig-api.cfg.inc @@ -6,7 +6,7 @@ host = "http://localhost:12345" baseroute = "/api/v1" -[openpgp] +[pgp] pubring = "/var/cache/mig/.gnupg/pubring.gpg" [directories] diff --git a/conf/mig-scheduler.cfg.inc b/conf/mig-scheduler.cfg.inc index fe88b667..a6aba089 100644 --- a/conf/mig-scheduler.cfg.inc +++ b/conf/mig-scheduler.cfg.inc @@ -55,3 +55,4 @@ [pgp] keyid = "1E644752FB76B77245B1694E556CDD7B07E9D5D6" + pubring = "/path/to/pubring.pgp" diff --git a/doc/.files/ER-diagram.png b/doc/.files/ER-diagram.png index d251202427586995d7fb6eccbbb9d42a6da479f1..1fd614e6c0b81f1976d66a27ef8a34c0b2380b99 100644 GIT binary patch literal 49333 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 diff --git a/doc/.files/createdb.sh b/doc/.files/createdb.sh new file mode 100644 index 00000000..72f6af45 --- /dev/null +++ b/doc/.files/createdb.sh @@ -0,0 +1,172 @@ +#! /usr/bin/env bash +[ ! -x $(which sudo) ] && echo "sudo isn't available, that won't work" && exit 1 + + +for user in "migadmin" "migapi" "migscheduler"; do + pass=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32}) + sudo su postgres -c "psql -c 'CREATE ROLE $user;'" 1>/dev/null + [ $? -ne 0 ] && echo "ERROR: user creation failed." && exit 123 + sudo su postgres -c "psql -c \"ALTER ROLE $user WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB LOGIN PASSWORD '$pass';\"" 1>/dev/null + [ $? -ne 0 ] && echo "ERROR: user creation failed." && exit 123 + echo "Created user $user with password '$pass'" +done +sudo su postgres -c "psql -c 'CREATE DATABASE mig OWNER migadmin;'" 1>/dev/null +[ $? -ne 0 ] && echo "ERROR: database creation failed." && exit 123 + +createdbtemp=$(mktemp) +cat > $createdbtemp << EOF +CREATE TABLE actions ( + id numeric NOT NULL, + name character varying(2048) NOT NULL, + target character varying(2048) NOT NULL, + description json, + threat json, + operations json, + validfrom timestamp with time zone NOT NULL, + expireafter timestamp with time zone NOT NULL, + starttime timestamp with time zone, + finishtime timestamp with time zone, + lastupdatetime timestamp with time zone, + status character varying(256), + sentctr integer, + returnedctr integer, + donectr integer, + cancelledctr integer, + failedctr integer, + timeoutctr integer, + pgpsignatures json, + syntaxversion integer +); +ALTER TABLE public.actions OWNER TO migadmin; +ALTER TABLE ONLY actions + ADD CONSTRAINT actions_pkey PRIMARY KEY (id); + +CREATE TABLE agents ( + id numeric NOT NULL, + name character varying(2048) NOT NULL, + queueloc character varying(2048) NOT NULL, + os character varying(2048) NOT NULL, + version character varying(2048) NOT NULL, + pid integer NOT NULL, + starttime timestamp with time zone NOT NULL, + destructiontime timestamp with time zone, + heartbeattime timestamp with time zone NOT NULL, + status character varying(255) +); +ALTER TABLE public.agents OWNER TO migadmin; +ALTER TABLE ONLY agents + ADD CONSTRAINT agents_pkey PRIMARY KEY (id); + +CREATE TABLE agtmodreq ( + moduleid numeric NOT NULL, + agentid numeric NOT NULL, + minimumweight integer NOT NULL +); +ALTER TABLE public.agtmodreq OWNER TO migadmin; +CREATE UNIQUE INDEX agtmodreq_moduleid_agentid_idx ON agtmodreq USING btree (moduleid, agentid); +CREATE INDEX agtmodreq_agentid_idx ON agtmodreq USING btree (agentid); +CREATE INDEX agtmodreq_moduleid_idx ON agtmodreq USING btree (moduleid); + +CREATE TABLE commands ( + id numeric NOT NULL, + actionid numeric NOT NULL, + agentid numeric NOT NULL, + status character varying(255) NOT NULL, + results json, + starttime timestamp with time zone NOT NULL, + finishtime timestamp with time zone +); +ALTER TABLE public.commands OWNER TO migadmin; +ALTER TABLE ONLY commands + ADD CONSTRAINT commands_pkey PRIMARY KEY (id); + +CREATE TABLE invagtmodperm ( + investigatorid bigint NOT NULL, + agentid numeric NOT NULL, + moduleid numeric NOT NULL, + weight integer NOT NULL +); +ALTER TABLE public.invagtmodperm OWNER TO migadmin; +CREATE UNIQUE INDEX invagtmodperm_investigatorid_agentid_moduleid_idx ON invagtmodperm USING btree (investigatorid, agentid, moduleid); +CREATE INDEX invagtmodperm_agentid_idx ON invagtmodperm USING btree (agentid); +CREATE INDEX invagtmodperm_investigatorid_idx ON invagtmodperm USING btree (investigatorid); +CREATE INDEX invagtmodperm_moduleid_idx ON invagtmodperm USING btree (moduleid); + +CREATE TABLE investigators ( + id bigserial NOT NULL, + name character varying(1024) NOT NULL, + pgpfingerprint character varying(128), + publickey bytea +); +ALTER TABLE public.investigators OWNER TO migadmin; +ALTER TABLE ONLY investigators + ADD CONSTRAINT investigators_pkey PRIMARY KEY (id); +CREATE UNIQUE INDEX investigators_pgpfingerprint_idx ON investigators USING btree (pgpfingerprint); + +CREATE TABLE modules ( + id numeric NOT NULL, + name character varying(256) NOT NULL +); +ALTER TABLE public.modules OWNER TO migadmin; +ALTER TABLE ONLY modules + ADD CONSTRAINT modules_pkey PRIMARY KEY (id); + +CREATE TABLE signatures ( + actionid numeric NOT NULL, + investigatorid bigint NOT NULL, + pgpsignature character varying(4096) NOT NULL +); +ALTER TABLE public.signatures OWNER TO migadmin; +CREATE UNIQUE INDEX signatures_actionid_investigatorid_idx ON signatures USING btree (actionid, investigatorid); +CREATE INDEX signatures_actionid_idx ON signatures USING btree (actionid); +CREATE INDEX signatures_investigatorid_idx ON signatures USING btree (investigatorid); + +ALTER TABLE ONLY agtmodreq + ADD CONSTRAINT agtmodreq_moduleid_fkey FOREIGN KEY (moduleid) REFERENCES modules(id); + +ALTER TABLE ONLY commands + ADD CONSTRAINT commands_actionid_fkey FOREIGN KEY (actionid) REFERENCES actions(id); + +ALTER TABLE ONLY commands + ADD CONSTRAINT commands_agentid_fkey FOREIGN KEY (agentid) REFERENCES agents(id); + +ALTER TABLE ONLY invagtmodperm + ADD CONSTRAINT invagtmodperm_agentid_fkey FOREIGN KEY (agentid) REFERENCES agents(id); + +ALTER TABLE ONLY invagtmodperm + ADD CONSTRAINT invagtmodperm_investigatorid_fkey FOREIGN KEY (investigatorid) REFERENCES investigators(id); + +ALTER TABLE ONLY invagtmodperm + ADD CONSTRAINT invagtmodperm_moduleid_fkey FOREIGN KEY (moduleid) REFERENCES modules(id); + +ALTER TABLE ONLY signatures + ADD CONSTRAINT signatures_actionid_fkey FOREIGN KEY (actionid) REFERENCES actions(id); + +ALTER TABLE ONLY signatures + ADD CONSTRAINT signatures_investigatorid_fkey FOREIGN KEY (investigatorid) REFERENCES investigators(id); +EOF + +chmod 777 $createdbtemp +sudo su postgres -c "psql -d mig -f $createdbtemp" 1>/dev/null +[ $? -ne 0 ] && echo "ERROR: tables creation failed." && exit 123 +rm "$createdbtemp" + +granttmp=$(mktemp) +cat > $granttmp << EOF +GRANT ALL PRIVILEGES ON DATABASE mig TO migadmin; + +\c mig + +GRANT SELECT ON ALL TABLES IN SCHEMA public TO migscheduler; +GRANT INSERT, UPDATE ON actions, commands, agents, signatures TO migscheduler; + +GRANT SELECT ON ALL TABLES IN SCHEMA public TO migapi; +GRANT INSERT ON actions, signatures TO migapi; +EOF + +chmod 777 $granttmp +sudo su postgres -c "psql -f $granttmp" 1>/dev/null +[ $? -ne 0 ] && echo "ERROR: grants failed." && exit 123 +rm "$granttmp" + +echo "MIG Database created successfully." diff --git a/doc/data.rst b/doc/data.rst index 5909f78c..b781fa8c 100644 --- a/doc/data.rst +++ b/doc/data.rst @@ -33,7 +33,12 @@ the scheduler, each action and command are stored individually in a text file in Postgresql database ------------------- -Database structure +Entity-Relationship Diagram +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: .files/ER-diagram.png + +Structure & Tables ~~~~~~~~~~~~~~~~~~ The `actions` table contains the detail of each action ran by the MIG platform. @@ -164,4 +169,23 @@ on an agent. This model allows for very fine grained permissions management. CREATE INDEX ON invagtmodperm (agentid); CREATE INDEX ON invagtmodperm (moduleid); -.. image:: .files/ER-diagram.png +Database creation script +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. include:: .files/createdb.sh + :code: bash + +Adding Investigators +~~~~~~~~~~~~~~~~~~~~ + +In the future, this will probably be automated via the API. But for now, and +until we have a strong authentication mechanism for API calls, it must be done +manually in the database. + +Adapt the query below to add a new investigator. + +.. code:: sql + + INSERT INTO investigators (name, pgpfingerprint) + VALUES ('Bob Kelso', 'E608......'); + diff --git a/src/mig/action.go b/src/mig/action.go index 05177e5b..d5b880b5 100644 --- a/src/mig/action.go +++ b/src/mig/action.go @@ -68,7 +68,7 @@ type Action struct { LastUpdateTime time.Time `json:"lastupdatetime,omitempty"` CommandIDs []uint64 `json:"commandids,omitempty"` Counters counters `json:"counters,omitempty"` - SyntaxVersion int `json:"syntaxversion,omitempty"` + SyntaxVersion uint16 `json:"syntaxversion,omitempty"` } // Some counters used to track the completion of an action diff --git a/src/mig/api/api.go b/src/mig/api/api.go index ed0c7b6d..d865bc0d 100644 --- a/src/mig/api/api.go +++ b/src/mig/api/api.go @@ -309,14 +309,14 @@ func createAction(respWriter http.ResponseWriter, request *http.Request) { // Init action fields action.ID = mig.GenID() - date0 := time.Date(11, time.January, 11, 11, 11, 11, 11, time.UTC) + date0 := time.Date(9998, time.January, 11, 11, 11, 11, 11, time.UTC) action.StartTime = date0 action.FinishTime = date0 action.LastUpdateTime = date0 action.Status = "init" // load keyring and validate action - keyring, err := os.Open(ctx.OpenPGP.PubRing) + keyring, err := os.Open(ctx.PGP.PubRing) if err != nil { panic(err) } @@ -344,7 +344,7 @@ func createAction(respWriter http.ResponseWriter, request *http.Request) { } for _, sig := range action.PGPSignatures { // TODO: opening the keyring in a loop is really ugly. rewind! - k, err := os.Open(ctx.OpenPGP.PubRing) + k, err := os.Open(ctx.PGP.PubRing) if err != nil { panic(err) } diff --git a/src/mig/api/context.go b/src/mig/api/context.go index da5a34af..e1ea3ecf 100644 --- a/src/mig/api/context.go +++ b/src/mig/api/context.go @@ -65,8 +65,8 @@ type Context struct { Ready, InFlight, Returned, Done string } } - DB migdb.DB - OpenPGP struct { + DB migdb.DB + PGP struct { PubRing string } Postgres struct { diff --git a/src/mig/database/queries.go b/src/mig/database/queries.go index 08c68637..219066b7 100644 --- a/src/mig/database/queries.go +++ b/src/mig/database/queries.go @@ -150,16 +150,17 @@ func (db *DB) UpdateAction(a mig.Action) (err error) { // InsertOrUpdateAction looks for an existing action in DB and update it, // or insert a new one if none is found -func (db *DB) InsertOrUpdateAction(a mig.Action) (err error) { +func (db *DB) InsertOrUpdateAction(a mig.Action) (inserted bool, err error) { var id uint64 err = db.c.QueryRow(`SELECT id FROM actions WHERE id=$1`, a.ID).Scan(&id) - if err != nil { - return fmt.Errorf("Error while retrieving action: '%v'", err) + if err != nil && err != sql.ErrNoRows { + return inserted, fmt.Errorf("Error while retrieving action: '%v'", err) } if err == sql.ErrNoRows { - return db.InsertAction(a) + inserted = true + return inserted, db.InsertAction(a) } else { - return db.UpdateAction(a) + return inserted, db.UpdateAction(a) } } @@ -192,12 +193,13 @@ func (db *DB) InsertSignature(aid, iid uint64, sig string) (err error) { // FindInvestigatorByFingerprint searches the database for an investigator that // has a given fingerprint func (db *DB) InvestigatorByFingerprint(fp string) (iid uint64, err error) { - err = db.c.QueryRow("SELECT id FROM investigators WHERE pgpfingerprint=$1", fp).Scan(&iid) + err = db.c.QueryRow("SELECT id FROM investigators WHERE LOWER(pgpfingerprint)=LOWER($1)", fp).Scan(&iid) if err != nil && err != sql.ErrNoRows { err = fmt.Errorf("Error while finding investigator: '%v'", err) return } if err == sql.ErrNoRows { + err = fmt.Errorf("InvestigatorByFingerprint: no investigator found for fingerprint '%s'", fp) return } return @@ -367,11 +369,8 @@ func (db *DB) UpdateAgentHeartbeat(agt mig.Agent) (err error) { // if it exists, or insert it if it doesn't func (db *DB) InsertOrUpdateAgent(agt mig.Agent) (err error) { agent, err := db.AgentByQueueAndPID(agt.QueueLoc, agt.PID) - if err != nil && err != sql.ErrNoRows { - return fmt.Errorf("Error while searching for agent: '%v'", err) - } - if err == sql.ErrNoRows { - agt.DestructionTime = time.Date(11, time.January, 11, 11, 11, 11, 11, time.UTC) + if err != nil { + agt.DestructionTime = time.Date(9998, time.January, 11, 11, 11, 11, 11, time.UTC) agt.Status = "heartbeating" // create a new agent return db.InsertAgent(agt) @@ -439,12 +438,22 @@ func (db *DB) ActiveAgentsByTarget(target string, pointInTime time.Time) (agents return } +// MarkAgentUpgraded updated the status of an agent in the database +func (db *DB) MarkAgentUpgraded(agent mig.Agent) (err error) { + _, err = db.c.Exec(`UPDATE agents SET status='upgraded' WHERE id=$1`, + agent.ID) + if err != nil { + return fmt.Errorf("Failed to mark agent as upgraded in database: '%v'", err) + } + return +} + // MarkAgentDestroyed updated the status and destructiontime of an agent in the database func (db *DB) MarkAgentDestroyed(agent mig.Agent) (err error) { agent.Status = "destroyed" agent.DestructionTime = time.Now() _, err = db.c.Exec(`UPDATE agents - SET heartbeattime=$1, status=$2 WHERE id=$3`, + SET destructiontime=$1, status=$2 WHERE id=$3`, agent.DestructionTime, agent.Status, agent.ID) if err != nil { return fmt.Errorf("Failed to mark agent as destroyed in database: '%v'", err) diff --git a/src/mig/scheduler/context.go b/src/mig/scheduler/context.go index e62e74ab..e77918e7 100644 --- a/src/mig/scheduler/context.go +++ b/src/mig/scheduler/context.go @@ -96,7 +96,7 @@ type Context struct { Chan *amqp.Channel } PGP struct { - KeyID string + KeyID, PubRing string } Postgres struct { Host, User, Password, DBName, SSLMode string diff --git a/src/mig/scheduler/flow.go b/src/mig/scheduler/flow.go index f2e69046..7b95e15a 100644 --- a/src/mig/scheduler/flow.go +++ b/src/mig/scheduler/flow.go @@ -108,7 +108,7 @@ func flyAction(ctx Context, a mig.Action, origin string) (err error) { panic(err) } a.Status = "inflight" - err = ctx.DB.InsertOrUpdateAction(a) + err = ctx.DB.UpdateAction(a) if err != nil { panic(err) } diff --git a/src/mig/scheduler/multiagents.go b/src/mig/scheduler/multiagents.go deleted file mode 100644 index 19091ce1..00000000 --- a/src/mig/scheduler/multiagents.go +++ /dev/null @@ -1,99 +0,0 @@ -/* Mozilla InvestiGator Scheduler - -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Initial Developer of the Original Code is -Mozilla Corporation -Portions created by the Initial Developer are Copyright (C) 2013 -the Initial Developer. All Rights Reserved. - -Contributor(s): -Julien Vehent jvehent@mozilla.com [:ulfr] - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. -*/ - -package main - -import ( - "fmt" - "mig" - "time" -) - -// inspectMultiAgents takes a number of actions when several agents are found -// to be listening on the same queue. It will trigger an agentdestroy action -// for agents that are flagged as upgraded, and log alerts for agents that -// are not, such that an investigator can look at them. -func inspectMultiAgents(queueLoc string, ctx Context) (err error) { - defer func() { - if e := recover(); e != nil { - err = fmt.Errorf("inspectMultiAgents() -> %v", e) - } - ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: "leaving inspectMultiAgents()"}.Debug() - }() - agentsCount, agents, err := findDupAgents(queueLoc, ctx) - if agentsCount < 2 { - return - } - - destroyedAgents := 0 - leftAloneAgents := 0 - for _, agent := range agents { - switch agent.Status { - case "upgraded": - // upgraded agents must die - err = destroyAgent(agent, ctx) - if err != nil { - panic(err) - } - destroyedAgents++ - case "destroyed": - // if the agent has already been marked as destroyed, check if - // that was done longer than 2 heartbeats ago. If it did, the - // destruction failed, and we need to reissue a destruction order - hbFreq, err := time.ParseDuration(ctx.Agent.HeartbeatFreq) - if err != nil { - panic(err) - } - twoHeartbeats := time.Now().Add(-hbFreq * 2) - if agent.DestructionTime.Before(twoHeartbeats) { - err = destroyAgent(agent, ctx) - if err != nil { - panic(err) - } - destroyedAgents++ - } else { - leftAloneAgents++ - } - } - } - - remainingAgents := agentsCount - destroyedAgents - leftAloneAgents - if remainingAgents > 1 { - // there's still some agents left, raise errors for these - desc := fmt.Sprintf("Found '%d' agents running on '%s'. Require manual inspection.", remainingAgents, queueLoc) - ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: desc}.Warning() - } - return -} diff --git a/src/mig/scheduler/scheduler.go b/src/mig/scheduler/scheduler.go index 268131bc..594940de 100644 --- a/src/mig/scheduler/scheduler.go +++ b/src/mig/scheduler/scheduler.go @@ -41,6 +41,7 @@ import ( "flag" "fmt" "mig" + "mig/pgp" "os" "runtime" "strings" @@ -114,7 +115,7 @@ func main() { // move action to INVALID folder and log dest := fmt.Sprintf("%s/%d.json", ctx.Directories.Action.Invalid, time.Now().UTC().UnixNano()) os.Rename(actionPath, dest) - reason := fmt.Sprintf("%v. %s moved to %s", err, actionPath, dest) + reason := fmt.Sprintf("%v. '%s' moved to '%s'", err, actionPath, dest) ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: reason}.Warning() } } @@ -344,10 +345,40 @@ func processNewAction(actionPath string, ctx Context) (err error) { return } action.Status = "preparing" - err = ctx.DB.InsertOrUpdateAction(action) + inserted, err := ctx.DB.InsertOrUpdateAction(action) if err != nil { panic(err) } + if inserted { + // action was inserted, and not updated, so we need to insert + // the signatures as well + astr, err := action.String() + if err != nil { + panic(err) + } + for _, sig := range action.PGPSignatures { + // TODO: opening the keyring in a loop is really ugly. rewind! + k, err := os.Open(ctx.PGP.PubRing) + if err != nil { + panic(err) + } + defer k.Close() + fp, err := pgp.GetFingerprintFromSignature(astr, sig, k) + if err != nil { + panic(err) + } + iid, err := ctx.DB.InvestigatorByFingerprint(fp) + if err != nil { + panic(err) + } + err = ctx.DB.InsertSignature(action.ID, iid, sig) + if err != nil { + panic(err) + } + } + } + ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, ActionID: action.ID, Desc: "Action written to database"}.Debug() + // expand the action in one command per agent action.CommandIDs, err = prepareCommands(action, ctx) if err != nil { diff --git a/src/mig/scheduler/upgradeagent.go b/src/mig/scheduler/upgradeagent.go index 24d0896e..8f1b9eba 100644 --- a/src/mig/scheduler/upgradeagent.go +++ b/src/mig/scheduler/upgradeagent.go @@ -79,20 +79,18 @@ func markUpgradedAgents(cmd mig.Command, ctx Context) (err error) { panic(err) } oldpid := reflect.ValueOf(resultMap["oldpid"]) - if oldpid.Int() < 2 { + if oldpid.Float() < 2 || oldpid.Float() > 65535 { desc := fmt.Sprintf("Successfully found upgraded action on agent '%s', but with PID '%s'. That's not right...", cmd.Agent.Name, oldpid) ctx.Channels.Log <- mig.Log{Desc: desc}.Err() panic(desc) } - // update the agent's registration to mark it as upgraded - agent, err := ctx.DB.AgentByQueueAndPID(cmd.Agent.QueueLoc, int(oldpid.Int())) + agent, err := ctx.DB.AgentByQueueAndPID(cmd.Agent.QueueLoc, int(oldpid.Float())) if err != nil { panic(err) } - agent.Status = "upgraded" - err = ctx.DB.InsertOrUpdateAgent(agent) + err = ctx.DB.MarkAgentUpgraded(agent) if err != nil { panic(err) } @@ -104,6 +102,66 @@ func markUpgradedAgents(cmd mig.Command, ctx Context) (err error) { return } +// inspectMultiAgents takes a number of actions when several agents are found +// to be listening on the same queue. It will trigger an agentdestroy action +// for agents that are flagged as upgraded, and log alerts for agents that +// are not, such that an investigator can look at them. +func inspectMultiAgents(queueLoc string, ctx Context) (err error) { + defer func() { + if e := recover(); e != nil { + err = fmt.Errorf("inspectMultiAgents() -> %v", e) + } + ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: "leaving inspectMultiAgents()"}.Debug() + }() + agentsCount, agents, err := findDupAgents(queueLoc, ctx) + if agentsCount < 2 { + return + } + destroyedAgents := 0 + leftAloneAgents := 0 + for _, agent := range agents { + switch agent.Status { + case "upgraded": + // upgraded agents must die + err = destroyAgent(agent, ctx) + if err != nil { + panic(err) + } + destroyedAgents++ + desc := fmt.Sprintf("Agent '%s' with PID '%d' has been upgraded and will be destroyed.", agent.Name, agent.PID) + ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: desc}.Debug() + case "destroyed": + // if the agent has already been marked as destroyed, check if + // that was done longer than 3 heartbeats ago. If it did, the + // destruction failed, and we need to reissue a destruction order + hbFreq, err := time.ParseDuration(ctx.Agent.HeartbeatFreq) + if err != nil { + panic(err) + } + pointInTime := time.Now().Add(-hbFreq * 3) + if agent.DestructionTime.Before(pointInTime) { + err = destroyAgent(agent, ctx) + if err != nil { + panic(err) + } + destroyedAgents++ + desc := fmt.Sprintf("Re-issuing destruction action for agent '%s' with PID '%d'.", agent.Name, agent.PID) + ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: desc}.Debug() + } else { + leftAloneAgents++ + } + } + } + + remainingAgents := agentsCount - destroyedAgents - leftAloneAgents + if remainingAgents > 1 { + // there's still some agents left, raise errors for these + desc := fmt.Sprintf("Found '%d' agents running on '%s'. Require manual inspection.", remainingAgents, queueLoc) + ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: desc}.Warning() + } + return +} + // destroyAgent issues an `agentdestroy` action targetted to a specific agent // and updates the status of the agent in the database func destroyAgent(agent mig.Agent, ctx Context) (err error) { @@ -151,7 +209,7 @@ func destroyAgent(agent mig.Agent, ctx Context) (err error) { } // write the action to the spool for scheduling - dest := fmt.Sprintf("%s/%s", ctx.Directories.Action.New, mig.GenID()) + dest := fmt.Sprintf("%s/%d.json", ctx.Directories.Action.New, killAction.ID) err = safeWrite(ctx, dest, jsonAction) if err != nil { panic(err)