initial registry support

Signed-off-by: Josh Dolitsky <jdolitsky@gmail.com>
pull/5243/head
Josh Dolitsky 7 years ago
parent 86d8596763
commit debcc67587

454
Gopkg.lock generated

@ -100,12 +100,12 @@
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
[[projects]]
digest = "1:69b1cc331fca23d702bd72f860c6a647afd0aa9fcbc1d0659b1365e26546dd70"
name = "github.com/Sirupsen/logrus"
branch = "master"
digest = "1:5b8a3b9e8d146a93f6d0538d3be408c9adff07fd694d4094b814a376b4727b14"
name = "github.com/Shopify/logrus-bugsnag"
packages = ["."]
pruneopts = "UT"
revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95"
version = "v1.2.0"
revision = "577dee27f20dd8f1a529f82210094af593be12bd"
[[projects]]
digest = "1:8f5416c7f59da8600725ae1ff00a99af1da8b04c211ae6f3c8f8bcab0164f650"
@ -123,6 +123,43 @@
revision = "7664702784775e51966f0885f5cd27435916517b"
version = "v4"
[[projects]]
branch = "master"
digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
name = "github.com/beorn7/perks"
packages = ["quantile"]
pruneopts = "UT"
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
[[projects]]
digest = "1:7b81d2ed76bf960333a8020c4b8c22abd6072f0b54ad31c66e90e6a17a19315a"
name = "github.com/bshuster-repo/logrus-logstash-hook"
packages = ["."]
pruneopts = "UT"
revision = "dbc1e22735aa6ed7bd9579a407c17bc7c4a4e046"
version = "v0.4.1"
[[projects]]
digest = "1:7643865a2cdb66fb14d8361611a75b370a99211ac44983505b3eecb4a6a7a882"
name = "github.com/bugsnag/bugsnag-go"
packages = [
".",
"device",
"errors",
"headers",
"sessions",
]
pruneopts = "UT"
revision = "109a9d63f2b57c4623f4912b256bac4a7a63517d"
[[projects]]
digest = "1:3049c43c6d1cfaa347acd27d6342187f8f38d9f416bbba7b02b43f82848302d2"
name = "github.com/bugsnag/panicwrap"
packages = ["."]
pruneopts = "UT"
revision = "4009b2b7c78d820cc4a2e42f035bb557ce4ae45b"
version = "v1.2.0"
[[projects]]
digest = "1:65b0d980b428a6ad4425f2df4cd5410edd81f044cf527bd1c345368444649e58"
name = "github.com/census-instrumentation/opencensus-proto"
@ -149,6 +186,23 @@
pruneopts = "UT"
revision = "bf70f2a70fb1b1f36d90d671a72795984eab0fcb"
[[projects]]
digest = "1:1872596d45cb52913fcdea90d468f3e57435959e9c0d99ccb316ee76de341313"
name = "github.com/containerd/containerd"
packages = [
"content",
"errdefs",
"images",
"log",
"platforms",
"reference",
"remotes",
"remotes/docker",
]
pruneopts = "UT"
revision = "9b32062dc1f5a7c2564315c269b5059754f12b9d"
version = "v1.2.1"
[[projects]]
digest = "1:7cb4fdca4c251b3ef8027c90ea35f70c7b661a593b9eeae34753c65499098bb1"
name = "github.com/cpuguy83/go-md2man"
@ -165,6 +219,17 @@
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
version = "v1.1.1"
[[projects]]
digest = "1:8285cd51b86f5c3af447ad1db7c8572578a422cf9a50f1f07eea1d021151044f"
name = "github.com/deislabs/oras"
packages = [
"pkg/content",
"pkg/oras",
]
pruneopts = "UT"
revision = "e8a1fa6ff9a507b99eedd45745959e8c5b826d9f"
version = "v0.3.3"
[[projects]]
digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
name = "github.com/dgrijalva/jwt-go"
@ -174,26 +239,87 @@
version = "v3.2.0"
[[projects]]
digest = "1:4ddc17aeaa82cb18c5f0a25d7c253a10682f518f4b2558a82869506eec223d76"
digest = "1:888aaacf886021e4a0fa6b09a61f1158063bd6c2e2ddefe14f3a7ccbc93ffe27"
name = "github.com/docker/distribution"
packages = [
".",
"configuration",
"context",
"digestset",
"health",
"health/checks",
"manifest",
"manifest/manifestlist",
"manifest/ocischema",
"manifest/schema1",
"manifest/schema2",
"metrics",
"notifications",
"reference",
"registry",
"registry/api/errcode",
"registry/api/v2",
"registry/auth",
"registry/client",
"registry/client/auth",
"registry/client/auth/challenge",
"registry/client/transport",
"registry/handlers",
"registry/listener",
"registry/middleware/registry",
"registry/middleware/repository",
"registry/proxy",
"registry/proxy/scheduler",
"registry/storage",
"registry/storage/cache",
"registry/storage/cache/memory",
"registry/storage/cache/redis",
"registry/storage/driver",
"registry/storage/driver/base",
"registry/storage/driver/factory",
"registry/storage/driver/inmemory",
"registry/storage/driver/middleware",
"uuid",
"version",
]
pruneopts = "UT"
revision = "40b7b5830a2337bb07627617740c0e39eb92800c"
version = "v2.7.0"
[[projects]]
digest = "1:53e99d883df3e940f5f0223795f300eb32b8c044f226132bfc0e74930f24ea4b"
branch = "master"
digest = "1:8da8bb2b12c31c632e96ca6f15666a36c36cd390326b6c5e1c5e309cf4b5419a"
name = "github.com/docker/docker"
packages = [
"pkg/term",
"pkg/term/windows",
]
pruneopts = "UT"
revision = "092cba3727bb9b4a2f0e922cd6c0f93ea270e363"
version = "v1.13.1"
revision = "2cb26cfe9cbf8a64c5046c74d65f4528b22e67f4"
[[projects]]
branch = "master"
digest = "1:2b126e77be4ab4b92cdb3924c87894dd76bf365ba282f358a13133e848aa0059"
name = "github.com/docker/go-metrics"
packages = ["."]
pruneopts = "UT"
revision = "b84716841b82eab644a0c64fc8b42d480e49add5"
[[projects]]
digest = "1:6f82cacd0af5921e99bf3f46748705239b36489464f4529a1589bc895764fb18"
name = "github.com/docker/go-units"
packages = ["."]
pruneopts = "UT"
revision = "47565b4f722fb6ceae66b95f853feed578a4a51c"
version = "v0.3.3"
[[projects]]
branch = "master"
digest = "1:4841e14252a2cecf11840bd05230412ad469709bbacfc12467e2ce5ad07f339b"
name = "github.com/docker/libtrust"
packages = ["."]
pruneopts = "UT"
revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20"
[[projects]]
branch = "master"
@ -207,12 +333,23 @@
revision = "6480d4af844c189cf5dd913db24ddd339d3a4f85"
[[projects]]
digest = "1:f1f2bd73c025d24c3b93abf6364bccb802cf2fdedaa44360804c67800e8fab8d"
digest = "1:899234af23e5793c34e06fd397f86ba33af5307b959b6a7afd19b63db065a9d7"
name = "github.com/emicklei/go-restful"
packages = [
".",
"log",
]
pruneopts = "UT"
revision = "3eb9738c1697594ea6e71a7156a9bb32ed216cf0"
version = "v2.8.0"
[[projects]]
digest = "1:b48d19e79fa607e9e3715ff9a73cdd3777a9cac254b50b9af721466f687e850d"
name = "github.com/evanphx/json-patch"
packages = ["."]
pruneopts = "UT"
revision = "72bf35d0ff611848c1dc9df0f976c81192392fa5"
version = "v4.1.0"
revision = "afac545df32f2287a079e2dfb7ba2745a643747e"
version = "v3.0.0"
[[projects]]
branch = "master"
@ -230,6 +367,17 @@
revision = "44e46d280b43ec1531bb25252440e34f1b800b65"
version = "v1.0.0"
[[projects]]
digest = "1:0594af97b2f4cec6554086eeace6597e20a4b69466eb4ada25adf9f4300dddd2"
name = "github.com/garyburd/redigo"
packages = [
"internal",
"redis",
]
pruneopts = "UT"
revision = "a69d19351219b6dd56f274f96d85a7014a2ec34e"
version = "v1.6.0"
[[projects]]
digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda"
name = "github.com/ghodss/yaml"
@ -288,15 +436,23 @@
version = "v0.2.3"
[[projects]]
digest = "1:34e709f36fd4f868fb00dbaf8a6cab4c1ae685832d392874ba9d7c5dec2429d1"
digest = "1:bed9d72d596f94e65fff37f4d6c01398074a6bb1c3f3ceff963516bd01db6ff5"
name = "github.com/gofrs/uuid"
packages = ["."]
pruneopts = "UT"
revision = "6b08a5c5172ba18946672b49749cde22873dd7c2"
version = "v3.2.0"
[[projects]]
digest = "1:b402bb9a24d108a9405a6f34675091b036c8b056aac843bf6ef2389a65c5cf48"
name = "github.com/gogo/protobuf"
packages = [
"proto",
"sortkeys",
]
pruneopts = "UT"
revision = "636bf0302bc95575d69441b25a2603156ffdddf1"
version = "v1.1.1"
revision = "4cbf7e384e768b4e01799441fdf2a706a5635ae7"
version = "v1.2.0"
[[projects]]
branch = "master"
@ -359,7 +515,7 @@
[[projects]]
branch = "master"
digest = "1:8105da6944d9227dd7c47cf290fbeafeb0b8f3b7f77a89e20b6ae4da7c71bb46"
digest = "1:d47549022c929925679aec031329f59f250d704f69ee44a194998cdb8d873393"
name = "github.com/gophercloud/gophercloud"
packages = [
".",
@ -371,7 +527,23 @@
"pagination",
]
pruneopts = "UT"
revision = "26de66c23d78a75fc37e5dad5b6f16ffbfe9ee31"
revision = "94924357ebf6c7d448c70d65082ff7ca6f78ddc5"
[[projects]]
digest = "1:664d37ea261f0fc73dd17f4a1f5f46d01fbb0b0d75f6375af064824424109b7d"
name = "github.com/gorilla/handlers"
packages = ["."]
pruneopts = "UT"
revision = "7e0847f9db758cdebd26c149d0ae9d5d0b9c98ce"
version = "v1.4.0"
[[projects]]
digest = "1:ca59b1175189b3f0e9f1793d2c350114be36eaabbe5b9f554b35edee1de50aea"
name = "github.com/gorilla/mux"
packages = ["."]
pruneopts = "UT"
revision = "a7962380ca08b5a188038c69871b8d3fbdf31e89"
version = "v1.7.0"
[[projects]]
branch = "master"
@ -439,6 +611,14 @@
revision = "1624edc4454b8682399def8740d46db5e4362ba4"
version = "v1.1.5"
[[projects]]
branch = "master"
digest = "1:caf6db28595425c0e0f2301a00257d11712f65c1878e12cffc42f6b9a9cf3f23"
name = "github.com/kardianos/osext"
packages = ["."]
pruneopts = "UT"
revision = "ae77be60afb1dcacde03767a8c37337fad28ac14"
[[projects]]
digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8"
name = "github.com/konsorten/go-windows-terminal-sequences"
@ -460,12 +640,12 @@
revision = "60711f1a8329503b04e1c88535f419d0bb440bff"
[[projects]]
digest = "1:cdb899c199f907ac9fb50495ec71212c95cb5b0e0a8ee0800da0238036091033"
digest = "1:0356f3312c9bd1cbeda81505b7fd437501d8e778ab66998ef69f00d7f9b3a0d7"
name = "github.com/mattn/go-runewidth"
packages = ["."]
pruneopts = "UT"
revision = "ce7b0b5c7b45a81508558cd1dba6bb1e4ddb51bb"
version = "v0.0.3"
revision = "3ee7d812e62a0804a7d0a324e0249ca2db3476d3"
version = "v0.0.4"
[[projects]]
digest = "1:7efe48dea4db6b35dcc15e15394b627247e5b3fb814242de986b746ba8e0abf0"
@ -475,6 +655,21 @@
revision = "02e3cf038dcea8290e44424da473dd12be796a8a"
version = "v1.0.3"
[[projects]]
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
pruneopts = "UT"
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
version = "v1.0.1"
[[projects]]
digest = "1:fac4398a5e6e7a30f0e5a13c47fd95f153fa0d94be371a6c01568d56808a9791"
name = "github.com/miekg/dns"
packages = ["."]
pruneopts = "UT"
revision = "0d29b283ac0f967dd3a02739bf26a22702210d7a"
[[projects]]
digest = "1:abf08734a6527df70ed361d7c369fb580e6840d8f7a6012e5f609fdfd93b4e48"
name = "github.com/mitchellh/go-wordwrap"
@ -507,6 +702,17 @@
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
version = "v1.0.0-rc1"
[[projects]]
digest = "1:11db38d694c130c800d0aefb502fb02519e514dc53d9804ce51d1ad25ec27db6"
name = "github.com/opencontainers/image-spec"
packages = [
"specs-go",
"specs-go/v1",
]
pruneopts = "UT"
revision = "d60099175f88c47cd379c4738d158884749ed235"
version = "v1.0.1"
[[projects]]
branch = "master"
digest = "1:3bf17a6e6eaa6ad24152148a631d18662f7212e21637c2699bff3369b7f00fa2"
@ -539,6 +745,51 @@
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
digest = "1:93a746f1060a8acbcf69344862b2ceced80f854170e1caae089b2834c5fbf7f4"
name = "github.com/prometheus/client_golang"
packages = [
"prometheus",
"prometheus/internal",
"prometheus/promhttp",
]
pruneopts = "UT"
revision = "505eaef017263e299324067d40ca2c48f6a2cf50"
version = "v0.9.2"
[[projects]]
branch = "master"
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
name = "github.com/prometheus/client_model"
packages = ["go"]
pruneopts = "UT"
revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8"
[[projects]]
digest = "1:35cf6bdf68db765988baa9c4f10cc5d7dda1126a54bd62e252dbcd0b1fc8da90"
name = "github.com/prometheus/common"
packages = [
"expfmt",
"internal/bitbucket.org/ww/goautoneg",
"model",
]
pruneopts = "UT"
revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250"
version = "v0.2.0"
[[projects]]
branch = "master"
digest = "1:5833c61ebbd625a6bad8e5a1ada2b3e13710cf3272046953a2c8915340fe60a3"
name = "github.com/prometheus/procfs"
packages = [
".",
"internal/util",
"nfs",
"xfs",
]
pruneopts = "UT"
revision = "316cf8ccfec56d206735d46333ca162eb374da8b"
[[projects]]
digest = "1:b36a0ede02c4c2aef7df7f91cbbb7bb88a98b5d253509d4f997dda526e50c88c"
name = "github.com/russross/blackfriday"
@ -547,6 +798,14 @@
revision = "05f3235734ad95d0016f6a23902f06461fcf567a"
version = "v1.5.2"
[[projects]]
digest = "1:69b1cc331fca23d702bd72f860c6a647afd0aa9fcbc1d0659b1365e26546dd70"
name = "github.com/sirupsen/logrus"
packages = ["."]
pruneopts = "UT"
revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95"
version = "v1.2.0"
[[projects]]
digest = "1:e01b05ba901239c783dfe56450bcde607fc858908529868259c9a8765dc176d0"
name = "github.com/spf13/cobra"
@ -567,13 +826,47 @@
version = "v1.0.3"
[[projects]]
digest = "1:18752d0b95816a1b777505a97f71c7467a8445b8ffb55631a7bf779f6ba4fa83"
digest = "1:5110e3d4f130772fd39e6ce8208ad1955b242ccfcc8ad9d158857250579c82f4"
name = "github.com/stretchr/testify"
packages = ["assert"]
packages = [
"assert",
"require",
"suite",
]
pruneopts = "UT"
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
version = "v1.2.2"
[[projects]]
digest = "1:340553b2fdaab7d53e63fd40f8ed82203bdd3274253055bdb80a46828482ef81"
name = "github.com/xenolf/lego"
packages = ["acme"]
pruneopts = "UT"
revision = "a9d8cec0e6563575e5868a005359ac97911b5985"
[[projects]]
branch = "master"
digest = "1:dcc3219685abd95a08e219859c5f0d80ad25d365b854849d04896ccde94e2422"
name = "github.com/yvasiyarov/go-metrics"
packages = ["."]
pruneopts = "UT"
revision = "c25f46c4b94079672242ec48a545e7ca9ebe3aec"
[[projects]]
digest = "1:c14faa3573c79c4a37d49b9081e062208ad1f27ec6e67c74c59eec45f17d9ae9"
name = "github.com/yvasiyarov/gorelic"
packages = ["."]
pruneopts = "UT"
revision = "4dc1bb7ab951bc884feb2c009092b1a454152355"
version = "v0.0.6"
[[projects]]
digest = "1:140012d43042bb7748adc780c767abaab8cf6027fe8cb4bca5099d74e2292656"
name = "github.com/yvasiyarov/newrelic_platform_go"
packages = ["."]
pruneopts = "UT"
revision = "b21fdbd4370f3717f3bbd2bf41c223bc273068e6"
[[projects]]
digest = "1:2ae8314c44cd413cfdb5b1df082b350116dd8d2fff973e62c01b285b7affd89e"
name = "go.opencensus.io"
@ -600,12 +893,13 @@
[[projects]]
branch = "master"
digest = "1:77b908a63f61c2e63c69b4b8f89bbecb0138899d236f656f1d255d74249531cb"
digest = "1:599ef9ff10026292c425292ab1d2bb1521cd671fe89a6034df07bf1411daa44b"
name = "golang.org/x/crypto"
packages = [
"cast5",
"ed25519",
"ed25519/internal/edwards25519",
"ocsp",
"openpgp",
"openpgp/armor",
"openpgp/clearsign",
@ -622,20 +916,26 @@
[[projects]]
branch = "master"
digest = "1:29fe5460430a338b64f4a0259a6c59a1e2350bbcff54fa66f906fa8d10515c4d"
digest = "1:647b0128e9a9886335bfb6c9a1fc97758b7f846ec42f222933f6fee6730c96e2"
name = "golang.org/x/net"
packages = [
"bpf",
"context",
"context/ctxhttp",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
"internal/iana",
"internal/socket",
"internal/timeseries",
"ipv4",
"ipv6",
"publicsuffix",
"trace",
]
pruneopts = "UT"
revision = "610586996380ceef02dd726cc09df7e00a3f8e56"
revision = "927f97764cc334a6575f4b7a1584a147864d5723"
[[projects]]
branch = "master"
@ -653,22 +953,25 @@
[[projects]]
branch = "master"
digest = "1:5e4d81c50cffcb124b899e4f3eabec3930c73532f0096c27f94476728ba03028"
digest = "1:04a5b0e4138f98eef79ce12a955a420ee358e9f787044cc3a553ac3c3ade997e"
name = "golang.org/x/sync"
packages = ["semaphore"]
packages = [
"errgroup",
"semaphore",
]
pruneopts = "UT"
revision = "42b317875d0fa942474b76e1b46a6060d720ae6e"
revision = "37e7f081c4d4c64e13b10787722085407fe5d15f"
[[projects]]
branch = "master"
digest = "1:b9dceb1408ba5105803d5859193bc7d89ac3199b611cf8681dbaa0aa09c10d9c"
digest = "1:3d5e79e10549fd9119cbefd614b6d351ef5bd0be2f2b103a4199788e784cbc68"
name = "golang.org/x/sys"
packages = [
"unix",
"windows",
]
pruneopts = "UT"
revision = "70b957f3b65e069b4930ea94e2721eefa0f8f695"
revision = "b4a75ba826a64a70990f11a225237acd6ef35c9f"
[[projects]]
digest = "1:28756bf526c1af662d24519f2fa7abca7237bebb06e3e02941b2b6e5b6ceb7b9"
@ -714,10 +1017,10 @@
name = "google.golang.org/api"
packages = ["support/bundler"]
pruneopts = "UT"
revision = "1a5ef82f9af45ef51c486291ef2b0a16d82fdb95"
revision = "65a46cafb132eff435c7d1e0f439cc73c8eebb85"
[[projects]]
digest = "1:d2a8db567a76203e3b41c1f632d86485ffd57f8e650a0d1b19d240671c2fddd7"
digest = "1:fa026a5c59bd2df343ec4a3538e6288dcf4e2ec5281d743ae82c120affe6926a"
name = "google.golang.org/appengine"
packages = [
".",
@ -732,8 +1035,8 @@
"urlfetch",
]
pruneopts = "UT"
revision = "4a4468ece617fc8205e99368fa2200e9d1fad421"
version = "v1.3.0"
revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1"
version = "v1.4.0"
[[projects]]
branch = "master"
@ -741,7 +1044,7 @@
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
pruneopts = "UT"
revision = "bd91e49a0898e27abb88c339b432fa53d7497ac0"
revision = "bd9b4fb69e2ffd37621a6caa54dcbead29b546f2"
[[projects]]
digest = "1:9edd250a3c46675d0679d87540b30c9ed253b19bd1fd1af08f4f5fb3c79fc487"
@ -791,6 +1094,18 @@
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
version = "v0.9.1"
[[projects]]
digest = "1:0c9d7630c981ff09c7d297db73b3a94358e6572e8de063853c38d1e2c500272e"
name = "gopkg.in/square/go-jose.v1"
packages = [
".",
"cipher",
"json",
]
pruneopts = "UT"
revision = "56062818b5e15ee405eb8363f9498c7113e98337"
version = "v1.1.2"
[[projects]]
digest = "1:550221cdc42e1ad44a1942d01c4135c30f6808b61dbad3c52d325e01d8e7cc07"
name = "gopkg.in/square/go-jose.v2"
@ -937,19 +1252,26 @@
"pkg/util/feature",
]
pruneopts = "UT"
revision = "6e69081b521942e4f4e46a657140d81bc913df73"
revision = "c3083108fa3bda1f3da8742881d36d20330d07a3"
[[projects]]
branch = "master"
digest = "1:63793246976569a95e534c731e79cc555dabee6f8efa29a0b28ca33f23b7e28b"
digest = "1:79d60410b8f3339b77a36d6096cea81ebe4974b7cb8108446a121266b58bff01"
name = "k8s.io/cli-runtime"
packages = [
"pkg/genericclioptions",
"pkg/genericclioptions/printers",
"pkg/genericclioptions/resource",
"pkg/kustomize/k8sdeps",
"pkg/kustomize/k8sdeps/configmapandsecret",
"pkg/kustomize/k8sdeps/kunstruct",
"pkg/kustomize/k8sdeps/transformer",
"pkg/kustomize/k8sdeps/transformer/hash",
"pkg/kustomize/k8sdeps/transformer/patch",
"pkg/kustomize/k8sdeps/validator",
]
pruneopts = "UT"
revision = "2f0d1d0a58f22eae7a0ec3d6cf01f4a122a57dae"
revision = "8abb1aeb8307ee1f2335c4331d850a232efb1cbd"
[[projects]]
digest = "1:ba0a20ca14958ddb44159a08daf69b6acbdc0ef99f449ec7035759e9362bc058"
@ -1088,9 +1410,10 @@
[[projects]]
branch = "master"
digest = "1:4b8768c5b052c2c2a2ba468ec9392657f8bec881b5a24fd172b4d81b0eac6a55"
digest = "1:d8f05387026197d55244f5866ea172e360c3f1602bea51ba90c72a7a43ecdce6"
name = "k8s.io/kube-openapi"
packages = [
"pkg/common",
"pkg/util/proto",
"pkg/util/proto/testing",
"pkg/util/proto/validation",
@ -1222,7 +1545,7 @@
"pkg/version",
]
pruneopts = "UT"
revision = "f2c8f1cadf1808ec28476682e49a3cce2b09efbf"
revision = "598a01989dcd06ec776248506fe6eb32f499bd38"
[[projects]]
branch = "master"
@ -1233,7 +1556,44 @@
"pointer",
]
pruneopts = "UT"
revision = "0d26856f57b32ec3398579285e5c8a2bfe8c5243"
revision = "8a16e7dd8fb6d97d1331b0c79a16722f934b00b1"
[[projects]]
digest = "1:3253435bcec387270fe70c39a4ffcb8bdc9bcc82c32d320b5546ec02a0808007"
name = "rsc.io/letsencrypt"
packages = ["."]
pruneopts = "UT"
revision = "33926faef6d434b854ea994228f11d0185faa0c1"
version = "v0.0.1"
[[projects]]
digest = "1:443f6048f55fc9e389e8f7fa20b25bc30ef565953dd5c6425c9032432a677301"
name = "sigs.k8s.io/kustomize"
packages = [
"pkg/commands/build",
"pkg/constants",
"pkg/expansion",
"pkg/factory",
"pkg/fs",
"pkg/gvk",
"pkg/ifc",
"pkg/ifc/transformer",
"pkg/internal/error",
"pkg/loader",
"pkg/patch",
"pkg/patch/transformer",
"pkg/resid",
"pkg/resmap",
"pkg/resource",
"pkg/target",
"pkg/transformers",
"pkg/transformers/config",
"pkg/transformers/config/defaultconfig",
"pkg/types",
]
pruneopts = "UT"
revision = "8f701a00417a812558a7b785e8354957afa469ae"
version = "v1.0.11"
[[projects]]
digest = "1:7719608fe0b52a4ece56c2dde37bedd95b938677d1ab0f84b8a7852e4c59f849"
@ -1260,22 +1620,36 @@
"github.com/Masterminds/sprig",
"github.com/Masterminds/vcs",
"github.com/asaskevich/govalidator",
"github.com/containerd/containerd/reference",
"github.com/containerd/containerd/remotes",
"github.com/containerd/containerd/remotes/docker",
"github.com/deislabs/oras/pkg/content",
"github.com/deislabs/oras/pkg/oras",
"github.com/docker/distribution/configuration",
"github.com/docker/distribution/registry",
"github.com/docker/distribution/registry/storage/driver/inmemory",
"github.com/docker/go-units",
"github.com/evanphx/json-patch",
"github.com/ghodss/yaml",
"github.com/gobwas/glob",
"github.com/gosuri/uitable",
"github.com/gosuri/uitable/util/strutil",
"github.com/mattn/go-shellwords",
"github.com/opencontainers/go-digest",
"github.com/opencontainers/image-spec/specs-go/v1",
"github.com/pkg/errors",
"github.com/sirupsen/logrus",
"github.com/spf13/cobra",
"github.com/spf13/cobra/doc",
"github.com/spf13/pflag",
"github.com/stretchr/testify/assert",
"github.com/stretchr/testify/suite",
"golang.org/x/crypto/openpgp",
"golang.org/x/crypto/openpgp/clearsign",
"golang.org/x/crypto/openpgp/errors",
"golang.org/x/crypto/openpgp/packet",
"golang.org/x/crypto/ssh/terminal",
"gopkg.in/yaml.v2",
"k8s.io/api/apps/v1",
"k8s.io/api/apps/v1beta1",
"k8s.io/api/apps/v1beta2",

