Commit 57bd8b2c authored by Adam Reese's avatar Adam Reese

feat(*): install releases into namespace

parent a0bc5106
......@@ -48,4 +48,6 @@ message Release {
// Version is an int32 which represents the version of the release.
int32 version = 7;
// Namespace is the kubernetes namespace of the release.
string namespace = 8;
}
......@@ -178,6 +178,9 @@ message InstallReleaseRequest {
// DisableHooks causes the server to skip running any hooks for the install.
bool disable_hooks = 5;
// Namepace is the kubernetes namespace of the release.
string namespace = 6;
}
// InstallReleaseResponse is the response from a release installation.
......
......@@ -28,14 +28,14 @@ import (
)
const (
homeEnvVar = "HELM_HOME"
hostEnvVar = "HELM_HOST"
homeEnvVar = "HELM_HOME"
hostEnvVar = "HELM_HOST"
tillerNamespace = "kube-system"
)
var (
helmHome string
tillerHost string
tillerNamespace string
helmHome string
tillerHost string
)
// flagDebug is a signal that the user wants additional output.
......@@ -80,7 +80,6 @@ func newRootCmd(out io.Writer) *cobra.Command {
p := cmd.PersistentFlags()
p.StringVar(&helmHome, "home", home, "location of your Helm config. Overrides $HELM_HOME.")
p.StringVar(&tillerHost, "host", thost, "address of tiller. Overrides $HELM_HOST.")
p.StringVarP(&tillerNamespace, "namespace", "", "", "kubernetes namespace")
p.BoolVarP(&flagDebug, "debug", "", false, "enable verbose output")
cmd.AddCommand(
......
......@@ -83,6 +83,9 @@ type fakeReleaseClient struct {
err error
}
var _ helm.Interface = &fakeReleaseClient{}
var _ helm.Interface = &helm.Client{}
func (c *fakeReleaseClient) ListReleases(opts ...helm.ReleaseListOption) (*rls.ListReleasesResponse, error) {
resp := &rls.ListReleasesResponse{
Count: int64(len(c.rels)),
......@@ -91,7 +94,7 @@ func (c *fakeReleaseClient) ListReleases(opts ...helm.ReleaseListOption) (*rls.L
return resp, c.err
}
func (c *fakeReleaseClient) InstallRelease(chStr string, opts ...helm.InstallOption) (*rls.InstallReleaseResponse, error) {
func (c *fakeReleaseClient) InstallRelease(chStr, ns string, opts ...helm.InstallOption) (*rls.InstallReleaseResponse, error) {
return &rls.InstallReleaseResponse{
Release: c.rels[0],
}, nil
......
......@@ -41,13 +41,13 @@ chart in the current working directory.
type installCmd struct {
name string
namespace string
valuesFile string
chartPath string
dryRun bool
disableHooks bool
out io.Writer
client helm.Interface
out io.Writer
client helm.Interface
}
func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
......@@ -78,9 +78,10 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
f := cmd.Flags()
f.StringVarP(&inst.valuesFile, "values", "f", "", "path to a values YAML file")
f.StringVarP(&inst.name, "name", "n", "", "the release name. If unspecified, it will autogenerate one for you.")
// TODO use kubeconfig default
f.StringVar(&inst.namespace, "namespace", "default", "the namespace to install the release into")
f.BoolVar(&inst.dryRun, "dry-run", false, "simulate an install")
f.BoolVar(&inst.disableHooks, "no-hooks", false, "prevent hooks from running during install")
return cmd
}
......@@ -94,7 +95,7 @@ func (i *installCmd) run() error {
return err
}
res, err := i.client.InstallRelease(i.chartPath, helm.ValueOverrides(rawVals), helm.ReleaseName(i.name), helm.InstallDryRun(i.dryRun), helm.InstallDisableHooks(i.disableHooks))
res, err := i.client.InstallRelease(i.chartPath, i.namespace, helm.ValueOverrides(rawVals), helm.ReleaseName(i.name), helm.InstallDryRun(i.dryRun), helm.InstallDisableHooks(i.disableHooks))
if err != nil {
return prettyError(err)
}
......@@ -118,6 +119,7 @@ func (i *installCmd) printRelease(rel *release.Release) {
// TODO: Switch to text/template like everything else.
if flagDebug {
fmt.Fprintf(i.out, "NAME: %s\n", rel.Name)
fmt.Fprintf(i.out, "NAMESPACE: %s\n", rel.Namespace)
fmt.Fprintf(i.out, "INFO: %s %s\n", timeconv.String(rel.Info.LastDeployed), rel.Info.Status)
fmt.Fprintf(i.out, "CHART: %s %s\n", rel.Chart.Metadata.Name, rel.Chart.Metadata.Version)
fmt.Fprintf(i.out, "MANIFEST: %s\n", rel.Manifest)
......
......@@ -29,23 +29,13 @@ import (
var tunnel *kube.Tunnel
func newTillerPortForwarder(namespace string) (*kube.Tunnel, error) {
kc := kube.New(nil)
if namespace == "" {
ns, _, err := kc.DefaultNamespace()
if err != nil {
return nil, err
}
namespace = ns
}
podName, err := getTillerPodName(namespace)
if err != nil {
return nil, err
}
// FIXME use a constain that is accessible on init
const tillerPort = 44134
return kc.ForwardPort(namespace, podName, tillerPort)
return kube.New(nil).ForwardPort(namespace, podName, tillerPort)
}
func getTillerPodName(namespace string) (string, error) {
......
......@@ -36,9 +36,6 @@ import (
// GoTplEngine is the name of the Go template engine, as registered in the EngineYard.
const GoTplEngine = "gotpl"
// DefaultNamespace is the default namespace for Tiller.
const DefaultNamespace = "helm"
// DefaultEngine points to the engine that the EngineYard should treat as the
// default. A chart that does not specify an engine may be run through the
// default engine.
......@@ -196,8 +193,6 @@ func (p *PrintingKubeClient) WatchUntilReady(ns string, r io.Reader) error {
//
// All services in a context are concurrency safe.
type Environment struct {
// The default namespace
Namespace string
// EngineYard provides access to the known template engines.
EngineYard EngineYard
// Releases stores records of releases.
......@@ -215,7 +210,6 @@ func New() *Environment {
GoTplEngine: e,
}
return &Environment{
Namespace: DefaultNamespace,
EngineYard: ey,
Releases: storage.NewMemory(),
KubeClient: kube.New(nil), //&PrintingKubeClient{Out: os.Stdout},
......
......@@ -44,7 +44,6 @@ func init() {
srv = &releaseServer{
env: env,
}
srv.env.Namespace = namespace
services.RegisterReleaseServiceServer(rootServer, srv)
}
......@@ -236,7 +235,7 @@ func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
}
ts := timeconv.Now()
options := chartutil.ReleaseOptions{Name: name, Time: ts, Namespace: s.env.Namespace}
options := chartutil.ReleaseOptions{Name: name, Time: ts, Namespace: req.Namespace}
valuesToRender, err := chartutil.ToRenderValues(req.Chart, req.Values, options)
if err != nil {
return nil, err
......@@ -267,9 +266,10 @@ func (s *releaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
// Store a release.
rel := &release.Release{
Name: name,
Chart: req.Chart,
Config: req.Values,
Name: name,
Namespace: req.Namespace,
Chart: req.Chart,
Config: req.Values,
Info: &release.Info{
FirstDeployed: ts,
LastDeployed: ts,
......@@ -293,7 +293,7 @@ func (s *releaseServer) performRelease(r *release.Release, req *services.Install
// pre-install hooks
if !req.DisableHooks {
if err := s.execHook(r.Hooks, r.Name, preInstall); err != nil {
if err := s.execHook(r.Hooks, r.Name, r.Namespace, preInstall); err != nil {
return res, err
}
}
......@@ -301,7 +301,7 @@ func (s *releaseServer) performRelease(r *release.Release, req *services.Install
// regular manifests
kubeCli := s.env.KubeClient
b := bytes.NewBufferString(r.Manifest)
if err := kubeCli.Create(s.env.Namespace, b); err != nil {
if err := kubeCli.Create(r.Namespace, b); err != nil {
r.Info.Status.Code = release.Status_FAILED
log.Printf("warning: Release %q failed: %s", r.Name, err)
if err := s.env.Releases.Create(r); err != nil {
......@@ -312,7 +312,7 @@ func (s *releaseServer) performRelease(r *release.Release, req *services.Install
// post-install hooks
if !req.DisableHooks {
if err := s.execHook(r.Hooks, r.Name, postInstall); err != nil {
if err := s.execHook(r.Hooks, r.Name, r.Namespace, postInstall); err != nil {
return res, err
}
}
......@@ -331,7 +331,7 @@ func (s *releaseServer) performRelease(r *release.Release, req *services.Install
return res, nil
}
func (s *releaseServer) execHook(hs []*release.Hook, name, hook string) error {
func (s *releaseServer) execHook(hs []*release.Hook, name, namespace, hook string) error {
kubeCli := s.env.KubeClient
code, ok := events[hook]
if !ok {
......@@ -352,14 +352,14 @@ func (s *releaseServer) execHook(hs []*release.Hook, name, hook string) error {
}
b := bytes.NewBufferString(h.Manifest)
if err := kubeCli.Create(s.env.Namespace, b); err != nil {
if err := kubeCli.Create(namespace, b); err != nil {
log.Printf("wrning: Release %q pre-install %s failed: %s", name, h.Path, err)
return err
}
// No way to rewind a bytes.Buffer()?
b.Reset()
b.WriteString(h.Manifest)
if err := kubeCli.WatchUntilReady(s.env.Namespace, b); err != nil {
if err := kubeCli.WatchUntilReady(namespace, b); err != nil {
log.Printf("warning: Release %q pre-install %s could not complete: %s", name, h.Path, err)
return err
}
......@@ -387,19 +387,19 @@ func (s *releaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
res := &services.UninstallReleaseResponse{Release: rel}
if !req.DisableHooks {
if err := s.execHook(rel.Hooks, rel.Name, preDelete); err != nil {
if err := s.execHook(rel.Hooks, rel.Name, rel.Namespace, preDelete); err != nil {
return res, err
}
}
b := bytes.NewBuffer([]byte(rel.Manifest))
if err := s.env.KubeClient.Delete(s.env.Namespace, b); err != nil {
if err := s.env.KubeClient.Delete(rel.Namespace, b); err != nil {
log.Printf("uninstall: Failed deletion of %q: %s", req.Name, err)
return nil, err
}
if !req.DisableHooks {
if err := s.execHook(rel.Hooks, rel.Name, postDelete); err != nil {
if err := s.execHook(rel.Hooks, rel.Name, rel.Namespace, postDelete); err != nil {
return res, err
}
}
......
......@@ -101,7 +101,14 @@ func TestInstallRelease(t *testing.T) {
// TODO: Refactor this into a mock.
req := &services.InstallReleaseRequest{
Chart: chartStub(),
Namespace: "spaced",
Chart: &chart.Chart{
Metadata: &chart.Metadata{Name: "hello"},
Templates: []*chart.Template{
{Name: "hello", Data: []byte("hello: world")},
{Name: "hooks", Data: []byte(manifestWithHook)},
},
},
}
res, err := rs.InstallRelease(c, req)
if err != nil {
......@@ -110,6 +117,9 @@ func TestInstallRelease(t *testing.T) {
if res.Release.Name == "" {
t.Errorf("Expected release name.")
}
if res.Release.Namespace != "spaced" {
t.Errorf("Expected release namespace 'spaced', got '%s'.", res.Release.Namespace)
}
rel, err := rs.env.Releases.Read(res.Release.Name)
if err != nil {
......
......@@ -40,7 +40,6 @@ var env = environment.New()
var addr = ":44134"
var probe = ":44135"
var namespace = ""
const globalUsage = `The Kubernetes Helm server.
......@@ -59,12 +58,10 @@ var rootCommand = &cobra.Command{
func main() {
pf := rootCommand.PersistentFlags()
pf.StringVarP(&addr, "listen", "l", ":44134", "The address:port to listen on")
pf.StringVarP(&namespace, "namespace", "n", "", "The namespace Tiller calls home")
rootCommand.Execute()
}
func start(c *cobra.Command, args []string) {
setNamespace()
lstn, err := net.Listen("tcp", addr)
if err != nil {
fmt.Fprintf(os.Stderr, "Server died: %s\n", err)
......@@ -97,20 +94,3 @@ func start(c *cobra.Command, args []string) {
fmt.Fprintf(os.Stderr, "Probes server died: %s\n", err)
}
}
// setNamespace sets the namespace.
//
// It checks for the --namespace flag first, then checks the environment
// (set by Downward API), then goes to default.
func setNamespace() {
if len(namespace) != 0 {
fmt.Printf("Setting namespace to %q\n", namespace)
srv.env.Namespace = namespace
} else if ns := os.Getenv("DEFAULT_NAMESPACE"); len(ns) != 0 {
fmt.Printf("Inhereting namespace %q from Downward API\n", ns)
srv.env.Namespace = ns
} else {
fmt.Printf("Using default namespace %q\n", environment.DefaultNamespace)
srv.env.Namespace = environment.DefaultNamespace
}
}
......@@ -86,12 +86,7 @@ spec:
name: tiller
spec:
containers:
- env:
- name: DEFAULT_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: {{default "gcr.io/kubernetes-helm/tiller:canary" .Image}}
- image: {{default "gcr.io/kubernetes-helm/tiller:canary" .Image}}
name: tiller
ports:
- containerPort: 44134
......
......@@ -73,7 +73,7 @@ func (h *Client) ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesRespo
}
// InstallRelease installs a new chart and returns the release response.
func (h *Client) InstallRelease(chStr string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
func (h *Client) InstallRelease(chStr, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
if err != nil {
return nil, err
......@@ -85,7 +85,7 @@ func (h *Client) InstallRelease(chStr string, opts ...InstallOption) (*rls.Insta
return nil, err
}
return h.opts.rpcInstallRelease(chart, rls.NewReleaseServiceClient(c), opts...)
return h.opts.rpcInstallRelease(chart, rls.NewReleaseServiceClient(c), ns, opts...)
}
// DeleteRelease uninstalls a named release and returns the response.
......
......@@ -23,7 +23,7 @@ import (
// Interface for helm client for mocking in tests
type Interface interface {
ListReleases(opts ...ReleaseListOption) (*rls.ListReleasesResponse, error)
InstallRelease(chStr string, opts ...InstallOption) (*rls.InstallReleaseResponse, error)
InstallRelease(chStr, namespace string, opts ...InstallOption) (*rls.InstallReleaseResponse, error)
DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error)
ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error)
UpdateRelease(rlsName string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error)
......
......@@ -179,12 +179,13 @@ func (o *options) rpcListReleases(rlc rls.ReleaseServiceClient, opts ...ReleaseL
}
// Executes tiller.InstallRelease RPC.
func (o *options) rpcInstallRelease(chr *cpb.Chart, rlc rls.ReleaseServiceClient, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
func (o *options) rpcInstallRelease(chr *cpb.Chart, rlc rls.ReleaseServiceClient, ns string, opts ...InstallOption) (*rls.InstallReleaseResponse, error) {
// apply the install options
for _, opt := range opts {
opt(o)
}
o.instReq.Chart = chr
o.instReq.Namespace = ns
o.instReq.DryRun = o.dryRun
o.instReq.DisableHooks = o.disableHooks
......
......@@ -33,6 +33,8 @@ type Release struct {
Hooks []*Hook `protobuf:"bytes,6,rep,name=hooks" json:"hooks,omitempty"`
// Version is an int32 which represents the version of the release.
Version int32 `protobuf:"varint,7,opt,name=version" json:"version,omitempty"`
// Namespace is the kubernetes namespace of the release.
Namespace string `protobuf:"bytes,8,opt,name=namespace" json:"namespace,omitempty"`
}
func (m *Release) Reset() { *m = Release{} }
......@@ -73,20 +75,21 @@ func init() {
}
var fileDescriptor2 = []byte{
// 239 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x64, 0x90, 0x3f, 0x4f, 0x03, 0x31,
0x0c, 0xc5, 0x75, 0xf4, 0xfe, 0x50, 0xc3, 0x82, 0x07, 0xb0, 0x6e, 0xaa, 0x18, 0xa0, 0x62, 0x48,
0x25, 0xf8, 0x06, 0xb0, 0xc0, 0x9a, 0x91, 0x2d, 0x54, 0x39, 0x2e, 0x82, 0x26, 0x55, 0x72, 0xe2,
0xc3, 0x33, 0x91, 0xc4, 0x29, 0xba, 0xc2, 0xe2, 0xc4, 0xfe, 0xbd, 0xbc, 0x3c, 0x19, 0xfa, 0x51,
0xed, 0xcd, 0xc6, 0xeb, 0x4f, 0xad, 0x82, 0x3e, 0x9c, 0x62, 0xef, 0xdd, 0xe4, 0xf0, 0x3c, 0x31,
0x51, 0x66, 0xfd, 0xd5, 0x91, 0x72, 0x74, 0xee, 0x83, 0x65, 0x7f, 0x80, 0xb1, 0x83, 0x3b, 0x02,
0xdb, 0x51, 0xf9, 0x69, 0xb3, 0x75, 0x76, 0x30, 0xef, 0x05, 0x5c, 0xce, 0x41, 0xaa, 0x3c, 0xbf,
0xfe, 0xae, 0xa0, 0x93, 0xec, 0x83, 0x08, 0xb5, 0x55, 0x3b, 0x4d, 0xd5, 0xaa, 0x5a, 0x2f, 0x65,
0xbe, 0xe3, 0x0d, 0xd4, 0xc9, 0x9e, 0x4e, 0xe2, 0xec, 0xec, 0x1e, 0xc5, 0x3c, 0x9f, 0x78, 0x89,
0x44, 0x66, 0x8e, 0xb7, 0xd0, 0x64, 0x5b, 0x5a, 0x64, 0xe1, 0x05, 0x0b, 0xf9, 0xa7, 0xa7, 0x54,
0x25, 0x73, 0xbc, 0x83, 0x96, 0x83, 0x51, 0x3d, 0xb7, 0x2c, 0xca, 0x4c, 0x64, 0x51, 0x60, 0x0f,
0xa7, 0x3b, 0x65, 0xcd, 0xa0, 0xc3, 0x44, 0x4d, 0x0e, 0xf5, 0xdb, 0xe3, 0x1a, 0x9a, 0xb4, 0x90,
0x40, 0xed, 0x6a, 0xf1, 0x3f, 0xd9, 0x73, 0x44, 0x92, 0x05, 0x48, 0xd0, 0x7d, 0x69, 0x1f, 0x8c,
0xb3, 0xd4, 0x45, 0x93, 0x46, 0x1e, 0xda, 0xc7, 0xe5, 0x6b, 0x57, 0x1e, 0xbc, 0xb5, 0x79, 0x1d,
0x0f, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x49, 0x8d, 0x14, 0x1a, 0x9d, 0x01, 0x00, 0x00,
// 254 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x64, 0x90, 0x3f, 0x4f, 0xc3, 0x30,
0x10, 0xc5, 0xd5, 0x36, 0x7f, 0x9a, 0x83, 0x85, 0x1b, 0xe0, 0x14, 0x31, 0x54, 0x0c, 0x50, 0x31,
0xa4, 0x12, 0x7c, 0x03, 0x58, 0x60, 0xf5, 0xc8, 0x66, 0x22, 0x87, 0x58, 0x50, 0x3b, 0x8a, 0x23,
0x3e, 0x0b, 0x1f, 0x17, 0xdb, 0xe7, 0x42, 0x0a, 0x8b, 0x13, 0xbf, 0xdf, 0xd3, 0xbb, 0xe7, 0x83,
0xba, 0x97, 0x83, 0xde, 0x8d, 0xea, 0x43, 0x49, 0xa7, 0x0e, 0xdf, 0x66, 0x18, 0xed, 0x64, 0xf1,
0x34, 0xb0, 0x26, 0x69, 0xf5, 0xc5, 0x91, 0xb3, 0xb7, 0xf6, 0x9d, 0x6d, 0x7f, 0x80, 0x36, 0x9d,
0x3d, 0x02, 0x6d, 0x2f, 0xc7, 0x69, 0xd7, 0x5a, 0xd3, 0xe9, 0xb7, 0x04, 0xce, 0xe7, 0x20, 0x9c,
0xac, 0x5f, 0x7d, 0x2d, 0xa1, 0x14, 0x9c, 0x83, 0x08, 0x99, 0x91, 0x7b, 0x45, 0x8b, 0xcd, 0x62,
0x5b, 0x89, 0xf8, 0x8f, 0xd7, 0x90, 0x85, 0x78, 0x5a, 0x7a, 0xed, 0xe4, 0x0e, 0x9b, 0x79, 0xbf,
0xe6, 0xd9, 0x13, 0x11, 0x39, 0xde, 0x40, 0x1e, 0x63, 0x69, 0x15, 0x8d, 0x67, 0x6c, 0xe4, 0x49,
0x8f, 0xe1, 0x14, 0xcc, 0xf1, 0x16, 0x0a, 0x2e, 0x46, 0xd9, 0x3c, 0x32, 0x39, 0x23, 0x11, 0xc9,
0x81, 0x35, 0xac, 0xf7, 0xd2, 0xe8, 0x4e, 0xb9, 0x89, 0xf2, 0x58, 0xea, 0xe7, 0x8e, 0x5b, 0xc8,
0xc3, 0x42, 0x1c, 0x15, 0x9b, 0xd5, 0xff, 0x66, 0x4f, 0x1e, 0x09, 0x36, 0x20, 0x41, 0xf9, 0xa9,
0x46, 0xa7, 0xad, 0xa1, 0xd2, 0x87, 0xe4, 0xe2, 0x70, 0xc5, 0x4b, 0xa8, 0xc2, 0x23, 0xdd, 0x20,
0x5b, 0x45, 0xeb, 0x38, 0xe0, 0x57, 0x78, 0xa8, 0x5e, 0xca, 0x14, 0xf7, 0x5a, 0xc4, 0x65, 0xdd,
0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0xc8, 0x8f, 0xec, 0x97, 0xbb, 0x01, 0x00, 0x00,
}
......@@ -250,6 +250,8 @@ type InstallReleaseRequest struct {
Name string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"`
// DisableHooks causes the server to skip running any hooks for the install.
DisableHooks bool `protobuf:"varint,5,opt,name=disable_hooks,json=disableHooks" json:"disable_hooks,omitempty"`
// Namepace is the kubernetes namespace of the release.
Namespace string `protobuf:"bytes,6,opt,name=namespace" json:"namespace,omitempty"`
}
func (m *InstallReleaseRequest) Reset() { *m = InstallReleaseRequest{} }
......@@ -590,50 +592,51 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{
}
var fileDescriptor0 = []byte{
// 720 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x55, 0xdd, 0x6e, 0xd3, 0x4a,
0x10, 0xae, 0x9b, 0x34, 0x49, 0xa7, 0x3f, 0x4a, 0xf7, 0xa4, 0x49, 0x8e, 0x2f, 0x8e, 0x8e, 0x8c,
0x80, 0x52, 0xa8, 0x03, 0xe1, 0x1e, 0x29, 0x6d, 0xa3, 0x52, 0x35, 0xa4, 0xd2, 0x86, 0x82, 0xc4,
0x05, 0x91, 0xdb, 0x6c, 0xa8, 0xc1, 0xf5, 0x06, 0xef, 0xa6, 0xa2, 0x8f, 0xc0, 0x1b, 0x71, 0xc5,
0xd3, 0xf0, 0x20, 0xec, 0x8f, 0xd7, 0x8a, 0x13, 0x1b, 0xa2, 0xde, 0x38, 0xbb, 0x3b, 0xdf, 0xce,
0x37, 0xfe, 0x66, 0x3e, 0x07, 0xec, 0x6b, 0x6f, 0xe2, 0xb7, 0x18, 0x89, 0x6e, 0xfd, 0x2b, 0xc2,
0x5a, 0xdc, 0x0f, 0x02, 0x12, 0xb9, 0x93, 0x88, 0x72, 0x8a, 0x6a, 0x32, 0xe6, 0x9a, 0x98, 0xab,
0x63, 0x76, 0x5d, 0xdd, 0xb8, 0xba, 0xf6, 0x22, 0xae, 0x9f, 0x1a, 0x6d, 0x37, 0x66, 0xcf, 0x69,
0x38, 0xf6, 0x3f, 0xc5, 0x01, 0x4d, 0x11, 0x91, 0x80, 0x78, 0x8c, 0x98, 0xdf, 0xd4, 0x25, 0x13,
0xf3, 0xc3, 0x31, 0xd5, 0x01, 0xe7, 0x97, 0x05, 0xff, 0xf4, 0x7c, 0xc6, 0xb1, 0x0e, 0x31, 0x4c,
0xbe, 0x4e, 0x09, 0xe3, 0xa8, 0x06, 0x6b, 0x81, 0x7f, 0xe3, 0xf3, 0xa6, 0xf5, 0xbf, 0xb5, 0x57,
0xc0, 0x7a, 0x83, 0xea, 0x50, 0xa2, 0xe3, 0x31, 0x23, 0xbc, 0xb9, 0x2a, 0x8e, 0xd7, 0x71, 0xbc,
0x43, 0xaf, 0xa0, 0xcc, 0x68, 0xc4, 0x87, 0x97, 0x77, 0xcd, 0x82, 0x08, 0x6c, 0xb7, 0x1f, 0xba,
0x59, 0xef, 0xe4, 0x4a, 0xa6, 0x81, 0x00, 0xba, 0xf2, 0x71, 0x78, 0x87, 0x4b, 0x4c, 0xfd, 0xca,
0xbc, 0x63, 0x3f, 0xe0, 0x24, 0x6a, 0x16, 0x75, 0x5e, 0xbd, 0x43, 0x27, 0x00, 0x2a, 0x2f, 0x8d,
0x46, 0x22, 0xb6, 0xa6, 0x52, 0xef, 0x2d, 0x91, 0xfa, 0x5c, 0xe2, 0xf1, 0x3a, 0x33, 0x4b, 0xe7,
0x23, 0x54, 0x0c, 0xc0, 0x69, 0x43, 0x49, 0xd3, 0xa3, 0x0d, 0x28, 0x5f, 0xf4, 0xcf, 0xfa, 0xe7,
0xef, 0xfb, 0xd5, 0x15, 0x54, 0x81, 0x62, 0xbf, 0xf3, 0xa6, 0x5b, 0xb5, 0xd0, 0x0e, 0x6c, 0xf5,
0x3a, 0x83, 0xb7, 0x43, 0xdc, 0xed, 0x75, 0x3b, 0x83, 0xee, 0x71, 0x75, 0xd5, 0xf9, 0x0f, 0xd6,
0x93, 0xbc, 0xa8, 0x0c, 0x85, 0xce, 0xe0, 0x48, 0x5f, 0x39, 0xee, 0x8a, 0x95, 0xe5, 0x7c, 0xb7,
0xa0, 0x96, 0x96, 0x91, 0x4d, 0x68, 0xc8, 0x88, 0xd4, 0xf1, 0x8a, 0x4e, 0xc3, 0x44, 0x47, 0xb5,
0x41, 0x08, 0x8a, 0x21, 0xf9, 0x66, 0x54, 0x54, 0x6b, 0x89, 0xe4, 0x94, 0x7b, 0x81, 0x52, 0x50,
0x20, 0xd5, 0x06, 0xbd, 0x80, 0x4a, 0xdc, 0x35, 0x26, 0xb4, 0x29, 0xec, 0x6d, 0xb4, 0x77, 0xf5,
0xfb, 0x9b, 0xfe, 0xc6, 0x8c, 0x38, 0x81, 0x39, 0x07, 0xd0, 0x38, 0x21, 0xa6, 0x92, 0x01, 0xf7,
0xf8, 0x34, 0xe9, 0xaa, 0xe4, 0xf5, 0x6e, 0x88, 0x2a, 0x46, 0xf2, 0x8a, 0xb5, 0xf3, 0x0e, 0x9a,
0x8b, 0xf0, 0xb8, 0xfa, 0x0c, 0x3c, 0x7a, 0x04, 0x45, 0x39, 0x3f, 0xaa, 0xf6, 0x8d, 0x36, 0x4a,
0x57, 0x73, 0x2a, 0x22, 0x58, 0xc5, 0x1d, 0x77, 0x36, 0xef, 0x11, 0x0d, 0x39, 0x09, 0xf9, 0x9f,
0xea, 0xe8, 0xc1, 0xbf, 0x19, 0xf8, 0xb8, 0x90, 0x16, 0x94, 0x63, 0x0a, 0x75, 0x27, 0x57, 0x05,
0x83, 0x72, 0xea, 0x50, 0xbb, 0x98, 0x8c, 0x3c, 0x4e, 0x4c, 0x44, 0x33, 0x3b, 0x0d, 0xd8, 0x9d,
0x3b, 0xd7, 0x0c, 0xce, 0x4f, 0x0b, 0x76, 0x4f, 0x43, 0x26, 0x34, 0x0f, 0xd2, 0x57, 0xd0, 0x63,
0xd1, 0x42, 0xe9, 0xb6, 0x98, 0x79, 0x47, 0x33, 0x6b, 0x4b, 0x1e, 0xc9, 0x27, 0xd6, 0x71, 0xb4,
0x0f, 0xa5, 0x5b, 0x2f, 0x10, 0x77, 0xd2, 0xda, 0xc4, 0x48, 0x65, 0x55, 0x1c, 0x23, 0x50, 0x03,
0xca, 0xa3, 0xe8, 0x6e, 0x18, 0x4d, 0x43, 0xd5, 0xef, 0x0a, 0x2e, 0x89, 0x2d, 0x9e, 0x86, 0x89,
0x34, 0xc5, 0x19, 0xc9, 0x1f, 0xc0, 0xd6, 0xc8, 0x67, 0xde, 0x65, 0x40, 0x86, 0xd7, 0x94, 0x7e,
0x61, 0xca, 0x09, 0x15, 0xbc, 0x19, 0x1f, 0xbe, 0x96, 0x67, 0xce, 0x29, 0xd4, 0xe7, 0xeb, 0xbf,
0xaf, 0x78, 0x18, 0x1a, 0x17, 0xa1, 0x9f, 0x29, 0x46, 0xd6, 0x44, 0x2c, 0x94, 0xb7, 0x9a, 0x51,
0xde, 0x19, 0x34, 0x17, 0x73, 0xde, 0xb3, 0xc0, 0xf6, 0x8f, 0x35, 0xd8, 0x36, 0x13, 0xab, 0xbf,
0x03, 0xc8, 0x87, 0xcd, 0x59, 0x03, 0xa2, 0x27, 0xf9, 0x9f, 0x89, 0xb9, 0x6f, 0x9d, 0xbd, 0xbf,
0x0c, 0x34, 0x1e, 0x93, 0x95, 0xe7, 0x16, 0x62, 0x50, 0x9d, 0x77, 0x0c, 0x3a, 0xc8, 0xce, 0x91,
0x63, 0x44, 0xdb, 0x5d, 0x16, 0x6e, 0x68, 0xd1, 0x2d, 0xec, 0x2c, 0xd8, 0x03, 0xfd, 0x35, 0x4d,
0xda, 0x77, 0x76, 0x6b, 0x69, 0x7c, 0xc2, 0xfb, 0x19, 0xb6, 0x52, 0x86, 0x41, 0x39, 0x6a, 0x65,
0xb9, 0xcd, 0x7e, 0xba, 0x14, 0x36, 0xe1, 0xba, 0x81, 0xed, 0xf4, 0x08, 0xa3, 0x9c, 0x04, 0x99,
0x46, 0xb5, 0x9f, 0x2d, 0x07, 0x4e, 0xe8, 0x44, 0x1f, 0xe7, 0x47, 0x32, 0xaf, 0x8f, 0x39, 0x76,
0xc8, 0xeb, 0x63, 0xde, 0xa4, 0x3b, 0x2b, 0x87, 0xf0, 0xa1, 0x62, 0xd0, 0x97, 0x25, 0xf5, 0x1f,
0xfc, 0xf2, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x38, 0x16, 0x87, 0x5f, 0x1d, 0x08, 0x00, 0x00,
// 732 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x55, 0xdb, 0x6e, 0xd3, 0x40,
0x10, 0xad, 0x9b, 0x34, 0x97, 0xe9, 0x45, 0xe9, 0x92, 0x26, 0xc1, 0x42, 0x08, 0x2d, 0x02, 0x4a,
0xa1, 0x0e, 0x84, 0x77, 0xa4, 0xb4, 0x8d, 0x4a, 0xd5, 0x90, 0x4a, 0x1b, 0x0a, 0x12, 0x0f, 0x44,
0x6e, 0xb2, 0xa1, 0x06, 0xd7, 0x0e, 0xde, 0x4d, 0x45, 0x3f, 0x81, 0x3f, 0xe2, 0x63, 0x78, 0xe4,
0x43, 0xd8, 0x8b, 0x6d, 0xe2, 0xc4, 0x86, 0xa8, 0x2f, 0xce, 0xee, 0xce, 0xd9, 0x39, 0xe3, 0x33,
0x73, 0x1c, 0x30, 0x2f, 0xed, 0x89, 0xd3, 0x64, 0x34, 0xb8, 0x76, 0x86, 0x94, 0x35, 0xb9, 0xe3,
0xba, 0x34, 0xb0, 0x26, 0x81, 0xcf, 0x7d, 0x54, 0x95, 0x31, 0x2b, 0x8a, 0x59, 0x3a, 0x66, 0xd6,
0xd4, 0x8d, 0xe1, 0xa5, 0x1d, 0x70, 0xfd, 0xd4, 0x68, 0xb3, 0x3e, 0x7b, 0xee, 0x7b, 0x63, 0xe7,
0x73, 0x18, 0xd0, 0x14, 0x01, 0x75, 0xa9, 0xcd, 0x68, 0xf4, 0x9b, 0xb8, 0x14, 0xc5, 0x1c, 0x6f,
0xec, 0xeb, 0x00, 0xfe, 0x6d, 0xc0, 0x9d, 0xae, 0xc3, 0x38, 0xd1, 0x21, 0x46, 0xe8, 0xb7, 0x29,
0x65, 0x1c, 0x55, 0x61, 0xcd, 0x75, 0xae, 0x1c, 0xde, 0x30, 0x1e, 0x18, 0xbb, 0x39, 0xa2, 0x37,
0xa8, 0x06, 0x05, 0x7f, 0x3c, 0x66, 0x94, 0x37, 0x56, 0xc5, 0x71, 0x99, 0x84, 0x3b, 0xf4, 0x1a,
0x8a, 0xcc, 0x0f, 0xf8, 0xe0, 0xe2, 0xa6, 0x91, 0x13, 0x81, 0xad, 0xd6, 0x23, 0x2b, 0xed, 0x9d,
0x2c, 0xc9, 0xd4, 0x17, 0x40, 0x4b, 0x3e, 0x0e, 0x6e, 0x48, 0x81, 0xa9, 0x5f, 0x99, 0x77, 0xec,
0xb8, 0x9c, 0x06, 0x8d, 0xbc, 0xce, 0xab, 0x77, 0xe8, 0x18, 0x40, 0xe5, 0xf5, 0x83, 0x91, 0x88,
0xad, 0xa9, 0xd4, 0xbb, 0x4b, 0xa4, 0x3e, 0x93, 0x78, 0x52, 0x66, 0xd1, 0x12, 0x7f, 0x82, 0x52,
0x04, 0xc0, 0x2d, 0x28, 0x68, 0x7a, 0xb4, 0x0e, 0xc5, 0xf3, 0xde, 0x69, 0xef, 0xec, 0x43, 0xaf,
0xb2, 0x82, 0x4a, 0x90, 0xef, 0xb5, 0xdf, 0x76, 0x2a, 0x06, 0xda, 0x86, 0xcd, 0x6e, 0xbb, 0xff,
0x6e, 0x40, 0x3a, 0xdd, 0x4e, 0xbb, 0xdf, 0x39, 0xaa, 0xac, 0xe2, 0xfb, 0x50, 0x8e, 0xf3, 0xa2,
0x22, 0xe4, 0xda, 0xfd, 0x43, 0x7d, 0xe5, 0xa8, 0x23, 0x56, 0x06, 0xfe, 0x61, 0x40, 0x35, 0x29,
0x23, 0x9b, 0xf8, 0x1e, 0xa3, 0x52, 0xc7, 0xa1, 0x3f, 0xf5, 0x62, 0x1d, 0xd5, 0x06, 0x21, 0xc8,
0x7b, 0xf4, 0x7b, 0xa4, 0xa2, 0x5a, 0x4b, 0x24, 0xf7, 0xb9, 0xed, 0x2a, 0x05, 0x05, 0x52, 0x6d,
0xd0, 0x4b, 0x28, 0x85, 0x5d, 0x63, 0x42, 0x9b, 0xdc, 0xee, 0x7a, 0x6b, 0x47, 0xbf, 0x7f, 0xd4,
0xdf, 0x90, 0x91, 0xc4, 0x30, 0xbc, 0x0f, 0xf5, 0x63, 0x1a, 0x55, 0xd2, 0xe7, 0x36, 0x9f, 0xc6,
0x5d, 0x95, 0xbc, 0xf6, 0x15, 0x55, 0xc5, 0x48, 0x5e, 0xb1, 0xc6, 0xef, 0xa1, 0xb1, 0x08, 0x0f,
0xab, 0x4f, 0xc1, 0xa3, 0xc7, 0x90, 0x97, 0xf3, 0xa3, 0x6a, 0x5f, 0x6f, 0xa1, 0x64, 0x35, 0x27,
0x22, 0x42, 0x54, 0x1c, 0x5b, 0xb3, 0x79, 0x0f, 0x7d, 0x8f, 0x53, 0x8f, 0xff, 0xab, 0x8e, 0x2e,
0xdc, 0x4d, 0xc1, 0x87, 0x85, 0x34, 0xa1, 0x18, 0x52, 0xa8, 0x3b, 0x99, 0x2a, 0x44, 0x28, 0x5c,
0x83, 0xea, 0xf9, 0x64, 0x64, 0x73, 0x1a, 0x45, 0x34, 0x33, 0xae, 0xc3, 0xce, 0xdc, 0xb9, 0x66,
0xc0, 0xbf, 0x0c, 0xd8, 0x39, 0xf1, 0x98, 0xd0, 0xdc, 0x4d, 0x5e, 0x41, 0x4f, 0x44, 0x0b, 0xa5,
0xdb, 0x42, 0xe6, 0x6d, 0xcd, 0xac, 0x2d, 0x79, 0x28, 0x9f, 0x44, 0xc7, 0xd1, 0x1e, 0x14, 0xae,
0x6d, 0x57, 0xdc, 0x49, 0x6a, 0x13, 0x22, 0x95, 0x55, 0x49, 0x88, 0x40, 0x75, 0x28, 0x8e, 0x82,
0x9b, 0x41, 0x30, 0xf5, 0x54, 0xbf, 0x4b, 0xa4, 0x20, 0xb6, 0x64, 0xea, 0xc5, 0xd2, 0xe4, 0x67,
0x24, 0x7f, 0x08, 0x9b, 0x23, 0x87, 0xd9, 0x17, 0x2e, 0x1d, 0x5c, 0xfa, 0xfe, 0x57, 0xa6, 0x9c,
0x50, 0x22, 0x1b, 0xe1, 0xe1, 0x1b, 0x79, 0x86, 0xee, 0x41, 0x59, 0x82, 0xd9, 0xc4, 0x1e, 0xd2,
0x46, 0x41, 0xdd, 0xfe, 0x7b, 0x80, 0x4f, 0xa0, 0x36, 0xff, 0x76, 0xb7, 0x95, 0x96, 0x40, 0xfd,
0xdc, 0x73, 0x52, 0xa5, 0x4a, 0x9b, 0x97, 0x85, 0xe2, 0x57, 0x17, 0x8b, 0xc7, 0xa7, 0xd0, 0x58,
0xcc, 0x79, 0xcb, 0x02, 0x5b, 0x3f, 0xd7, 0x60, 0x2b, 0x9a, 0x67, 0xfd, 0x95, 0x40, 0x0e, 0x6c,
0xcc, 0xda, 0x13, 0x3d, 0xcd, 0xfe, 0x88, 0xcc, 0x7d, 0x09, 0xcd, 0xbd, 0x65, 0xa0, 0xe1, 0x10,
0xad, 0xbc, 0x30, 0x10, 0x83, 0xca, 0xbc, 0x9f, 0xd0, 0x7e, 0x7a, 0x8e, 0x0c, 0x9b, 0x9a, 0xd6,
0xb2, 0xf0, 0x88, 0x16, 0x5d, 0xc3, 0xf6, 0x82, 0x79, 0xd0, 0x7f, 0xd3, 0x24, 0x5d, 0x69, 0x36,
0x97, 0xc6, 0xc7, 0xbc, 0x5f, 0x60, 0x33, 0x61, 0x27, 0x94, 0xa1, 0x56, 0x9a, 0x17, 0xcd, 0x67,
0x4b, 0x61, 0x63, 0xae, 0x2b, 0xd8, 0x4a, 0x8e, 0x30, 0xca, 0x48, 0x90, 0x6a, 0x63, 0xf3, 0xf9,
0x72, 0xe0, 0x98, 0x4e, 0xf4, 0x71, 0x7e, 0x24, 0xb3, 0xfa, 0x98, 0x61, 0x87, 0xac, 0x3e, 0x66,
0x4d, 0x3a, 0x5e, 0x39, 0x80, 0x8f, 0xa5, 0x08, 0x7d, 0x51, 0x50, 0xff, 0xd0, 0xaf, 0xfe, 0x04,
0x00, 0x00, 0xff, 0xff, 0x90, 0x99, 0xf0, 0xc6, 0x3b, 0x08, 0x00, 0x00,
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment