diff options
author | David Anderson <[email protected]> | 2017-01-31 14:36:35 -0800 |
---|---|---|
committer | David Anderson <[email protected]> | 2017-01-31 14:36:35 -0800 |
commit | aded79682ca01ac8c7fb17449d79f5274e727f2d (patch) | |
tree | ae754122bac09493cb5ef046c3bd10d65bde85f8 | |
parent | 3e6354c147b050cb9b008ae44d68fd1d3d385723 (diff) |
Add a deploy step to garbage-collect old packagecloud files.
-rw-r--r-- | .travis.yml | 14 | ||||
-rw-r--r-- | scripts/prune_old_versions.go | 128 |
2 files changed, 139 insertions, 3 deletions
diff --git a/.travis.yml b/.travis.yml index 9dad151..888f051 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,9 +20,12 @@ script: --description "TLS SNI router" --url "https://github.com/google/tlsrouter" ./tlsrouter=/usr/bin/tlsrouter ./systemd/tlsrouter.service=/lib/systemd/system/tlsrouter.service -# Random edit to force travis rebuild +env: + # Packagecloud API key, for prune_old_versions.go + - secure: "SRcNwt+45QyPS1w9aGxMg9905Y6d9w4mBM29G6iTTnUB5nD7cAk4m+tf834knGSobVXlWcRnTDW8zrHdQ9yX22dPqCpH5qE+qzTmIvxRHrVJRMmPeYvligJ/9jYfHgQbvuRT8cUpIcpCQAla6rw8nXfKTOE3h8XqMP2hdc3DTVOu2HCfKCNco1tJ7is+AIAnFV2Wpsbb3ZsdKFvHvi2RKUfFaX61J1GNt2/XJIlZs8jC6Y1IAC+ftjql9UsAE/WjZ9fL0Ww1b9/LBIIGHXWI3HpVv9WvlhhIxIlJgOVjmU2lbSuj2w/EBDJ9cd1Qe+wJkT3yKzE1NRsNScVjGg+Ku5igJu/XXuaHkIX01+15BqgPduBYRL0atiNQDhqgBiSyVhXZBX9vsgsp0bgpKaBSF++CV18Q9dara8aljqqS33M3imO3I8JmXU10944QA9Wvu7pCYuIzXxhINcDXRvqxBqz5LnFJGwnGqngTrOCSVS2xn7Y+sjmhe1n5cPCEISlozfa9mPYPvMPp8zg3TbATOOM8CVfcpaNscLqa/+SExN3zMwSanjNKrBgoaQcBzGW5mIgSPxhXkWikBgapiEN7+2Y032Lhqdb9dYjH+EuwcnofspDjjMabWxnuJaln+E3/9vZi2ooQrBEtvymUTy4VMSnqwIX5bU7nPdIuQycdWhk=" + deploy: - provider: packagecloud +- provider: packagecloud repository: tlsrouter username: danderson dist: debian/stretch @@ -30,5 +33,10 @@ deploy: token: secure: gNU3o70EU4oYeIS6pr0K5oLMGqqxrcf41EOv6c/YoHPVdV6Cx4j9NW0/ISgu6a1/Xf2NgWKT5BWwLpAuhmGdALuOz1Ah//YBWd9N8mGHGaC6RpOPDU8/9NkQdBEmjEH9sgX4PNOh1KQ7d7O0OH0g8RqJlJa0MkUYbTtN6KJ29oiUXxKmZM4D/iWB8VonKOnrtx1NwQL8jL8imZyEV/1fknhDwumz2iKeU1le4Neq9zkxwICMLUonmgphlrp+SDb1EOoHxT6cn51bqBQtQUplfC4dN4OQU/CPqE9E1N1noibvN29YA93qfcrjD3I95KT9wzq+3B6he33+kb0Gz+Cj5ypGy4P85l7TuX4CtQg0U3NAlJCk32IfsdjK+o47pdmADij9IIb9yKt+g99FMERkJJY5EInqEsxHlW/vNF5OqQCmpiHstZL4R2XaHEsWh6j77npnjjC1Aea8xZTWr8PTsbSzVkbG7bTmFpZoPH8eEmr4GNuw5gnbi6D1AJDjcA+UdY9s5qZNpzuWOqfhOFxL+zUW+8sHBvcoFw3R+pwHECs2LCL1c0xAC1LtNUnmW/gnwHavtvKkzErjR1P8Xl7obCbeChJjp+b/BcFYlNACldZcuzBAPyPwIdlWVyUonL4bm63upfMEEShiAIDDJ21y7fjsQK7CfPA7g25bpyo+hV8= on: - branch: "master" + branch: master + go: "1.7" +- provider: script + script: go run scripts/prune_old_versions.go -user=danderson -repo=tlsrouter -distro=debian -version=stretch -package=tlsrouter -arch=amd64 -limit=2 + on: + branch: master go: "1.7" diff --git a/scripts/prune_old_versions.go b/scripts/prune_old_versions.go new file mode 100644 index 0000000..43d9997 --- /dev/null +++ b/scripts/prune_old_versions.go @@ -0,0 +1,128 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "net/http" + "os" + "sort" + "strings" + "time" +) + +var ( + user = flag.String("user", "", "username") + repo = flag.String("repo", "", "repository name") + pkgType = flag.String("pkg-type", "deb", "Package type, e.g. 'deb'") + distro = flag.String("distro", "", "distro name, e.g. 'debian'") + distroVersion = flag.String("version", "", "distro version, e.g. 'stretch'") + pkg = flag.String("package", "", "package name") + arch = flag.String("arch", "", "package architecture") + limit = flag.Int("limit", 2, "package versions to keep") +) + +func fatalf(msg string, args ...interface{}) { + fmt.Printf(msg+"\n", args...) + os.Exit(1) +} + +func main() { + flag.Parse() + if *user == "" { + fatalf("missing -user") + } + if *repo == "" { + fatalf("missing -repo") + } + if *pkgType == "" { + fatalf("missing -pkg-type") + } + if *distro == "" { + fatalf("missing -distro") + } + if *distroVersion == "" { + fatalf("missing -version") + } + if *pkg == "" { + fatalf("missing -package") + } + if *arch == "" { + fatalf("missing -arch") + } + if *limit < 1 { + fatalf("limit must be >= 1") + } + + files, err := packageVersions(*user, *repo, *pkgType, *distro, *distroVersion, *pkg, *arch) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + if len(files) <= *limit { + fmt.Println("Below limit, no packages deleted") + return + } + delete := files[:len(files)-*limit] + keep := files[len(files)-*limit:] + if err = deletePackages(delete); err != nil { + fmt.Println(err) + os.Exit(1) + } + + fmt.Printf("Deleted:\n\n%s\n\nKept:\n\n%s\n", strings.Join(delete, "\n"), strings.Join(keep, "\n")) +} + +type packageMeta struct { + Created time.Time `json:"created_at"` + Filename string `json:"filename"` +} + +type metaSort []packageMeta + +func (m metaSort) Len() int { return len(m) } +func (m metaSort) Less(i, j int) bool { return m[i].Created.Before(m[j].Created) } +func (m metaSort) Swap(i, j int) { m[i], m[j] = m[j], m[i] } + +func packageVersions(user, repo, typ, distro, version, pkgname, arch string) ([]string, error) { + url := fmt.Sprintf("https://%s:@packagecloud.io/api/v1/repos/%s/%s/package/%s/%s/%s/%s/%s/versions.json", os.Getenv("PACKAGECLOUD_API_KEY"), user, repo, typ, distro, version, pkgname, arch) + resp, err := http.Get(url) + if err != nil { + return nil, fmt.Errorf("get versions.json: %s", err) + } + defer resp.Body.Close() + + var files []packageMeta + if err := json.NewDecoder(resp.Body).Decode(&files); err != nil { + return nil, fmt.Errorf("decode versions.json: %s", err) + } + + // Newest first + sort.Sort(metaSort(files)) + + var ret []string + for _, meta := range files { + ret = append(ret, fmt.Sprintf("/api/v1/repos/%s/%s/%s/%s/%s", user, repo, distro, version, meta.Filename)) + } + + return ret, nil +} + +func deletePackages(urls []string) error { + for _, url := range urls { + fullURL := fmt.Sprintf("https://%s:@packagecloud.io%s", os.Getenv("PACKAGECLOUD_API_KEY"), url) + req, err := http.NewRequest("DELETE", fullURL, nil) + if err != nil { + return fmt.Errorf("build delete request for %s: %s", url, err) + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return fmt.Errorf("delete %s: %s", url, err) + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return fmt.Errorf("delete %s: %s", url, resp.Status) + } + } + return nil +} |