@ -55,9 +55,34 @@
name = "github.com/imdario/mergo"
version = "v0.3.5"
[[constraint]]
name = "github.com/deislabs/oras"
version = "v0.3.3"
[[constraint]]
name = "github.com/docker/go-units"
version = "v0.3.3"
[prune]
go-tests = true
unused-packages = true
[[constraint]]
name = "github.com/stretchr/testify"
# These overrides below necessary for using docker/distribution as a test dependency
[[override]]
name = "github.com/yvasiyarov/newrelic_platform_go"
revision = "b21fdbd4370f3717f3bbd2bf41c223bc273068e6"
[[override]]
name = "github.com/miekg/dns"
revision = "0d29b283ac0f967dd3a02739bf26a22702210d7a"
[[override]]
name = "github.com/xenolf/lego"
revision = "a9d8cec0e6563575e5868a005359ac97911b5985"
[[override]]
name = "github.com/bugsnag/bugsnag-go"
revision = "109a9d63f2b57c4623f4912b256bac4a7a63517d"

@ -85,7 +85,12 @@ coverage:
# dependencies
.PHONY: bootstrap
bootstrap: vendor
bootstrap: vendor fix-vendor
# fix dependecies that are incorrect
.PHONY: fix-vendor
fix-vendor:
wget -O vendor/rsc.io/letsencrypt/lets.go https://raw.githubusercontent.com/dmcgowan/letsencrypt/e770c10b0f1a64775ae91d240407ce00d1a5bdeb/lets.go
$(DEP):
go get -u github.com/golang/dep/cmd/dep

