Example #1
0
func generate_config_file(settings_filename string) {
	log := logging.InitFromFlags()

	// setup logging
	log.SetLogLevel(2)

	if _, err := os.Stat(settings_filename); err != nil {
		if os.IsNotExist(err) {
			log.Info("Creating settings file: " + settings_filename)
			settings := yaml.New()
			settings.Set("connection/irc_server", "irc.example.net")
			settings.Set("connection/channel", "#example")
			settings.Set("connection/nick", "gobot")
			settings.Set("connection/realname", "Go Bot")

			settings.Set("bot_config/rejoin_on_kick", true)
			settings.Set("bot_config/channel_protection", true)
			settings.Set("bot_config/owner", "example!example@example/example")
			settings.Set("bot_config/friends", sugar.List{"friend1!example@example/example", "friend2!example@example/example", "friend2!example@example/example"})

			settings.Set("bitly/shorturls_enabled", true)
			settings.Set("bitly/username", "example")
			settings.Set("bitly/api_key", "xxxxxxxxxxxxxxxxxxxxx")

			settings.Write(settings_filename)
		} else {

		}
	} else {
		log.Info("Settings file: " + settings_filename + " already exists")
	}

}
Example #2
0
func Client(nick, ident, name string, r event.EventRegistry) *Conn {
	if r == nil {
		return nil
	}
	logging.InitFromFlags()
	conn := &Conn{
		ER:        r,
		ED:        r,
		st:        false,
		in:        make(chan *Line, 32),
		out:       make(chan string, 32),
		cSend:     make(chan bool),
		cLoop:     make(chan bool),
		cPing:     make(chan bool),
		SSL:       false,
		SSLConfig: nil,
		PingFreq:  3 * time.Minute,
		Flood:     false,
		NewNick:   func(s string) string { return s + "_" },
		badness:   0,
		lastsent:  time.Now(),
	}
	conn.addIntHandlers()
	conn.Me = state.NewNick(nick)
	conn.Me.Ident = ident
	conn.Me.Name = name

	conn.initialise()
	return conn
}
Example #3
0
func Trust(identity string, trusted_identities []string) bool {
	log := logging.InitFromFlags()
	for _, value := range trusted_identities {
		if identity == value {
			log.Info("Authenticated: " + identity)
			return true
		}
	}
	log.Info("Authentication failed for : " + identity)
	return false
}
Example #4
0
// Creates a new IRC connection object, but doesn't connect to anything so
// that you can add event handlers to it. See AddHandler() for details.
func SimpleClient(nick string, args ...string) *Conn {
	r := event.NewRegistry()
	l := logging.InitFromFlags()
	ident := "goirc"
	name := "Powered by GoIRC"

	if len(args) > 0 && args[0] != "" {
		ident = args[0]
	}
	if len(args) > 1 && args[1] != "" {
		name = args[1]
	}
	return Client(nick, ident, name, r, l)
}
Example #5
0
func Client(cfg *Config) *Conn {
	logging.InitFromFlags()
	if cfg == nil || cfg.Me == nil || cfg.Me.Nick == "" || cfg.Me.Ident == "" {
		logging.Fatal("irc.Client(): Both cfg.Nick and cfg.Ident must be non-empty.")
	}
	conn := &Conn{
		cfg:        cfg,
		in:         make(chan *Line, 32),
		out:        make(chan string, 32),
		handlers:   handlerSet(),
		stRemovers: make([]Remover, 0, len(stHandlers)),
		lastsent:   time.Now(),
	}
	conn.addIntHandlers()
	conn.initialise()
	return conn
}
Example #6
0
File: main.go Project: pzsz/sp0rkle
func main() {
	flag.Parse()
	logging.InitFromFlags()

	// Initialise bot state
	bot.Init()

	// Connect to mongo
	db.Init()
	defer db.Close()

	// Add drivers
	calcdriver.Init()
	decisiondriver.Init()
	factdriver.Init()
	karmadriver.Init()
	markovdriver.Init()
	quotedriver.Init()
	reminddriver.Init()
	seendriver.Init()
	urldriver.Init()

	// Start up the HTTP server
	go http.ListenAndServe(*httpPort, nil)

	// Connect the bot to IRC and wait; reconnects are handled automatically.
	// If we get true back from the bot, re-exec the (rebuilt) binary.
	if bot.Connect() {
		// Calling syscall.Exec probably means deferred functions won't get
		// called, so disconnect from mongodb first for politeness' sake.
		db.Close()
		// If sp0rkle was run from PATH, we need to do that lookup manually.
		fq, _ := exec.LookPath(os.Args[0])
		logging.Warn("Re-executing sp0rkle with args '%v'.", os.Args)
		err := syscall.Exec(fq, os.Args, os.Environ())
		if err != nil {
			// hmmmmmm
			logging.Fatal("Couldn't re-exec sp0rkle: %v", err)
		}
	}
	logging.Info("Shutting down cleanly.")
}
Example #7
0
func Client(cfg *Config) (*Conn, error) {
	logging.InitFromFlags()
	if cfg.Me == nil || cfg.Me.Nick == "" || cfg.Me.Ident == "" {
		return nil, fmt.Errorf("irc.Client(): Both cfg.Nick and cfg.Ident must be non-empty.")
	}
	conn := &Conn{
		cfg:        cfg,
		in:         make(chan *Line, 32),
		out:        make(chan string, 32),
		cSend:      make(chan bool),
		cLoop:      make(chan bool),
		cPing:      make(chan bool),
		handlers:   handlerSet(),
		stRemovers: make([]Remover, 0, len(stHandlers)),
		lastsent:   time.Now(),
	}
	conn.addIntHandlers()
	conn.initialise()
	return conn, nil
}
Example #8
0
func main() {
	flag.Parse()
	logging.InitFromFlags()

	// Let's go find some mongo.
	db.Init()
	defer db.Close()
	qc := quotes.Init()

	// A communication channel of Quotes.
	quotes := make(chan *quotes.Quote)
	rows := make(chan []interface{})

	// Function to feed rows into the rows channel.
	row_feeder := func(sth *sqlite3.Statement, row ...interface{}) {
		rows <- row
	}

	// Function to execute a query on the SQLite db.
	db_query := func(dbh *sqlite3.Database) {
		n, err := dbh.Execute("SELECT * FROM Quotes;", row_feeder)
		if err == nil {
			logging.Info("Read %d rows from database.\n", n)
		} else {
			logging.Error("DB error: %s\n", err)
		}
	}

	// Open up the quote database in a goroutine and feed rows
	// in on the input_rows channel.
	go func() {
		sqlite3.Session(*file, db_query)
		// once we've done the query, close the channel to indicate this
		close(rows)
	}()

	// Another goroutine to munge the rows into quotes.
	// This was originally done inside the SQLite callbacks, but
	// cgo or sqlite3 obscures runtime panics and makes fail happen.
	go func() {
		for row := range rows {
			parseQuote(row, quotes)
		}
		close(quotes)
	}()

	// And finally...
	count := 0
	var err error
	for quote := range quotes {
		// ... push each quote into mongo
		err = qc.Insert(quote)
		if err != nil {
			logging.Error("Awww: %v\n", err)
		} else {
			if count%1000 == 0 {
				fmt.Printf("%d...", count)
			}
			count++
		}
	}
	fmt.Println("done.")
	logging.Info("Inserted %d quotes.\n", count)
}
Example #9
0
func main() {

	// Parse flags from command line
	flag.Parse()
	log := logging.InitFromFlags()

	// setup logging
	log.SetLogLevel(2)

	if _, err := os.Stat(*config_file); err != nil {

		generate_config_file(*config_file)
		log.Error("You must edit the " + *config_file + " file before continuing")
		os.Exit(0)
	}

	//generate a config file if it isn't found
	if *generate_config {
		generate_config_file(*config_file)
		log.Error("You must edit the " + *config_file + " file before continuing")
		os.Exit(0)
	}

	// handle configuration

	log.Info("Read configuration file: " + *config_file)
	settings := yaml.New()
	settings.Read(*config_file)

	if *channel == "" {
		*channel = settings.Get("connection/channel").(string)
		log.Debug("Read channel from config file: " + *channel)
	} else {
		log.Debug("Read channel from flag: " + *channel)
	}

	if *nick == "" {
		*nick = settings.Get("connection/nick").(string)
		log.Debug("Read nick from config file: " + *nick)
	} else {
		log.Debug("Read nick from flag: " + *nick)
	}

	if *realname == "" {
		*realname = settings.Get("connection/realname").(string)
		log.Debug("Read realname from config file: " + *realname)
	} else {
		log.Debug("Read realname from flag: " + *realname)
	}

	if *irc_server == "" {
		*irc_server = settings.Get("connection/irc_server").(string)
		log.Debug("Read irc_server from config file: " + *irc_server)
	} else {
		log.Debug("Read irc_server from flag: " + *irc_server)
	}

	if *rejoin_on_kick == true {
		*rejoin_on_kick = settings.Get("bot_config/rejoin_on_kick").(bool)
		log.Debug("Read rejoin_on_kick from config file: %t ", *rejoin_on_kick)
	} else {
		log.Debug("Read rejoin_on_kick from flag: %t ", *rejoin_on_kick)
	}

	// bitly

	shorturl_enabled := settings.Get("bitly/shorturls_enabled").(bool)
	bitly_username := settings.Get("bitly/username").(string)
	bitly_api_key := settings.Get("bitly/api_key").(string)
	if shorturl_enabled {
		bitly.SetUser(bitly_username)
		bitly.SetKey(bitly_api_key)
	}

	owner_nick := to.String(settings.Get("bot_config/owner"))
	friends := to.List(settings.Get("bot_config/friends"))
	trusted_identities := make([]string, 0)
	trusted_identities = append(trusted_identities, owner_nick)
	for _, value := range friends {
		trusted_identities = append(trusted_identities, value.(string))
	}

	// set up bot command event registry
	bot_command_registry := event.NewRegistry()
	reallyquit := false

	// Bot command handlers
	// addfriend
	addfriend_state := make(chan string)
	bot_command_registry.AddHandler(NewHandler(func(conn *irc.Conn, line *irc.Line, commands []string) {
		if line.Src == owner_nick {
			channel := line.Args[0]
			if len(commands) > 1 {
				target := commands[1]
				log.Debug("adding friend: %q", target)
				conn.Whois(target)
				log.Debug("triggering channel: %q", target)
				addfriend_state <- target

			} else {
				conn.Privmsg(channel, line.Nick+": use !addfriend <friend nick>")
			}
		}
	}), "addfriend")

	//save
	bot_command_registry.AddHandler(NewHandler(func(conn *irc.Conn, line *irc.Line, commands []string) {
		if line.Src == owner_nick {
			channel := line.Args[0]
			conn.Privmsg(channel, line.Nick+": saving settings")
			settings.Set("bot_config/friends", friends)
			settings.Write(*config_file)
			log.Info("%q", to.List(settings.Get("bot_config/friends")))
		}
	}), "save")

	//reload
	bot_command_registry.AddHandler(NewHandler(func(conn *irc.Conn, line *irc.Line, commands []string) {
		if line.Src == owner_nick {
			channel := line.Args[0]
			conn.Privmsg(channel, line.Nick+": reloading settings")
			friends := to.List(settings.Get("bot_config/friends"))
			trusted_identities = make([]string, 0)
			trusted_identities = append(trusted_identities, owner_nick)
			for _, value := range friends {
				trusted_identities = append(trusted_identities, value.(string))
			}
			log.Info("%q", to.List(settings.Get("bot_config/friends")))
		}
	}), "reload")

	// op
	bot_command_registry.AddHandler(NewHandler(func(conn *irc.Conn, line *irc.Line, commands []string) {
		if Trust(line.Src, trusted_identities) {
			channel := line.Args[0]
			if len(commands) > 1 {
				target := commands[1]
				log.Info("Oping user: "******"+o "+target)
			} else {
				log.Info("Oping user: "******"+o "+line.Nick)
			}
		}
	}), "op")

	//deop
	bot_command_registry.AddHandler(NewHandler(func(conn *irc.Conn, line *irc.Line, commands []string) {
		if Trust(line.Src, trusted_identities) {
			channel := line.Args[0]
			if len(commands) > 1 {
				target := commands[1]
				conn.Mode(channel, "-o "+target)
			} else {
				conn.Mode(channel, "-o "+line.Nick)
			}
		}
	}), "deop")

	// kick
	bot_command_registry.AddHandler(NewHandler(func(conn *irc.Conn, line *irc.Line, commands []string) {
		if Trust(line.Src, trusted_identities) {
			channel := line.Args[0]
			if len(commands) > 1 {
				target := commands[1]
				kick_message := "get out"
				if len(commands) > 2 {
					//this doesn't work. Need to fix.
					kick_message = commands[2]
				}
				//do'nt kick if owner
				if target != strings.Split(owner_nick, "!")[0] {
					//don't kick if self
					if *nick != target {
						conn.Kick(channel, target, kick_message)
					} else {
						conn.Privmsg(channel, line.Nick+": why would i kick myself?")
					}
				} else {
					conn.Privmsg(channel, line.Nick+": why would i kick my lovely friend "+target+"?")

				}
			} else {
				conn.Privmsg(channel, line.Nick+": invalid command")
			}
		}
	}), "kick")

	//quit
	bot_command_registry.AddHandler(NewHandler(func(conn *irc.Conn, line *irc.Line, commands []string) {
		if line.Src == owner_nick {
			quit_message := "i died"
			reallyquit = true
			if len(commands) > 1 {
				quit_message = commands[1]
			}
			conn.Quit(quit_message)
		}
	}), "quit")

	//urlshortener
	bot_command_registry.AddHandler(NewHandler(func(conn *irc.Conn, line *irc.Line, commands []string) {
		log.Info("URLS event")
		channel := line.Args[0]
		for _, long_url := range commands {
			work_url := long_url
			work_urlr := regexp.MustCompile(`^[\w-]+://([^/?]+)(/(?:[^/?]+/)*)?([^./?][^/?]+?)?(\.[^.?]*)?(\?.*)?$`)
			url_parts := work_urlr.FindAllStringSubmatch(work_url, -1)
			domain := url_parts[0][1]
			ext := url_parts[0][4]

			forbidden_extensions := "png|gif|jpg|mp3|avi|md|zip"
			extension_regex := regexp.MustCompile(`(` + forbidden_extensions + `)`)
			extension_test := extension_regex.FindAllStringSubmatch(ext, -1)

			title := ""
			url_util_channel := make(chan string)
			if extension_test == nil {
				go grab_title(work_url, url_util_channel)
				title = <-url_util_channel
			}

			go shorten_url(work_url, url_util_channel, bitly_username, bitly_api_key)
			short_url := <-url_util_channel
			output := ""
			if short_url != long_url {

				output = output + "<" + short_url + "> (at " + domain + ") "
			}
			if title != "" {
				output = output + " " + title
			}
			conn.Privmsg(channel, output)
		}
	}), "urlshortener")

	// create new IRC connection
	log.Info("create new IRC connection")
	irc_client := irc.SimpleClient(*nick, *realname)

	// IRC HANDLERS!

	irc_client.EnableStateTracking()
	irc_client.AddHandler("connected",
		func(conn *irc.Conn, line *irc.Line) {
			log.Info("connected as " + *nick)
			conn.Join(*channel)
		})

	// Set up a handler to notify of disconnect events.
	quit := make(chan bool)
	irc_client.AddHandler("disconnected",
		func(conn *irc.Conn, line *irc.Line) {
			log.Info("disconnected")
			quit <- true
		})

	//Handle Private messages
	irc_client.AddHandler("PRIVMSG",
		func(conn *irc.Conn, line *irc.Line) {
			log.Info("privmsg")
			irc_input := strings.ToLower(line.Args[1])
			if strings.HasPrefix(irc_input, *command_char) {
				irc_command := strings.Split(irc_input[1:], " ")
				bot_command_registry.Dispatch(irc_command[0], conn, line, irc_command)
			}
			url_regex := regexp.MustCompile(`\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))`)
			urls := url_regex.FindAllString(irc_input, -1)
			if len(urls) > 0 {
				bot_command_registry.Dispatch("urlshortener", conn, line, urls)
			}

		})

	//handle kick by rejoining kicked channel
	irc_client.AddHandler("KICK",
		func(conn *irc.Conn, line *irc.Line) {
			log.Info("Kicked from " + line.Args[0])
			if *rejoin_on_kick {
				log.Info("rejoining " + line.Args[0])
				conn.Join(line.Args[0])
			}
		})

	//notify on 332 - topic reply on join to channel
	irc_client.AddHandler("332",
		func(conn *irc.Conn, line *irc.Line) {
			log.Debug("Topic is %q, on %q ", line.Args[2], line.Args[1])
		})

	//notify on MODE
	irc_client.AddHandler("MODE",
		func(conn *irc.Conn, line *irc.Line) {
			for _, v := range line.Args {
				log.Info("mode: %q ", v)
			}
		})

	//notify on WHOIS
	irc_client.AddHandler("311",
		func(conn *irc.Conn, line *irc.Line) {
			addedfriend := <-addfriend_state
			log.Info("addfriend channel: %q", addedfriend)
			if addedfriend == line.Args[1] {
				friend := line.Args[1] + "!" + line.Args[2] + "@" + line.Args[3]
				log.Debug("added friend " + friend)
				trusted_identities = append(trusted_identities, friend)
				friends = append(friends, friend)
				log.Debug("friends: %q", friends)
				conn.Privmsg(strings.Split(owner_nick, "!")[0], line.Nick+": added "+line.Args[1]+" as friend")
				//addfriend_state <- ""
			} else {
				log.Info("addfriend channel is empty: %q", addedfriend)

			}
		})

	//notify on join
	irc_client.AddHandler("JOIN",
		func(conn *irc.Conn, line *irc.Line) {
			log.Info("Joined " + line.Args[0])
		})

	//handle topic changes
	irc_client.AddHandler("TOPIC",
		func(conn *irc.Conn, line *irc.Line) {
			log.Info("Topic on " + line.Args[0] + " changed to: " + line.Args[1])
		})

	// set up a goroutine to read commands from stdin

	if *generate_config == false {

		for !reallyquit {
			// connect to server
			if err := irc_client.Connect(*irc_server); err != nil {
				fmt.Printf("Connection error: %s\n", err)
				return
			}

			// wait on quit channel
			<-quit
		}
	}
}
Example #10
0
func main() {
	flag.Parse()
	logging.InitFromFlags()

	// Let's go find some mongo.
	db.Init()
	defer db.Close()
	fc := factoids.Init()

	// A communication channel of Factoids.
	facts := make(chan *factoids.Factoid)
	ptrs := make(chan []interface{})
	rows := make(chan []interface{})

	// Function to execute some queries on the SQLite db and shove the results
	// into the ptrs and rows channels created above.
	db_query := func(dbh *sqlite3.Database) {
		_, err := dbh.Execute("SELECT * FROM Factoids WHERE Value LIKE '%*%';", feeder(ptrs))
		close(ptrs)
		if err != nil {
			logging.Error("DB error: %s", err)
		}
		n, err := dbh.Execute("SELECT * FROM Factoids;", feeder(rows))
		close(rows)
		if err == nil {
			logging.Info("Read %d rows from database.", n)
		} else {
			logging.Error("DB error: %s", err)
		}
	}

	go func() {
		sqlite3.Session(*file, db_query)
	}()

	// First, synchronously read all the stuff from the ptrs channel
	// and build a set of all the factoid keys that are used as pointers
	for row := range ptrs {
		for _, val := range parseMultipleValues(toString(row[cValue])) {
			if key, _, _ := util.FactPointer(val); key != "" {
				ptrkeys[key] = true
			}
		}
	}

	// Now run another goroutine to munge the rows into factoids.
	// This was originally done inside the SQLite callbacks, but
	// cgo or sqlite3 obscures runtime panics and makes fail happen.
	go func() {
		for row := range rows {
			parseFactoid(row, facts)
		}
		close(facts)
	}()

	// And finally...
	count := 0
	var err error
	for fact := range facts {
		// ... push each fact into mongo
		err = fc.Insert(fact)
		if err != nil {
			logging.Error("Awww: %v\n", err)
		} else {
			if count%1000 == 0 {
				fmt.Printf("%d...", count)
			}
			count++
		}
	}
	fmt.Println("done.")
	logging.Info("Inserted %d factoids.\n", count)
}
Example #11
0
func main() {
	var host = flag.String("H", "", "host (or hosts) to act on")
	var role = flag.String("R", "", "role (or roles) to act on")
	var proxy = flag.String("P", "127.0.0.1", "agent to interact with")
	var all = flag.Bool("A", false, "act on all live nodes")
	var fserial = flag.Bool("s", false, "print output when commands finish")
	var fbinary = flag.Bool("b", false, "force binary mode output")
	var ftext = flag.Bool("l", false, "force line mode output")
	var glock = flag.String("G", "", "global lock to claim")
	var llock = flag.String("L", "", "local lock to claim")
	var dzrhost = flag.String("doozer", "localhost:8046",
		"host:port for doozer")
	var jobs = flag.Int("j", 0, "jobs to run in parallel")
	var tout = flag.Int("t", 20, "timeout (in seconds) for jobs")
	var fnowarn = flag.Bool("w", false, "suppress error text output")

	flag.Usage = clientUsage
	flag.Parse()

	timeout = *tout
	if timeout < 0 {
		log.Error("timeout must be 0 (no timeout) or positive")
		os.Exit(1)
	}
	nowarn = *fnowarn

	// The output selection modes. By default, we assume that if the output
	// is from a single machine, it's binary and we don't touch it. However,
	// if the user is running against multiple targets, we assume that the
	// output is line-based and we prefix the hostname returning each line.
	//
	// Line based defaults to interleaved. The serial flag can be used to
	// ask us to buffer each host's output and then dump it all at once when
	// that host is done. This is more useful for doing a batch job and having
	// easily read output later, but still running commands in parallel.
	//
	// Finally, the user can force binary mode on multi-host outputs, which
	// makes us not touch the output.
	serial = *fserial
	binary = *fbinary && !*ftext

	// Uses the nice golog package to handle logging arguments and flags
	// so we don't have to worry about it.
	log = logging.InitFromFlags()
	safedoozer.SetLogger(log)

	// Connect to our doozer host. We have to do this early because alias
	// validation requires doozer.
	dzr = safedoozer.Dial(*dzrhost)
	defer dzr.Close()

	// Do some simple argument validation.
	args := expandAlias(flag.Args())
	if len(args) == 0 {
		flag.Usage()
		os.Exit(1)
	}
	if !isValidCommand(args[0], args[1:]) {
		os.Exit(1)
	}

	// Figure out localhost.
	var err error // If we use := below, we shadow the global, which is bad.
	hostname, err = os.Hostname()
	if err != nil {
		log.Error("failed getting hostname: %s", err)
		os.Exit(1)
	}
	hostname = strings.Split(hostname, ".")[0]
	if len(hostname) <= 0 {
		log.Error("hostname is empty!")
		os.Exit(1)
	}

	zmq_ctx, err = zmq.NewContext()
	if err != nil {
		log.Error("failed to init zmq: %s", err)
		os.Exit(1)
	}
	defer zmq_ctx.Close()

	// Connect to the proxy agent. This is the agent we will be having do all
	// of the work for us. This is probably localhost.
	psock = socketForIp(*proxy)
	if psock == nil {
		log.Error("unable to connect to proxy agent")
		os.Exit(1)
	}
	defer (*psock).Close()

	// Determine which nodes we will be addressing.
	hosts := make(map[string]bool)
	if *all {
		for _, host := range nodes() {
			hosts[host] = false
		}
	} else {
		if *host != "" {
			lhosts := strings.Split(*host, ",")
			for _, host := range lhosts {
				host = strings.TrimSpace(host)
				if len(host) > 0 {
					hosts[strings.TrimSpace(host)] = false
				}
			}
		}

		if *role != "" {
			roles := strings.Split(*role, ",")
			for _, role := range roles {
				lhosts := convertRoleToHosts(strings.TrimSpace(role))
				for _, host := range lhosts {
					hosts[host] = false
				}
			}
		}

		if *host == "" && *role == "" {
			// Both empty, default to this machine.
			hosts[hostname] = false
		}
	}

	// If no hosts, bail out.
	if len(hosts) <= 0 {
		log.Error("no hosts or roles specified")
		os.Exit(1)
	} else if len(hosts) == 1 {
		// If we're targetting a single machine, we want to use binary mode by
		// default unless the user explicitly set text mode.
		binary = true && !*ftext
	}

	// If we have been told to get a global lock, let's try to get that now.
	if *glock != "" {
		resp := proxyCommand("global_lock", *glock)
		if resp != "locked" {
			log.Error("failed to get global lock %s: %s", *glock, resp)
			os.Exit(1)
		}
		defer func(lock string) {
			resp := proxyCommand("global_unlock", *glock)
			if resp != "unlocked" {
				log.Error("failed to release global lock %s: %s", *glock, resp)
			}
		}(*glock)
	}

	// Same, local.
	if *llock != "" {
		resp := proxyCommand("local_lock", *llock)
		if resp != "locked" {
			log.Error("failed to get local lock %s: %s", *llock, resp)
			os.Exit(1)
		}
		defer func(lock string) {
			resp := proxyCommand("local_unlock", *llock)
			if resp != "unlocked" {
				log.Error("failed to release local lock %s: %s", *llock, resp)
			}
		}(*llock)
	}

	// There are some commands which are client-only and don't run against a
	// given set of hosts. For these, just execute locally and then we're done.
	switch args[0] {
	case "roles":
		cmdRoles()
	case "hosts":
		cmdHosts()
	case "alias":
		cmdAlias(args[1:])
	}

	// Queue up the jobs and then execute them.
	for host, _ := range hosts {
		queueJob(host, args)
	}
	runJobs(*jobs) // Returns when jobs are done.
}
Example #12
0
func main() {
	var myhost = flag.String("hostname", "", "this machine's hostname")
	var myport = flag.Int("port", 7330, "port number to listen on")
	var dzrhost = flag.String("doozer", "localhost:8046",
		"host:port for doozer")
	flag.Parse()

	// Uses the nice golog package to handle logging arguments and flags
	// so we don't have to worry about it.
	log = logging.InitFromFlags()
	safedoozer.SetLogger(log)

	log.Info("starting up - gid %s", gid)
	rand.Seed(int64(time.Now().Nanosecond())) // Not the best but ok?

	dzr = safedoozer.Dial(*dzrhost)
	defer dzr.Close()
	defer removeGlobalLocks()

	// see config.go for this
	initializeConfig()

	var err error // If we use := below, we shadow the global, which is bad.
	zmq_ctx, err = zmq.NewContext()
	if err != nil {
		log.Fatal("failed to init zmq: %s", err)
	}
	defer zmq_ctx.Close()

	myinfo, err := getSelfInfo()
	if err != nil {
		log.Fatal("Failed getting local information: %s", err)
	}
	if *myhost == "" {
		_, ok := myinfo["hostname"]
		if !ok {
			log.Fatal("getSelfInfo() did not return a hostname")
		}
		hostname = myinfo["hostname"]
	} else {
		log.Warn("user requested hostname override (command line argument)")
		hostname = *myhost
	}

	// Global, easy to access variable since we use it everywhere. This is safe
	// because it's read-only, too -- well, by definition. It isn't really. But
	// if it changes in maintainInfo then we exit.
	log.Info("client starting with hostname %s", hostname)

	// Now we have enough information to see if anybody else is claiming to be
	// this particular node. If so, we want to wait a bit and see if they
	// update again. If they are updating, then it is assumed they are running
	// okay, and we shouldn't start up again.
	lock := "/s/nlock/" + hostname
	rev := dzr.Stat(lock, nil)

	// If the lock is claimed, attempt to wait and see if the remote seems
	// to still be alive.
	if rev > 0 {
		log.Warn("node lock is claimed, waiting to see if it's lively")
		time.Sleep(3 * time.Second)

		nrev := dzr.Stat(lock, nil)
		if nrev > rev {
			log.Fatal("lock is lively, we can't continue!")
		}
	}

	// Safe to claim the node lock. Let's get it.
	log.Info("attempting to get the node lock")
	nrev := dzr.Set(lock, rev, fmt.Sprintf("%d", time.Now().Unix()))
	if nrev <= rev {
		log.Fatal("failed to obtain the lock")
	}
	log.Info("lock successfully obtained! we are lively.")
	go maintainLock(lock, nrev)

	// Now we want to reset the gid map, asserting that we are now the living
	// agent for this host.
	lock = "/s/gid/" + hostname
	rev = dzr.Stat(lock, nil)
	dzr.Set(lock, rev, gid)

	// There are certain miscellaneous tasks that need to get done somewhere,
	// so we use global locks to make sure that somebody is doing them. We
	// don't really care who.
	go manageGlobalFunc(5, "gf.expire-hosts", gfExpireHosts)
	go manageGlobalFunc(5, "gf.expire-glocks", gfExpireGlobalLocks)

	// Personal maintenance here.
	go maintainInfo(&myinfo)
	go maintainStanzas()
	runAgent(*myport) // Returns when dead.
}
Example #13
0
func init() {
	// This is probably a dirty hack...
	logging.InitFromFlags()
	logging.SetLogLevel(logging.LogFatal)
}
Example #14
0
func main() {
	flag.Parse()
	logging.InitFromFlags()
	golog.Init()

	// Slightly more random than 1.
	rand.Seed(time.Now().UnixNano() * int64(os.Getpid()))

	// Initialise bot state
	bot.Init()

	// Connect to mongo
	db.Init()
	defer db.Close()

	// Add drivers
	calcdriver.Init()
	decisiondriver.Init()
	factdriver.Init()
	karmadriver.Init()
	markovdriver.Init()
	netdriver.Init()
	quotedriver.Init()
	reminddriver.Init()
	seendriver.Init()
	statsdriver.Init()
	urldriver.Init()

	// Start up the HTTP server
	go http.ListenAndServe(*httpPort, nil)

	// Set up a signal handler to shut things down gracefully.
	// NOTE: net/http doesn't provide for graceful shutdown :-/
	go func() {
		called := new(int32)
		sigint := make(chan os.Signal, 1)
		signal.Notify(sigint, syscall.SIGINT)
		for _ = range sigint {
			if atomic.AddInt32(called, 1) > 1 {
				logging.Fatal("Recieved multiple interrupts, dying.")
			}
			bot.Shutdown()
		}
	}()

	// Connect the bot to IRC and wait; reconnects are handled automatically.
	// If we get true back from the bot, re-exec the (rebuilt) binary.
	if <-bot.Connect() {
		// Calling syscall.Exec probably means deferred functions won't get
		// called, so disconnect from mongodb first for politeness' sake.
		db.Close()
		// If sp0rkle was run from PATH, we need to do that lookup manually.
		fq, _ := exec.LookPath(os.Args[0])
		logging.Warn("Re-executing sp0rkle with args '%v'.", os.Args)
		err := syscall.Exec(fq, os.Args, os.Environ())
		if err != nil {
			// hmmmmmm
			logging.Fatal("Couldn't re-exec sp0rkle: %v", err)
		}
	}
	logging.Info("Shutting down cleanly.")
}
Example #15
0
func main() {
	flag.Parse()
	logging.InitFromFlags()

	// Let's go find some mongo.
	db.Init()
	defer db.Close()
	uc := urls.Init()

	work := make(chan *urls.Url)
	quit := make(chan bool)
	urls := make(chan *urls.Url)
	rows := make(chan []interface{})
	failed := 0

	// If we're checking, spin up some workers
	if *check {
		for i := 1; i <= *workq; i++ {
			go func(n int) {
				count := 0
				for u := range work {
					count++
					logging.Debug("w%02d r%04d: Fetching '%s'", n, count, u.Url)
					res, err := http.Head(u.Url)
					logging.Debug("w%02d r%04d: Response '%s'", n, count, res.Status)
					if err == nil && res.StatusCode == 200 {
						urls <- u
					} else {
						failed++
					}
				}
				quit <- true
			}(i)
		}
	}

	// Function to feed rows into the rows channel.
	row_feeder := func(sth *sqlite3.Statement, row ...interface{}) {
		rows <- row
	}

	// Function to execute a query on the SQLite db.
	db_query := func(dbh *sqlite3.Database) {
		n, err := dbh.Execute("SELECT * FROM urls;", row_feeder)
		if err == nil {
			logging.Info("Read %d rows from database.\n", n)
		} else {
			logging.Error("DB error: %s\n", err)
		}
	}

	// Open up the URL database in a goroutine and feed rows
	// in on the input_rows channel.
	go func() {
		sqlite3.Session(*file, db_query)
		// once we've done the query, close the channel to indicate this
		close(rows)
	}()

	// Another goroutine to munge the rows into Urls and optionally send
	// them to the pool of checker goroutines.
	go func() {
		for row := range rows {
			u := parseUrl(row)
			if *check {
				work <- u
			} else {
				urls <- u
			}
		}
		if *check {
			// Close work channel and wait for all workers to quit.
			close(work)
			for i := 0; i < *workq; i++ {
				<-quit
			}
		}
		close(urls)
	}()

	// And finally...
	count := 0
	var err error
	for u := range urls {
		// ... push each url into mongo
		err = uc.Insert(u)
		if err != nil {
			logging.Error("Awww: %v\n", err)
		} else {
			if count%1000 == 0 {
				fmt.Printf("%d...", count)
			}
			count++
		}
	}
	fmt.Println("done.")
	if *check {
		logging.Info("Dropped %d non-200 urls.", failed)
	}
	logging.Info("Inserted %d urls.", count)
}