Index: push/go/pulld/main.go |
diff --git a/push/go/pulld/main.go b/push/go/pulld/main.go |
new file mode 100644 |
index 0000000000000000000000000000000000000000..65bcfd8f0b521bab524c3f46285818af4f4df480 |
--- /dev/null |
+++ b/push/go/pulld/main.go |
@@ -0,0 +1,106 @@ |
+// pulld is an application that monitors and pulls down new Debian packages and installs them. |
+// |
+// It presumes each package is monitored via systemd and not monit, so there's |
+// no monitoring of monit config files is done. |
+// |
+// Note that it is safe for pulld to install pulld since the list of installed |
+// packages is written out before 'dpkg -i' is called. |
+package main |
+ |
+import ( |
+ "flag" |
+ "os" |
+ "strings" |
+ "time" |
+ |
+ "code.google.com/p/google-api-go-client/storage/v1" |
+ "github.com/skia-dev/glog" |
+ "go.skia.org/infra/go/common" |
+ "go.skia.org/infra/go/util" |
+ "go.skia.org/infra/push/go/gsauth" |
+ "go.skia.org/infra/push/go/packages" |
+) |
+ |
+var ( |
+ graphiteServer = flag.String("graphite_server", "skia-monitoring:2003", "Where is Graphite metrics ingestion server running.") |
+ doOauth = flag.Bool("oauth", true, "Run through the OAuth 2.0 flow on startup, otherwise use a GCE service account.") |
+ oauthCacheFile = flag.String("oauth_cache_file", "google_storage_token.data", "Path to the file where to cache cache the oauth credentials.") |
+ installedPackagesFile = flag.String("installed_packages_file", "installed_packages.json", "Path to the file where to cache the list of installed debs.") |
+) |
+ |
+// differences returns all strings that appear in server but not local. |
+func differences(server, local []string) ([]string, []string) { |
+ newPackages := []string{} |
+ installedPackages := []string{} |
+ for _, s := range server { |
+ if util.In(s, local) { |
+ installedPackages = append(installedPackages, s) |
+ } else { |
+ newPackages = append(newPackages, s) |
+ } |
+ } |
+ return newPackages, installedPackages |
+} |
+ |
+func main() { |
+ hostname, err := os.Hostname() |
+ if err != nil { |
+ // Never call glog before common.Init*. |
+ os.Exit(1) |
+ } |
+ common.InitWithMetrics("pulld."+hostname, graphiteServer) |
+ glog.Infof("Running with hostname: %s", hostname) |
+ |
+ client, err := gsauth.NewClient(*doOauth, *oauthCacheFile) |
+ if err != nil { |
+ glog.Fatalf("Failed to create authenticated HTTP client: %s", err) |
+ } |
+ glog.Info("Got authenticated client.") |
+ |
+ store, err := storage.New(client) |
+ if err != nil { |
+ glog.Fatalf("Failed to create storage service client: %s", err) |
+ } |
+ |
+ for _ = range time.Tick(time.Second * 15) { |
+ glog.Info("About to read package list.") |
+ // Read the old and new packages from their respective storage locations. |
+ serverList, err := packages.InstalledForServer(client, store, hostname) |
+ if err != nil { |
+ glog.Errorf("Failed to retrieve remote package list: %s", err) |
+ continue |
+ } |
+ localList, err := packages.FromLocalFile(*installedPackagesFile) |
+ if err != nil { |
+ glog.Errorf("Failed to retrieve local package list: %s", err) |
+ continue |
+ } |
+ |
+ // Install any new or updated packages. |
+ newPackages, installed := differences(serverList.Names, localList) |
+ glog.Infof("New: %v, Installed: %v", newPackages, installed) |
+ |
+ for _, name := range newPackages { |
+ // If just an appname appears w/o a package name then that means |
+ // that package hasn't been selected, so just skip it for now. |
+ if len(strings.Split(name, "/")) == 1 { |
+ continue |
+ } |
+ installed = append(installed, name) |
+ if err := packages.ToLocalFile(installed, *installedPackagesFile); err != nil { |
+ glog.Errorf("Failed to write local package list: %s", err) |
+ continue |
+ } |
+ if err := packages.Install(client, store, name); err != nil { |
+ glog.Errorf("Failed to install package %s: %s", name, err) |
+ // Pop last name from 'installed' then rewrite the file since the |
+ // install failed. |
+ installed = installed[:len(installed)-1] |
+ if err := packages.ToLocalFile(installed, *installedPackagesFile); err != nil { |
+ glog.Errorf("Failed to rewrite local package list after install failure for %s: %s", name, err) |
+ } |
+ continue |
+ } |
+ } |
+ } |
+} |