@ -0,0 +1,53 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/helm/pkg/action"
)
const chartHelp = `
This command consists of multiple subcommands to interact with charts and registries.
It can be used to push, pull, tag, list, or remove Helm charts.
Example usage:
$ helm chart pull [URL]
`
func newChartCmd(cfg *action.Configuration) *cobra.Command {
cmd := &cobra.Command{
Use: "chart",
Short: "push, pull, tag, or remove Helm charts",
Long: chartHelp,
}
cmd.AddCommand(
newChartListCmd(cfg),
newChartExportCmd(cfg),
newChartPullCmd(cfg),
newChartPushCmd(cfg),
newChartRemoveCmd(cfg),
newChartSaveCmd(cfg),
)
return cmd
}
// TODO remove once WARN lines removed from oras or containerd
func init() {
logrus.SetLevel(logrus.ErrorLevel)
}

@ -0,0 +1,41 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
"k8s.io/helm/pkg/action"
)
const chartExportDesc = `
TODO
`
func newChartExportCmd(cfg *action.Configuration) *cobra.Command {
return &cobra.Command{
Use: "export [ref]",
Short: "export a chart to directory",
Long: chartExportDesc,
Args: require.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ref := args[0]
return action.NewChartExport(cfg).Run(ref)
},
}
}

@ -0,0 +1,39 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
"k8s.io/helm/pkg/action"
)
const chartListDesc = `
TODO
`
func newChartListCmd(cfg *action.Configuration) *cobra.Command {
return &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "list all saved charts",
Long: chartListDesc,
RunE: func(cmd *cobra.Command, args []string) error {
return action.NewChartList(cfg).Run()
},
}
}

@ -0,0 +1,41 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
"k8s.io/helm/pkg/action"
)
const chartPullDesc = `
TODO
`
func newChartPullCmd(cfg *action.Configuration) *cobra.Command {
return &cobra.Command{
Use: "pull [ref]",
Short: "pull a chart from remote",
Long: chartPullDesc,
Args: require.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ref := args[0]
return action.NewChartPull(cfg).Run(ref)
},
}
}

@ -0,0 +1,41 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
"k8s.io/helm/pkg/action"
)
const chartPushDesc = `
TODO
`
func newChartPushCmd(cfg *action.Configuration) *cobra.Command {
return &cobra.Command{
Use: "push [ref]",
Short: "push a chart to remote",
Long: chartPushDesc,
Args: require.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ref := args[0]
return action.NewChartPush(cfg).Run(ref)
},
}
}

@ -0,0 +1,42 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
"k8s.io/helm/pkg/action"
)
const chartRemoveDesc = `
TODO
`
func newChartRemoveCmd(cfg *action.Configuration) *cobra.Command {
return &cobra.Command{
Use: "remove [ref]",
Aliases: []string{"rm"},
Short: "remove a chart",
Long: chartRemoveDesc,
Args: require.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ref := args[0]
return action.NewChartRemove(cfg).Run(ref)
},
}
}

@ -0,0 +1,42 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
"k8s.io/helm/pkg/action"
)
const chartSaveDesc = `
TODO
`
func newChartSaveCmd(cfg *action.Configuration) *cobra.Command {
return &cobra.Command{
Use: "save [path] [ref]",
Short: "save a chart directory",
Long: chartSaveDesc,
Args: require.MinimumNArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
path := args[0]
ref := args[1]
return action.NewChartSave(cfg).Run(path, ref)
},
}
}

@ -19,11 +19,13 @@ package main // import "k8s.io/helm/cmd/helm"
import (
"io"
"github.com/containerd/containerd/remotes/docker"
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
"k8s.io/helm/pkg/action"
"k8s.io/helm/pkg/helm"
"k8s.io/helm/pkg/registry"
)
var globalUsage = `The Kubernetes package manager
@ -61,6 +63,21 @@ func newRootCmd(c helm.Interface, actionConfig *action.Configuration, out io.Wri
settings.AddFlags(flags)
flags.Parse(args)
// set defaults from environment
settings.Init(flags)
// Add the registry client based on settings
// TODO: Move this elsewhere (first, settings.Init() must move)
actionConfig.RegistryClient = registry.NewClient(&registry.ClientOptions{
Out: out,
Resolver: registry.Resolver{
Resolver: docker.NewResolver(docker.ResolverOptions{}),
},
CacheRootDir: settings.Home.Registry(),
})
cmd.AddCommand(
// chart commands
newCreateCmd(out),
@ -72,6 +89,7 @@ func newRootCmd(c helm.Interface, actionConfig *action.Configuration, out io.Wri
newRepoCmd(out),
newSearchCmd(out),
newVerifyCmd(out),
newChartCmd(actionConfig),
// release commands
newGetCmd(c, out),
@ -95,11 +113,6 @@ func newRootCmd(c helm.Interface, actionConfig *action.Configuration, out io.Wri
newDocsCmd(out),
)
flags.Parse(args)
// set defaults from environment
settings.Init(flags)
// Find and add plugins
loadPlugins(cmd, out)

@ -23,6 +23,7 @@ import (
"k8s.io/client-go/discovery"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/registry"
"k8s.io/helm/pkg/storage"
"k8s.io/helm/pkg/tiller/environment"
)
@ -40,9 +41,13 @@ type Configuration struct {
// Releases stores records of releases.
Releases *storage.Storage
// KubeClient is a Kubernetes API client.
KubeClient environment.KubeClient
// RegistryClient is a client for working with registries
RegistryClient *registry.Client
Capabilities *chartutil.Capabilities
Log func(string, ...interface{})

@ -0,0 +1,70 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package action
import (
"io/ioutil"
"os"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/registry"
)
// ChartExport performs a chart export operation.
type ChartExport struct {
cfg *Configuration
}
// NewChartExport creates a new ChartExport object with the given configuration.
func NewChartExport(cfg *Configuration) *ChartExport {
return &ChartExport{
cfg: cfg,
}
}
// Run executes the chart export operation
func (a *ChartExport) Run(ref string) error {
r, err := registry.ParseReference(ref)
if err != nil {
return err
}
ch, err := a.cfg.RegistryClient.LoadChart(r)
if err != nil {
return err
}
// Save the chart to local directory
// TODO: init in Helm home? Or no file creation at all?
tempDirPrefix := ".helm-chart-export"
os.MkdirAll(tempDirPrefix, 0755)
tempDir, err := ioutil.TempDir(tempDirPrefix, "")
if err != nil {
return err
}
defer os.RemoveAll(tempDir)
tarballAbsPath, err := chartutil.Save(ch, tempDir)
if err != nil {
return err
}
err = chartutil.ExpandFile("", tarballAbsPath)
if err != nil {
return err
}
return nil
}

@ -0,0 +1,34 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package action
// ChartList performs a chart list operation.
type ChartList struct {
cfg *Configuration
}
// NewChartList creates a new ChartList object with the given configuration.
func NewChartList(cfg *Configuration) *ChartList {
return &ChartList{
cfg: cfg,
}
}
// Run executes the chart list operation
func (a *ChartList) Run() error {
return a.cfg.RegistryClient.PrintChartTable()
}

@ -0,0 +1,42 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package action
import (
"k8s.io/helm/pkg/registry"
)
// ChartPull performs a chart pull operation.
type ChartPull struct {
cfg *Configuration
}
// NewChartPull creates a new ChartPull object with the given configuration.
func NewChartPull(cfg *Configuration) *ChartPull {
return &ChartPull{
cfg: cfg,
}
}
// Run executes the chart pull operation
func (a *ChartPull) Run(ref string) error {
r, err := registry.ParseReference(ref)
if err != nil {
return err
}
return a.cfg.RegistryClient.PullChart(r)
}

@ -0,0 +1,42 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package action
import (
"k8s.io/helm/pkg/registry"
)
// ChartPush performs a chart push operation.
type ChartPush struct {
cfg *Configuration
}
// NewChartPush creates a new ChartPush object with the given configuration.
func NewChartPush(cfg *Configuration) *ChartPush {
return &ChartPush{
cfg: cfg,
}
}
// Run executes the chart push operation
func (a *ChartPush) Run(ref string) error {
r, err := registry.ParseReference(ref)
if err != nil {
return err
}
return a.cfg.RegistryClient.PushChart(r)
}

@ -0,0 +1,42 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package action
import (
"k8s.io/helm/pkg/registry"
)
// ChartRemove performs a chart remove operation.
type ChartRemove struct {
cfg *Configuration
}
// NewChartRemove creates a new ChartRemove object with the given configuration.
func NewChartRemove(cfg *Configuration) *ChartRemove {
return &ChartRemove{
cfg: cfg,
}
}
// Run executes the chart remove operation
func (a *ChartRemove) Run(ref string) error {
r, err := registry.ParseReference(ref)
if err != nil {
return err
}
return a.cfg.RegistryClient.RemoveChart(r)
}

@ -0,0 +1,56 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package action
import (
"path/filepath"
"k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/registry"
)
// ChartSave performs a chart save operation.
type ChartSave struct {
cfg *Configuration
}
// NewChartSave creates a new ChartSave object with the given configuration.
func NewChartSave(cfg *Configuration) *ChartSave {
return &ChartSave{
cfg: cfg,
}
}
// Run executes the chart save operation
func (a *ChartSave) Run(path string, ref string) error {
path, err := filepath.Abs(path)
if err != nil {
return err
}
ch, err := loader.LoadDir(path)
if err != nil {
return err
}
r, err := registry.ParseReference(ref)
if err != nil {
return err
}
return a.cfg.RegistryClient.SaveChart(ch, r)
}

@ -40,6 +40,11 @@ func (h Home) Path(elem ...string) string {
return filepath.Join(p...)
}
// Registry returns the path to the local registry cache.
func (h Home) Registry() string {
return h.Path("registry")
}
// Repository returns the path to the local repository.
func (h Home) Repository() string {
return h.Path("repository")

@ -31,6 +31,7 @@ func TestHelmHome(t *testing.T) {
}
isEq(t, hh.String(), "/r")
isEq(t, hh.Registry(), "/r/registry")
isEq(t, hh.Repository(), "/r/repository")
isEq(t, hh.RepositoryFile(), "/r/repository/repositories.yaml")
isEq(t, hh.Cache(), "/r/repository/cache")

@ -28,6 +28,7 @@ func TestHelmHome(t *testing.T) {
}
isEq(t, hh.String(), "r:\\")
isEq(t, hh.Registry(), "r:\\registry")
isEq(t, hh.Repository(), "r:\\repository")
isEq(t, hh.RepositoryFile(), "r:\\repository\\repositories.yaml")
isEq(t, hh.Cache(), "r:\\repository\\cache")

@ -0,0 +1 @@
helm-registry-test

@ -0,0 +1,446 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package registry // import "k8s.io/helm/pkg/registry"
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
"time"
orascontent "github.com/deislabs/oras/pkg/content"
"github.com/docker/go-units"
checksum "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/chartutil"
)
type (
filesystemCache struct {
out io.Writer
rootDir string
store *orascontent.Memorystore
}
)
func (cache *filesystemCache) LayersToChart(layers []ocispec.Descriptor) (*chart.Chart, error) {
metaLayer, contentLayer, err := extractLayers(layers)
if err != nil {
return nil, err
}
name, version, err := extractChartNameVersionFromLayer(contentLayer)
if err != nil {
return nil, err
}
// Obtain raw chart meta content (json)
_, metaJSONRaw, ok := cache.store.Get(metaLayer)
if !ok {
return nil, errors.New("error retrieving meta layer")
}
// Construct chart metadata object
metadata := chart.Metadata{}
err = json.Unmarshal(metaJSONRaw, &metadata)
if err != nil {
return nil, err
}
metadata.Name = name
metadata.Version = version
// Obtain raw chart content
_, contentRaw, ok := cache.store.Get(contentLayer)
if !ok {
return nil, errors.New("error retrieving meta layer")
}
// Construct chart object and attach metadata
ch, err := loader.LoadArchive(bytes.NewBuffer(contentRaw))
if err != nil {
return nil, err
}
ch.Metadata = &metadata
return ch, nil
}
func (cache *filesystemCache) ChartToLayers(ch *chart.Chart) ([]ocispec.Descriptor, error) {
// extract/separate the name and version from other metadata
if ch.Metadata == nil {
return nil, errors.New("chart does not contain metadata")
}
name := ch.Metadata.Name
version := ch.Metadata.Version
// Create meta layer, clear name and version from Chart.yaml and convert to json
ch.Metadata.Name = ""
ch.Metadata.Version = ""
metaJSONRaw, err := json.Marshal(ch.Metadata)
if err != nil {
return nil, err
}
metaLayer := cache.store.Add(HelmChartMetaFileName, HelmChartMetaMediaType, metaJSONRaw)
// Create content layer
// TODO: something better than this hack. Currently needed for chartutil.Save()
ch.Metadata = &chart.Metadata{Name: "-", Version: "-"}
destDir := mkdir(filepath.Join(cache.rootDir, "blobs", ".build"))
tmpFile, err := chartutil.Save(ch, destDir)
defer os.Remove(tmpFile)
if err != nil {
return nil, errors.Wrap(err, "failed to save")
}
contentRaw, err := ioutil.ReadFile(tmpFile)
if err != nil {
return nil, err
}
contentLayer := cache.store.Add(HelmChartContentFileName, HelmChartContentMediaType, contentRaw)
// Set annotations
contentLayer.Annotations[HelmChartNameAnnotation] = name
contentLayer.Annotations[HelmChartVersionAnnotation] = version
layers := []ocispec.Descriptor{metaLayer, contentLayer}
return layers, nil
}
func (cache *filesystemCache) LoadReference(ref *Reference) ([]ocispec.Descriptor, error) {
tagDir := filepath.Join(cache.rootDir, "refs", ref.Locator, "tags", tagOrDefault(ref.Object))
// add meta layer
metaJSONRaw, err := getSymlinkDestContent(filepath.Join(tagDir, "meta"))
if err != nil {
return nil, err
}
metaLayer := cache.store.Add(HelmChartMetaFileName, HelmChartMetaMediaType, metaJSONRaw)
// add content layer
contentRaw, err := getSymlinkDestContent(filepath.Join(tagDir, "content"))
if err != nil {
return nil, err
}
contentLayer := cache.store.Add(HelmChartContentFileName, HelmChartContentMediaType, contentRaw)
// set annotations on content layer (chart name and version)
err = setLayerAnnotationsFromChartLink(contentLayer, filepath.Join(tagDir, "chart"))
if err != nil {
return nil, err
}
layers := []ocispec.Descriptor{metaLayer, contentLayer}
return layers, nil
}
func (cache *filesystemCache) StoreReference(ref *Reference, layers []ocispec.Descriptor) error {
tagDir := mkdir(filepath.Join(cache.rootDir, "refs", ref.Locator, "tags", tagOrDefault(ref.Object)))
// Retrieve just the meta and content layers
metaLayer, contentLayer, err := extractLayers(layers)
if err != nil {
return err
}
// Extract chart name and version
name, version, err := extractChartNameVersionFromLayer(contentLayer)
if err != nil {
return err
}
// Create chart file
chartPath, err := createChartFile(filepath.Join(cache.rootDir, "charts"), name, version)
if err != nil {
return err
}
// Create chart symlink
err = createSymlink(chartPath, filepath.Join(tagDir, "chart"))
if err != nil {
return err
}
// Save meta blob
_, metaJSONRaw, ok := cache.store.Get(metaLayer)
if !ok {
return errors.New("error retrieving meta layer")
}
metaPath, err := createDigestFile(filepath.Join(cache.rootDir, "blobs", "meta"), metaJSONRaw)
if err != nil {
return err
}
// Create meta symlink
err = createSymlink(metaPath, filepath.Join(tagDir, "meta"))
if err != nil {
return err
}
// Save content blob
_, contentRaw, ok := cache.store.Get(contentLayer)
if !ok {
return errors.New("error retrieving content layer")
}
contentPath, err := createDigestFile(filepath.Join(cache.rootDir, "blobs", "content"), contentRaw)
if err != nil {
return err
}
// Create content symlink
return createSymlink(contentPath, filepath.Join(tagDir, "content"))
}
func (cache *filesystemCache) DeleteReference(ref *Reference) error {
tagDir := filepath.Join(cache.rootDir, "refs", ref.Locator, "tags", tagOrDefault(ref.Object))
if _, err := os.Stat(tagDir); os.IsNotExist(err) {
return errors.New("ref not found")
}
return os.RemoveAll(tagDir)
}
func (cache *filesystemCache) TableRows() ([][]string, error) {
return getRefsSorted(filepath.Join(cache.rootDir, "refs"))
}
// mkdir will create a directory (no error check) and return the path
func mkdir(dir string) string {
os.MkdirAll(dir, 0755)
return dir
}
// createSymlink creates a symbolic link, deleting existing one if exists
func createSymlink(src string, dest string) error {
os.Remove(dest)
err := os.Symlink(src, dest)
return err
}
// getSymlinkDestContent returns the file contents of a symlink's destination
func getSymlinkDestContent(linkPath string) ([]byte, error) {
src, err := os.Readlink(linkPath)
if err != nil {
return nil, err
}
return ioutil.ReadFile(src)
}
// setLayerAnnotationsFromChartLink will set chart name/version annotations on a layer
// based on the path of the chart link destination
func setLayerAnnotationsFromChartLink(layer ocispec.Descriptor, chartLinkPath string) error {
src, err := os.Readlink(chartLinkPath)
if err != nil {
return err
}
// example path: /some/path/charts/mychart/versions/1.2.0
chartName := filepath.Base(filepath.Dir(filepath.Dir(src)))
chartVersion := filepath.Base(src)
layer.Annotations[HelmChartNameAnnotation] = chartName
layer.Annotations[HelmChartVersionAnnotation] = chartVersion
return nil
}
// extractLayers obtains the meta and content layers from a list of layers
func extractLayers(layers []ocispec.Descriptor) (ocispec.Descriptor, ocispec.Descriptor, error) {
var metaLayer, contentLayer ocispec.Descriptor
if len(layers) != 2 {
return metaLayer, contentLayer, errors.New("manifest does not contain exactly 2 layers")
}
for _, layer := range layers {
switch layer.MediaType {
case HelmChartMetaMediaType:
metaLayer = layer
case HelmChartContentMediaType:
contentLayer = layer
}
}
if metaLayer.Size == 0 {
return metaLayer, contentLayer, errors.New("manifest does not contain a Helm chart meta layer")
}
if contentLayer.Size == 0 {
return metaLayer, contentLayer, errors.New("manifest does not contain a Helm chart content layer")
}
return metaLayer, contentLayer, nil
}
// extractChartNameVersionFromLayer retrieves the chart name and version from layer annotations
func extractChartNameVersionFromLayer(layer ocispec.Descriptor) (string, string, error) {
name, ok := layer.Annotations[HelmChartNameAnnotation]
if !ok {
return "", "", errors.New("could not find chart name in annotations")
}
version, ok := layer.Annotations[HelmChartVersionAnnotation]
if !ok {
return "", "", errors.New("could not find chart version in annotations")
}
return name, version, nil
}
// createChartFile creates a file under "<chartsdir>" dir which is linked to by ref
func createChartFile(chartsRootDir string, name string, version string) (string, error) {
chartPathDir := filepath.Join(chartsRootDir, name, "versions")
chartPath := filepath.Join(chartPathDir, version)
if _, err := os.Stat(chartPath); err != nil && os.IsNotExist(err) {
os.MkdirAll(chartPathDir, 0755)
err := ioutil.WriteFile(chartPath, []byte("-"), 0644)
if err != nil {
return "", err
}
}
return chartPath, nil
}
// createDigestFile calcultaes the sha256 digest of some content and creates a file, returning the path
func createDigestFile(rootDir string, c []byte) (string, error) {
digest := checksum.FromBytes(c).String()
digestLeft, digestRight := splitDigest(digest)
pathDir := filepath.Join(rootDir, "sha256", digestLeft)
path := filepath.Join(pathDir, digestRight)
if _, err := os.Stat(path); err != nil && os.IsNotExist(err) {
os.MkdirAll(pathDir, 0755)
err := ioutil.WriteFile(path, c, 0644)
if err != nil {
return "", err
}
}
return path, nil
}
// splitDigest returns a sha256 digest in two parts, on with first 2 chars and one with second 62 chars
func splitDigest(digest string) (string, string) {
var digestLeft, digestRight string
digest = strings.TrimPrefix(digest, "sha256:")
if len(digest) == 64 {
digestLeft = digest[0:2]
digestRight = digest[2:64]
}
return digestLeft, digestRight
}
// byteCountBinary produces a human-readable file size
func byteCountBinary(b int64) string {
const unit = 1024
if b < unit {
return fmt.Sprintf("%d B", b)
}
div, exp := int64(unit), 0
for n := b / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %ciB", float64(b)/float64(div), "KMGTPE"[exp])
}
// tagOrDefault returns the tag if present, if not the default tag
func tagOrDefault(tag string) string {
if tag != "" {
return tag
}
return HelmChartDefaultTag
}
// getRefsSorted returns a map of all refs stored in a refsRootDir
func getRefsSorted(refsRootDir string) ([][]string, error) {
refsMap := map[string]map[string]string{}
// Walk the storage dir, check for symlinks under "refs" dir pointing to valid files in "blobs/" and "charts/"
err := filepath.Walk(refsRootDir, func(path string, fileInfo os.FileInfo, fileError error) error {
// Check if this file is a symlink
linkPath, err := os.Readlink(path)
if err == nil {
destFileInfo, err := os.Stat(linkPath)
if err == nil {
tagDir := filepath.Dir(path)
// Determine the ref
locator := strings.TrimLeft(
strings.TrimPrefix(filepath.Dir(filepath.Dir(tagDir)), refsRootDir), "/\\")
object := filepath.Base(tagDir)
ref := fmt.Sprintf("%s:%s", locator, object)
// Init hashmap entry if does not exist
if _, ok := refsMap[ref]; !ok {
refsMap[ref] = map[string]string{}
}
// Add data to entry based on file name (symlink name)
base := filepath.Base(path)
switch base {
case "chart":
refsMap[ref]["name"] = filepath.Base(filepath.Dir(filepath.Dir(linkPath)))
refsMap[ref]["version"] = destFileInfo.Name()
case "content":
shaPrefix := filepath.Base(filepath.Dir(linkPath))
digest := fmt.Sprintf("%s%s", shaPrefix, destFileInfo.Name())
// Make sure the filename looks like a sha256 digest (64 chars)
if len(digest) == 64 {
refsMap[ref]["digest"] = digest[:7]
refsMap[ref]["size"] = byteCountBinary(destFileInfo.Size())
refsMap[ref]["created"] = units.HumanDuration(time.Now().UTC().Sub(destFileInfo.ModTime()))
}
}
}
}
return nil
})
// Filter out any refs that are incomplete (do not have all required fields)
for k, ref := range refsMap {
allKeysFound := true
for _, v := range []string{"name", "version", "digest", "size", "created"} {
if _, ok := ref[v]; !ok {
allKeysFound = false
break
}
}
if !allKeysFound {
delete(refsMap, k)
}
}
// Sort and convert to slice of slices
var refs [][]string
keys := make([]string, 0, len(refsMap))
for key := range refsMap {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
ref := refsMap[key]
ref["ref"] = key
refs = append(refs, []string{key, ref["name"], ref["version"], ref["digest"], ref["size"], ref["created"]})
}
return refs, err
}

@ -0,0 +1,122 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package registry // import "k8s.io/helm/pkg/registry"
import (
"context"
"fmt"
"io"
orascontent "github.com/deislabs/oras/pkg/content"
"github.com/deislabs/oras/pkg/oras"
"github.com/gosuri/uitable"
"k8s.io/helm/pkg/chart"
)
type (
// ClientOptions is used to construct a new client
ClientOptions struct {
Out io.Writer
Resolver Resolver
CacheRootDir string
}
// Client works with OCI-compliant registries and local Helm chart cache
Client struct {
out io.Writer
resolver Resolver
cache *filesystemCache // TODO: something more robust
}
)
// NewClient returns a new registry client with config
func NewClient(options *ClientOptions) *Client {
return &Client{
out: options.Out,
resolver: options.Resolver,
cache: &filesystemCache{
out: options.Out,
rootDir: options.CacheRootDir,
store: orascontent.NewMemoryStore(),
},
}
}
// PushChart uploads a chart to a registry
func (c *Client) PushChart(ref *Reference) error {
layers, err := c.cache.LoadReference(ref)
if err != nil {
return err
}
err = oras.Push(context.Background(), c.resolver, ref.String(), c.cache.store, layers)
return err
}
// PullChart downloads a chart from a registry
func (c *Client) PullChart(ref *Reference) error {
layers, err := oras.Pull(context.Background(), c.resolver, ref.String(), c.cache.store, KnownMediaTypes()...)
if err != nil {
return err
}
err = c.cache.StoreReference(ref, layers)
return err
}
// SaveChart stores a copy of chart in local cache
func (c *Client) SaveChart(ch *chart.Chart, ref *Reference) error {
layers, err := c.cache.ChartToLayers(ch)
if err != nil {
return err
}
err = c.cache.StoreReference(ref, layers)
return err
}
// LoadChart retrieves a chart object by reference
func (c *Client) LoadChart(ref *Reference) (*chart.Chart, error) {
layers, err := c.cache.LoadReference(ref)
if err != nil {
return nil, err
}
ch, err := c.cache.LayersToChart(layers)
return ch, err
}
// RemoveChart deletes a locally saved chart
func (c *Client) RemoveChart(ref *Reference) error {
err := c.cache.DeleteReference(ref)
return err
}
// PrintChartTable prints a list of locally stored charts
func (c *Client) PrintChartTable() error {
table := uitable.New()
table.MaxColWidth = 60
table.AddRow("REF", "NAME", "VERSION", "DIGEST", "SIZE", "CREATED")
rows, err := c.cache.TableRows()
if err != nil {
return err
}
for _, row := range rows {
if len(row) == 6 {
table.AddRow(row[0], row[1], row[2], row[3], row[4], row[5])
}
}
fmt.Fprintln(c.out, table.String())
return nil
}

@ -0,0 +1,178 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package registry
import (
"bytes"
"context"
"fmt"
"io"
"k8s.io/helm/pkg/chart"
"net"
"os"
"testing"
"time"
"github.com/containerd/containerd/remotes/docker"
"github.com/docker/distribution/configuration"
"github.com/docker/distribution/registry"
_ "github.com/docker/distribution/registry/storage/driver/inmemory"
"github.com/stretchr/testify/suite"
)
type RegistryClientTestSuite struct {
suite.Suite
Out io.Writer
DockerRegistryHost string
RegistryClient *Client
}
func (suite *RegistryClientTestSuite) SetupSuite() {
os.RemoveAll("helm-registry-test")
// Init test client
var out bytes.Buffer
suite.Out = &out
suite.RegistryClient = NewClient(&ClientOptions{
Out: suite.Out,
Resolver: Resolver{
Resolver: docker.NewResolver(docker.ResolverOptions{}),
},
CacheRootDir: "helm-registry-test",
})
// Registry config
config := &configuration.Configuration{}
port, err := getFreePort()
if err != nil {
suite.Nil(err, "no error finding free port for test registry")
}
suite.DockerRegistryHost = fmt.Sprintf("localhost:%d", port)
config.HTTP.Addr = fmt.Sprintf(":%d", port)
config.HTTP.DrainTimeout = time.Duration(10) * time.Second
config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}}
dockerRegistry, err := registry.NewRegistry(context.Background(), config)
suite.Nil(err, "no error creating test registry")
// Start Docker registry
go dockerRegistry.ListenAndServe()
}
func (suite *RegistryClientTestSuite) Test_0_SaveChart() {
ref, err := ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost))
suite.Nil(err)
// empty chart
err = suite.RegistryClient.SaveChart(&chart.Chart{}, ref)
suite.NotNil(err)
// valid chart
ch := &chart.Chart{}
ch.Metadata = &chart.Metadata{
Name: "testchart",
Version: "1.2.3",
}
err = suite.RegistryClient.SaveChart(ch, ref)
suite.Nil(err)
}
func (suite *RegistryClientTestSuite) Test_1_LoadChart() {
// non-existent ref
ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost))
suite.Nil(err)
ch, err := suite.RegistryClient.LoadChart(ref)
suite.NotNil(err)
// existing ref
ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost))
suite.Nil(err)
ch, err = suite.RegistryClient.LoadChart(ref)
suite.Nil(err)
suite.Equal("testchart", ch.Metadata.Name)
suite.Equal("1.2.3", ch.Metadata.Version)
}
func (suite *RegistryClientTestSuite) Test_2_PushChart() {
// non-existent ref
ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost))
suite.Nil(err)
err = suite.RegistryClient.PushChart(ref)
suite.NotNil(err)
// existing ref
ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost))
suite.Nil(err)
err = suite.RegistryClient.PushChart(ref)
suite.Nil(err)
}
func (suite *RegistryClientTestSuite) Test_3_PullChart() {
// non-existent ref
ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost))
suite.Nil(err)
err = suite.RegistryClient.PullChart(ref)
suite.NotNil(err)
// existing ref
ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost))
suite.Nil(err)
err = suite.RegistryClient.PullChart(ref)
suite.Nil(err)
}
func (suite *RegistryClientTestSuite) Test_4_PrintChartTable() {
err := suite.RegistryClient.PrintChartTable()
suite.Nil(err)
}
func (suite *RegistryClientTestSuite) Test_5_RemoveChart() {
// non-existent ref
ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost))
suite.Nil(err)
err = suite.RegistryClient.RemoveChart(ref)
suite.NotNil(err)
// existing ref
ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost))
suite.Nil(err)
err = suite.RegistryClient.RemoveChart(ref)
suite.Nil(err)
}
func TestRegistryClientTestSuite(t *testing.T) {
suite.Run(t, new(RegistryClientTestSuite))
}
// borrowed from https://github.com/phayes/freeport
func getFreePort() (int, error) {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
return 0, err
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return 0, err
}
defer l.Close()
return l.Addr().(*net.TCPAddr).Port, nil
}

@ -0,0 +1,48 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package registry // import "k8s.io/helm/pkg/registry"
const (
// HelmChartDefaultTag is the default tag used when storing a chart reference with no tag
HelmChartDefaultTag = "latest"
// HelmChartMetaMediaType is the reserved media type for Helm chart metadata
HelmChartMetaMediaType = "application/vnd.cncf.helm.chart.meta.v1+json"
// HelmChartContentMediaType is the reserved media type for Helm chart package content
HelmChartContentMediaType = "application/vnd.cncf.helm.chart.content.v1+tar"
// HelmChartMetaFileName is the reserved file name for Helm chart metadata
HelmChartMetaFileName = "chart-meta.json"
// HelmChartContentFileName is the reserved file name for Helm chart package content
HelmChartContentFileName = "chart-content.tgz"
// HelmChartNameAnnotation is the reserved annotation key for Helm chart name
HelmChartNameAnnotation = "sh.helm.chart.name"
// HelmChartVersionAnnotation is the reserved annotation key for Helm chart version
HelmChartVersionAnnotation = "sh.helm.chart.version"
)
// KnownMediaTypes returns a list of layer mediaTypes that the Helm client knows about
func KnownMediaTypes() []string {
return []string{
HelmChartMetaMediaType,
HelmChartContentMediaType,
}
}

@ -0,0 +1,29 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package registry
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestConstants(t *testing.T) {
knownMediaTypes := KnownMediaTypes()
assert.Contains(t, knownMediaTypes, HelmChartMetaMediaType)
assert.Contains(t, knownMediaTypes, HelmChartContentMediaType)
}

@ -0,0 +1,45 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package registry // import "k8s.io/helm/pkg/registry"
import (
"strings"
"github.com/containerd/containerd/reference"
)
type (
// Reference defines the main components of a reference specification
Reference struct {
*reference.Spec
}
)
// ParseReference converts a string to a Reference
func ParseReference(s string) (*Reference, error) {
spec, err := reference.Parse(s)
if err != nil {
return nil, err
}
ref := Reference{&spec}
return &ref, nil
}
// Repo returns a reference's repo minus the hostname
func (ref *Reference) Repo() string {
return strings.TrimPrefix(strings.TrimPrefix(ref.Locator, ref.Hostname()), "/")
}

@ -0,0 +1,49 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package registry
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestReference(t *testing.T) {
is := assert.New(t)
// bad ref
s := ""
_, err := ParseReference(s)
is.Error(err)
// good refs
s = "localhost:5000/mychart:latest"
ref, err := ParseReference(s)
is.NoError(err)
is.Equal("localhost:5000", ref.Hostname())
is.Equal("mychart", ref.Repo())
is.Equal("localhost:5000/mychart", ref.Locator)
is.Equal("latest", ref.Object)
s = "my.host.com/my/nested/repo:1.2.3"
ref, err = ParseReference(s)
is.NoError(err)
is.Equal("my.host.com", ref.Hostname())
is.Equal("my/nested/repo", ref.Repo())
is.Equal("my.host.com/my/nested/repo", ref.Locator)
is.Equal("1.2.3", ref.Object)
}

@ -0,0 +1,28 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package registry // import "k8s.io/helm/pkg/registry"
import (
"github.com/containerd/containerd/remotes"
)
type (
// Resolver provides remotes based on a locator
Resolver struct {
remotes.Resolver
}
)
Loading…
Cancel
Save