├── .gitignore ├── main.go ├── glide.yaml ├── LICENSE ├── rubykube ├── resources_serviceClass.go ├── resources_daemonSetClass.go ├── resources_replicaSetClass.go ├── resources_servicesClass.go ├── resources_daemonSetsClass.go ├── gotemplate_podSingletonModule.go ├── resources_deploymentsClass.go ├── resources_replicaSetsClass.go ├── gotemplate_serviceSingletonModule.go ├── gotemplate_daemonSetSingletonModule.go ├── gotemplate_deploymentSingletonModule.go ├── gotemplate_replicaSetSingletonModule.go ├── templates │ ├── resource │ │ ├── podfinder │ │ │ └── template.go │ │ ├── singleton │ │ │ └── template.go │ │ ├── template.go │ │ └── list │ │ │ └── template.go │ └── basic │ │ └── template.go ├── gotemplate_servicePodFinderModule.go ├── gotemplate_daemonSetPodFinderModule.go ├── gotemplate_deploymentPodFinderModule.go ├── gotemplate_replicaSetPodFinderModule.go ├── helpers_fieldSelectorClass.go ├── patches.go ├── helpers_labelSelectorClass.go ├── gotemplate_podLogsClass.go ├── resources_podsClass.go ├── gotemplate_fieldKeyClass.go ├── gotemplate_labelKeyClass.go ├── gotemplate_podMakerClass.go ├── gotemplate_fieldSelectorClass.go ├── gotemplate_labelSelectorClass.go ├── gotemplate_fieldCollectorClass.go ├── gotemplate_labelCollectorClass.go ├── resources_deploymentClass.go ├── gotemplate_podClass.go ├── gotemplate_podsClass.go ├── resources_podClass.go ├── gotemplate_serviceClass.go ├── gotemplate_servicesClass.go ├── gotemplate_daemonSetClass.go ├── gotemplate_deploymentClass.go ├── gotemplate_replicaSetClass.go ├── gotemplate_daemonSetsClass.go ├── gotemplate_deploymentsClass.go ├── gotemplate_replicaSetsClass.go ├── funcs.go ├── helpers_fieldCollectorClass.go ├── helpers_labelCollectorClass.go ├── helpers_labelKeyClass.go ├── helpers_fieldKeyClass.go ├── helpers_podMakerClass.go ├── helpers_podLogsClass.go ├── gotemplate_podsListModule.go ├── gotemplate_servicesListModule.go ├── gotemplate_daemonSetsListModule.go ├── gotemplate_deploymentsListModule.go ├── gotemplate_replicaSetsListModule.go ├── converter │ └── converter.go ├── verbs.go ├── util.go └── rubykube.go ├── app.rb ├── repl └── repl.go ├── glide.lock └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.sw? 2 | kubeplay 3 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/errordeveloper/kubeplay/repl" 7 | ) 8 | 9 | func main() { 10 | repl, err := repl.NewRepl() 11 | if err != nil { 12 | panic(fmt.Errorf("repl.NewRepl: %v", err)) 13 | } 14 | err = repl.Loop() 15 | if err != nil { 16 | panic(fmt.Errorf("repl.Loop: %v", err)) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /glide.yaml: -------------------------------------------------------------------------------- 1 | package: github.com/errordeveloper/kubeplay 2 | import: 3 | - package: github.com/chzyer/readline 4 | version: ^1.4.0 5 | - package: github.com/mitchellh/go-mruby 6 | - package: "k8s.io/client-go" 7 | version: "v6.0.0" 8 | subpackages: 9 | - kubernetes 10 | - tools/clientcmd 11 | - package: "k8s.io/apimachinery" 12 | version: "180eddb345a5be3a157cea1c624700ad5bd27b8f" 13 | subpackages: 14 | - pkg/api/resource 15 | - pkg/apis/meta/v1 16 | - pkg/runtime 17 | - pkg/util/intstr 18 | - package: "k8s.io/kubernetes" 19 | version: "v1.9.2" 20 | subpackages: 21 | - pkg/printers 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016 Erik Hollensbe. All rights reserved. 2 | Copyright 2016 Ilya Dmitrichenko. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /rubykube/resources_serviceClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | mruby "github.com/mitchellh/go-mruby" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | corev1 "k8s.io/api/core/v1" 7 | ) 8 | 9 | type serviceTypeAlias = corev1.Service 10 | 11 | //go:generate gotemplate "./templates/resource" "serviceClass(\"Service\", service, serviceTypeAlias)" 12 | 13 | func (c *serviceClass) getSingleton(ns, name string) (*corev1.Service, error) { 14 | return c.rk.clientset.Core().Services(ns).Get(name, metav1.GetOptions{}) 15 | } 16 | 17 | //go:generate gotemplate "./templates/resource/singleton" "serviceSingletonModule(serviceClass, \"Service\", service, serviceTypeAlias)" 18 | 19 | //go:generate gotemplate "./templates/resource/podfinder" "servicePodFinderModule(serviceClass, \"Service\", service, serviceTypeAlias)" 20 | 21 | func (c *serviceClass) defineOwnMethods() { 22 | c.defineSingletonMethods() 23 | c.definePodFinderMethods() 24 | } 25 | 26 | func (o *serviceClassInstance) Update() (mruby.Value, error) { 27 | return call(o.self, "get!") 28 | } 29 | -------------------------------------------------------------------------------- /rubykube/resources_daemonSetClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | mruby "github.com/mitchellh/go-mruby" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | appsv1 "k8s.io/api/apps/v1" 7 | ) 8 | 9 | type daemonSetTypeAlias = appsv1.DaemonSet 10 | 11 | //go:generate gotemplate "./templates/resource" "daemonSetClass(\"DaemonSet\", daemonSet, daemonSetTypeAlias)" 12 | 13 | func (c *daemonSetClass) getSingleton(ns, name string) (*appsv1.DaemonSet, error) { 14 | return c.rk.clientset.Apps().DaemonSets(ns).Get(name, metav1.GetOptions{}) 15 | } 16 | 17 | //go:generate gotemplate "./templates/resource/singleton" "daemonSetSingletonModule(daemonSetClass, \"daemonSet\", daemonSet, daemonSetTypeAlias)" 18 | 19 | //go:generate gotemplate "./templates/resource/podfinder" "daemonSetPodFinderModule(daemonSetClass, \"daemonSet\", daemonSet, daemonSetTypeAlias)" 20 | 21 | func (c *daemonSetClass) defineOwnMethods() { 22 | c.defineSingletonMethods() 23 | c.definePodFinderMethods() 24 | } 25 | 26 | func (o *daemonSetClassInstance) Update() (mruby.Value, error) { 27 | return call(o.self, "get!") 28 | } 29 | -------------------------------------------------------------------------------- /rubykube/resources_replicaSetClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | mruby "github.com/mitchellh/go-mruby" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | appsv1 "k8s.io/api/apps/v1" 7 | ) 8 | 9 | type replicaSetTypeAlias appsv1.ReplicaSet 10 | 11 | //go:generate gotemplate "./templates/resource" "replicaSetClass(\"ReplicaSet\", replicaSet, replicaSetTypeAlias)" 12 | 13 | func (c *replicaSetClass) getSingleton(ns, name string) (*appsv1.ReplicaSet, error) { 14 | return c.rk.clientset.Apps().ReplicaSets(ns).Get(name, metav1.GetOptions{}) 15 | } 16 | 17 | //go:generate gotemplate "./templates/resource/singleton" "replicaSetSingletonModule(replicaSetClass, \"replicaSet\", replicaSet, replicaSetTypeAlias)" 18 | 19 | //go:generate gotemplate "./templates/resource/podfinder" "replicaSetPodFinderModule(replicaSetClass, \"replicaSet\", replicaSet, replicaSetTypeAlias)" 20 | 21 | func (c *replicaSetClass) defineOwnMethods() { 22 | c.defineSingletonMethods() 23 | c.definePodFinderMethods() 24 | } 25 | 26 | func (o *replicaSetClassInstance) Update() (mruby.Value, error) { 27 | return call(o.self, "get!") 28 | } 29 | -------------------------------------------------------------------------------- /app.rb: -------------------------------------------------------------------------------- 1 | App.new(service: false, image: "errordeveloper/foo:latest") 2 | App.new(image: "errordeveloper/foo:latest") 3 | 4 | # name label is set automaticaly, whenever possible 5 | # otherwise user can set it with `:name`, or set all labels, or even all of metadata 6 | 7 | Pod.new({ 8 | image: "errordeveloper/foo:latest", 9 | cmd: [ ] 10 | }, 11 | { 12 | image: "errordeveloper/foo:latest", 13 | cmd: [ ] 14 | }) 15 | 16 | c1 = Container.new(image: "errordeveloper/foo:latest") 17 | c2 = c1.clone 18 | c2.image = "errordeveloper/bar:latest" 19 | c.cmd = [ ] 20 | 21 | # container names are infered from image name, whenever possible, otherwise an exception is thrown 22 | # user can set a container name 23 | 24 | ... 25 | 26 | # declarative syntax with Kubefile 27 | 28 | image "errordeveloper/foo:latest" 29 | replicas "10" 30 | labels { 31 | myapp: "foo" 32 | } 33 | 34 | # those are all Ruby methods that can only be called once per Kubefile, they result in a replicaset/service pair (unless 35 | # specified otherwise) and generate data that is passed to Go implementation further validation (binding to Go may be 36 | # seen as a premature optimisation, but something to consider also) 37 | -------------------------------------------------------------------------------- /rubykube/resources_servicesClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | mruby "github.com/mitchellh/go-mruby" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | corev1 "k8s.io/api/core/v1" 7 | ) 8 | 9 | type serviceListTypeAlias = corev1.ServiceList 10 | 11 | //go:generate gotemplate "./templates/resource" "servicesClass(\"Services\", services, serviceListTypeAlias)" 12 | 13 | func (c *servicesClass) getList(ns string, listOptions metav1.ListOptions) (*corev1.ServiceList, error) { 14 | return c.rk.clientset.Core().Services(ns).List(listOptions) 15 | } 16 | 17 | func (c *servicesClass) getItem(services serviceListTypeAlias, index int) (*serviceClassInstance, error) { 18 | newServiceObj, err := c.rk.classes.Service.New() 19 | if err != nil { 20 | return nil, err 21 | } 22 | service := services.Items[index] 23 | newServiceObj.vars.service = serviceTypeAlias(service) 24 | return newServiceObj, nil 25 | } 26 | 27 | //go:generate gotemplate "./templates/resource/list" "servicesListModule(servicesClass, \"Services\", services, serviceListTypeAlias)" 28 | 29 | func (c *servicesClass) defineOwnMethods() { 30 | c.defineListMethods() 31 | } 32 | 33 | func (o *servicesClassInstance) Update(args ...*mruby.MrbValue) (mruby.Value, error) { 34 | return call(o.self, "get!", args...) 35 | } 36 | -------------------------------------------------------------------------------- /rubykube/resources_daemonSetsClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | mruby "github.com/mitchellh/go-mruby" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | appsv1 "k8s.io/api/apps/v1" 7 | ) 8 | 9 | type daemonSetListTypeAlias = appsv1.DaemonSetList 10 | 11 | //go:generate gotemplate "./templates/resource" "daemonSetsClass(\"DaemonSets\", daemonSets, daemonSetListTypeAlias)" 12 | 13 | func (c *daemonSetsClass) getList(ns string, listOptions metav1.ListOptions) (*appsv1.DaemonSetList, error) { 14 | return c.rk.clientset.Apps().DaemonSets(ns).List(listOptions) 15 | } 16 | 17 | func (c *daemonSetsClass) getItem(daemonSets daemonSetListTypeAlias, index int) (*daemonSetClassInstance, error) { 18 | newDaemonSetObj, err := c.rk.classes.DaemonSet.New() 19 | if err != nil { 20 | return nil, err 21 | } 22 | daemonSet := daemonSets.Items[index] 23 | newDaemonSetObj.vars.daemonSet = daemonSetTypeAlias(daemonSet) 24 | return newDaemonSetObj, nil 25 | } 26 | 27 | //go:generate gotemplate "./templates/resource/list" "daemonSetsListModule(daemonSetsClass, \"DaemonSets\", daemonSets, daemonSetListTypeAlias)" 28 | 29 | func (c *daemonSetsClass) defineOwnMethods() { 30 | c.defineListMethods() 31 | } 32 | 33 | func (o *daemonSetsClassInstance) Update(args ...*mruby.MrbValue) (mruby.Value, error) { 34 | return call(o.self, "get!", args...) 35 | } 36 | -------------------------------------------------------------------------------- /rubykube/gotemplate_podSingletonModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 10 | 11 | type podSingletonModule struct{} 12 | 13 | func (c *podClass) defineSingletonMethods() { 14 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 15 | "get!": { 16 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 17 | vars, err := c.LookupVars(self) 18 | if err != nil { 19 | return nil, createException(m, err.Error()) 20 | } 21 | 22 | meta := vars.pod.ObjectMeta 23 | pod, err := c.getSingleton(meta.Namespace, meta.Name) 24 | if err != nil { 25 | return nil, createException(m, err.Error()) 26 | } 27 | vars.pod = podTypeAlias(*pod) 28 | return self, nil 29 | }, 30 | instanceMethod, 31 | }, 32 | "inspect": { 33 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 34 | vars, err := c.LookupVars(self) 35 | if err != nil { 36 | return nil, createException(m, err.Error()) 37 | } 38 | 39 | fmt.Printf("self: %s/%s\n", vars.pod.ObjectMeta.Namespace, vars.pod.ObjectMeta.Name) 40 | return self, nil 41 | }, 42 | instanceMethod, 43 | }, 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /rubykube/resources_deploymentsClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | mruby "github.com/mitchellh/go-mruby" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | appsv1 "k8s.io/api/apps/v1" 7 | ) 8 | 9 | type deploymentListTypeAlias = appsv1.DeploymentList 10 | 11 | //go:generate gotemplate "./templates/resource" "deploymentsClass(\"Deployments\", deployments, deploymentListTypeAlias)" 12 | 13 | func (c *deploymentsClass) getList(ns string, listOptions metav1.ListOptions) (*appsv1.DeploymentList, error) { 14 | return c.rk.clientset.Apps().Deployments(ns).List(listOptions) 15 | } 16 | 17 | func (c *deploymentsClass) getItem(deployments deploymentListTypeAlias, index int) (*deploymentClassInstance, error) { 18 | newDeploymentObj, err := c.rk.classes.Deployment.New() 19 | if err != nil { 20 | return nil, err 21 | } 22 | deployment := deployments.Items[index] 23 | newDeploymentObj.vars.deployment = deploymentTypeAlias(deployment) 24 | return newDeploymentObj, nil 25 | } 26 | 27 | //go:generate gotemplate "./templates/resource/list" "deploymentsListModule(deploymentsClass, \"Deployments\", deployments, deploymentListTypeAlias)" 28 | 29 | func (c *deploymentsClass) defineOwnMethods() { 30 | c.defineListMethods() 31 | } 32 | 33 | func (o *deploymentsClassInstance) Update(args ...*mruby.MrbValue) (mruby.Value, error) { 34 | return call(o.self, "get!", args...) 35 | } 36 | -------------------------------------------------------------------------------- /rubykube/resources_replicaSetsClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | mruby "github.com/mitchellh/go-mruby" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | appsv1 "k8s.io/api/apps/v1" 7 | ) 8 | 9 | type replicaSetListTypeAlias = appsv1.ReplicaSetList 10 | 11 | //go:generate gotemplate "./templates/resource" "replicaSetsClass(\"ReplicaSets\", replicaSets, replicaSetListTypeAlias)" 12 | 13 | func (c *replicaSetsClass) getList(ns string, listOptions metav1.ListOptions) (*appsv1.ReplicaSetList, error) { 14 | return c.rk.clientset.Apps().ReplicaSets(ns).List(listOptions) 15 | } 16 | 17 | func (c *replicaSetsClass) getItem(replicaSets replicaSetListTypeAlias, index int) (*replicaSetClassInstance, error) { 18 | newReplicaSetObj, err := c.rk.classes.ReplicaSet.New() 19 | if err != nil { 20 | return nil, err 21 | } 22 | replicaSet := replicaSets.Items[index] 23 | newReplicaSetObj.vars.replicaSet = replicaSetTypeAlias(replicaSet) 24 | return newReplicaSetObj, nil 25 | } 26 | 27 | //go:generate gotemplate "./templates/resource/list" "replicaSetsListModule(replicaSetsClass, \"ReplicaSets\", replicaSets, replicaSetListTypeAlias)" 28 | 29 | func (c *replicaSetsClass) defineOwnMethods() { 30 | c.defineListMethods() 31 | } 32 | 33 | func (o *replicaSetsClassInstance) Update(args ...*mruby.MrbValue) (mruby.Value, error) { 34 | return call(o.self, "get!", args...) 35 | } 36 | -------------------------------------------------------------------------------- /rubykube/gotemplate_serviceSingletonModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 10 | 11 | type serviceSingletonModule struct{} 12 | 13 | func (c *serviceClass) defineSingletonMethods() { 14 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 15 | "get!": { 16 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 17 | vars, err := c.LookupVars(self) 18 | if err != nil { 19 | return nil, createException(m, err.Error()) 20 | } 21 | 22 | meta := vars.service.ObjectMeta 23 | service, err := c.getSingleton(meta.Namespace, meta.Name) 24 | if err != nil { 25 | return nil, createException(m, err.Error()) 26 | } 27 | vars.service = serviceTypeAlias(*service) 28 | return self, nil 29 | }, 30 | instanceMethod, 31 | }, 32 | "inspect": { 33 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 34 | vars, err := c.LookupVars(self) 35 | if err != nil { 36 | return nil, createException(m, err.Error()) 37 | } 38 | 39 | fmt.Printf("self: %s/%s\n", vars.service.ObjectMeta.Namespace, vars.service.ObjectMeta.Name) 40 | return self, nil 41 | }, 42 | instanceMethod, 43 | }, 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /rubykube/gotemplate_daemonSetSingletonModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 10 | 11 | type daemonSetSingletonModule struct{} 12 | 13 | func (c *daemonSetClass) defineSingletonMethods() { 14 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 15 | "get!": { 16 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 17 | vars, err := c.LookupVars(self) 18 | if err != nil { 19 | return nil, createException(m, err.Error()) 20 | } 21 | 22 | meta := vars.daemonSet.ObjectMeta 23 | daemonSet, err := c.getSingleton(meta.Namespace, meta.Name) 24 | if err != nil { 25 | return nil, createException(m, err.Error()) 26 | } 27 | vars.daemonSet = daemonSetTypeAlias(*daemonSet) 28 | return self, nil 29 | }, 30 | instanceMethod, 31 | }, 32 | "inspect": { 33 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 34 | vars, err := c.LookupVars(self) 35 | if err != nil { 36 | return nil, createException(m, err.Error()) 37 | } 38 | 39 | fmt.Printf("self: %s/%s\n", vars.daemonSet.ObjectMeta.Namespace, vars.daemonSet.ObjectMeta.Name) 40 | return self, nil 41 | }, 42 | instanceMethod, 43 | }, 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /rubykube/gotemplate_deploymentSingletonModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 10 | 11 | type deploymentSingletonModule struct{} 12 | 13 | func (c *deploymentClass) defineSingletonMethods() { 14 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 15 | "get!": { 16 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 17 | vars, err := c.LookupVars(self) 18 | if err != nil { 19 | return nil, createException(m, err.Error()) 20 | } 21 | 22 | meta := vars.deployment.ObjectMeta 23 | deployment, err := c.getSingleton(meta.Namespace, meta.Name) 24 | if err != nil { 25 | return nil, createException(m, err.Error()) 26 | } 27 | vars.deployment = deploymentTypeAlias(*deployment) 28 | return self, nil 29 | }, 30 | instanceMethod, 31 | }, 32 | "inspect": { 33 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 34 | vars, err := c.LookupVars(self) 35 | if err != nil { 36 | return nil, createException(m, err.Error()) 37 | } 38 | 39 | fmt.Printf("self: %s/%s\n", vars.deployment.ObjectMeta.Namespace, vars.deployment.ObjectMeta.Name) 40 | return self, nil 41 | }, 42 | instanceMethod, 43 | }, 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /rubykube/gotemplate_replicaSetSingletonModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 10 | 11 | type replicaSetSingletonModule struct{} 12 | 13 | func (c *replicaSetClass) defineSingletonMethods() { 14 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 15 | "get!": { 16 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 17 | vars, err := c.LookupVars(self) 18 | if err != nil { 19 | return nil, createException(m, err.Error()) 20 | } 21 | 22 | meta := vars.replicaSet.ObjectMeta 23 | replicaSet, err := c.getSingleton(meta.Namespace, meta.Name) 24 | if err != nil { 25 | return nil, createException(m, err.Error()) 26 | } 27 | vars.replicaSet = replicaSetTypeAlias(*replicaSet) 28 | return self, nil 29 | }, 30 | instanceMethod, 31 | }, 32 | "inspect": { 33 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 34 | vars, err := c.LookupVars(self) 35 | if err != nil { 36 | return nil, createException(m, err.Error()) 37 | } 38 | 39 | fmt.Printf("self: %s/%s\n", vars.replicaSet.ObjectMeta.Namespace, vars.replicaSet.ObjectMeta.Name) 40 | return self, nil 41 | }, 42 | instanceMethod, 43 | }, 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /rubykube/templates/resource/podfinder/template.go: -------------------------------------------------------------------------------- 1 | package resourcepodfinder 2 | 3 | import ( 4 | mruby "github.com/mitchellh/go-mruby" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | ) 7 | 8 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 9 | 10 | type RubyKubeClass struct{} 11 | 12 | type parentClass int 13 | type classNameString string 14 | type instanceVariableName int 15 | type instanceVariableType int 16 | 17 | func (c *parentClass) definePodFinderMethods() { 18 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 19 | "pods": { 20 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 21 | vars, err := c.LookupVars(self) 22 | if err != nil { 23 | return nil, createException(m, err.Error()) 24 | } 25 | 26 | ns := vars.instanceVariableName.ObjectMeta.Namespace 27 | 28 | listOptions := metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(vars.deployment.Spec.Selector)} 29 | 30 | pods, err := c.rk.clientset.Core().Pods(ns).List(listOptions) 31 | if err != nil { 32 | return nil, createException(m, err.Error()) 33 | } 34 | 35 | // TODO: verify `ownerReferences`... 36 | 37 | newPodsObj, err := c.rk.classes.Pods.New() 38 | if err != nil { 39 | return nil, createException(m, err.Error()) 40 | } 41 | newPodsObj.vars.pods = podListTypeAlias(*pods) 42 | return newPodsObj.self, nil 43 | }, 44 | instanceMethod, 45 | }, 46 | }) 47 | } 48 | -------------------------------------------------------------------------------- /rubykube/gotemplate_servicePodFinderModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 12 | 13 | type servicePodFinderModule struct{} 14 | 15 | func (c *serviceClass) definePodFinderMethods() { 16 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 17 | "pods": { 18 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 19 | vars, err := c.LookupVars(self) 20 | if err != nil { 21 | return nil, createException(m, err.Error()) 22 | } 23 | 24 | ns := vars.service.ObjectMeta.Namespace 25 | 26 | selector := []string{} 27 | // TODO: probably should use `spec.selector` 28 | for k, v := range vars.service.ObjectMeta.Labels { 29 | selector = append(selector, fmt.Sprintf("%s in (%s)", k, v)) 30 | } 31 | listOptions := metav1.ListOptions{LabelSelector: strings.Join(selector, ",")} 32 | 33 | pods, err := c.rk.clientset.Core().Pods(ns).List(listOptions) 34 | if err != nil { 35 | return nil, createException(m, err.Error()) 36 | } 37 | 38 | // TODO: verify `ownerReferences`... 39 | 40 | newPodsObj, err := c.rk.classes.Pods.New() 41 | if err != nil { 42 | return nil, createException(m, err.Error()) 43 | } 44 | newPodsObj.vars.pods = podListTypeAlias(*pods) 45 | return newPodsObj.self, nil 46 | }, 47 | instanceMethod, 48 | }, 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /rubykube/gotemplate_daemonSetPodFinderModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 12 | 13 | type daemonSetPodFinderModule struct{} 14 | 15 | func (c *daemonSetClass) definePodFinderMethods() { 16 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 17 | "pods": { 18 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 19 | vars, err := c.LookupVars(self) 20 | if err != nil { 21 | return nil, createException(m, err.Error()) 22 | } 23 | 24 | ns := vars.daemonSet.ObjectMeta.Namespace 25 | 26 | selector := []string{} 27 | // TODO: probably should use `spec.selector` 28 | for k, v := range vars.daemonSet.ObjectMeta.Labels { 29 | selector = append(selector, fmt.Sprintf("%s in (%s)", k, v)) 30 | } 31 | listOptions := metav1.ListOptions{LabelSelector: strings.Join(selector, ",")} 32 | 33 | pods, err := c.rk.clientset.Core().Pods(ns).List(listOptions) 34 | if err != nil { 35 | return nil, createException(m, err.Error()) 36 | } 37 | 38 | // TODO: verify `ownerReferences`... 39 | 40 | newPodsObj, err := c.rk.classes.Pods.New() 41 | if err != nil { 42 | return nil, createException(m, err.Error()) 43 | } 44 | newPodsObj.vars.pods = podListTypeAlias(*pods) 45 | return newPodsObj.self, nil 46 | }, 47 | instanceMethod, 48 | }, 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /rubykube/gotemplate_deploymentPodFinderModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 12 | 13 | type deploymentPodFinderModule struct{} 14 | 15 | func (c *deploymentClass) definePodFinderMethods() { 16 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 17 | "pods": { 18 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 19 | vars, err := c.LookupVars(self) 20 | if err != nil { 21 | return nil, createException(m, err.Error()) 22 | } 23 | 24 | ns := vars.deployment.ObjectMeta.Namespace 25 | 26 | selector := []string{} 27 | // TODO: probably should use `spec.selector` 28 | for k, v := range vars.deployment.ObjectMeta.Labels { 29 | selector = append(selector, fmt.Sprintf("%s in (%s)", k, v)) 30 | } 31 | listOptions := metav1.ListOptions{LabelSelector: strings.Join(selector, ",")} 32 | 33 | pods, err := c.rk.clientset.Core().Pods(ns).List(listOptions) 34 | if err != nil { 35 | return nil, createException(m, err.Error()) 36 | } 37 | 38 | // TODO: verify `ownerReferences`... 39 | 40 | newPodsObj, err := c.rk.classes.Pods.New() 41 | if err != nil { 42 | return nil, createException(m, err.Error()) 43 | } 44 | newPodsObj.vars.pods = podListTypeAlias(*pods) 45 | return newPodsObj.self, nil 46 | }, 47 | instanceMethod, 48 | }, 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /rubykube/gotemplate_replicaSetPodFinderModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 12 | 13 | type replicaSetPodFinderModule struct{} 14 | 15 | func (c *replicaSetClass) definePodFinderMethods() { 16 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 17 | "pods": { 18 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 19 | vars, err := c.LookupVars(self) 20 | if err != nil { 21 | return nil, createException(m, err.Error()) 22 | } 23 | 24 | ns := vars.replicaSet.ObjectMeta.Namespace 25 | 26 | selector := []string{} 27 | // TODO: probably should use `spec.selector` 28 | for k, v := range vars.replicaSet.ObjectMeta.Labels { 29 | selector = append(selector, fmt.Sprintf("%s in (%s)", k, v)) 30 | } 31 | listOptions := metav1.ListOptions{LabelSelector: strings.Join(selector, ",")} 32 | 33 | pods, err := c.rk.clientset.Core().Pods(ns).List(listOptions) 34 | if err != nil { 35 | return nil, createException(m, err.Error()) 36 | } 37 | 38 | // TODO: verify `ownerReferences`... 39 | 40 | newPodsObj, err := c.rk.classes.Pods.New() 41 | if err != nil { 42 | return nil, createException(m, err.Error()) 43 | } 44 | newPodsObj.vars.pods = podListTypeAlias(*pods) 45 | return newPodsObj.self, nil 46 | }, 47 | instanceMethod, 48 | }, 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /rubykube/templates/resource/singleton/template.go: -------------------------------------------------------------------------------- 1 | package resourcesingleton 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 10 | 11 | type RubyKubeClass struct{} 12 | 13 | type parentClass int 14 | type classNameString string 15 | type instanceVariableName int 16 | type instanceVariableType int 17 | 18 | func (c *parentClass) defineSingletonMethods() { 19 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 20 | "get!": { 21 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 22 | vars, err := c.LookupVars(self) 23 | if err != nil { 24 | return nil, createException(m, err.Error()) 25 | } 26 | 27 | meta := vars.instanceVariableName.ObjectMeta 28 | instanceVariableName, err := c.getSingleton(meta.Namespace, meta.Name) 29 | if err != nil { 30 | return nil, createException(m, err.Error()) 31 | } 32 | vars.instanceVariableName = instanceVariableType(*instanceVariableName) 33 | return self, nil 34 | }, 35 | instanceMethod, 36 | }, 37 | "inspect": { 38 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 39 | vars, err := c.LookupVars(self) 40 | if err != nil { 41 | return nil, createException(m, err.Error()) 42 | } 43 | 44 | fmt.Printf("self: %s/%s\n", vars.instanceVariableName.ObjectMeta.Namespace, vars.instanceVariableName.ObjectMeta.Name) 45 | return self, nil 46 | }, 47 | instanceMethod, 48 | }, 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /rubykube/helpers_fieldSelectorClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | type fieldSelectorClassInstanceVars struct { 11 | collector *fieldCollectorClassInstance 12 | } 13 | 14 | func newFieldSelectorClassInstanceVars(c *fieldSelectorClass, s *mruby.MrbValue, args ...mruby.Value) (*fieldSelectorClassInstanceVars, error) { 15 | if len(args) != 1 { 16 | return nil, fmt.Errorf("Exactly one argument must supplied") 17 | } 18 | 19 | newFieldCollectorObj, err := c.rk.classes.FieldCollector.New(args...) 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | if err := newFieldCollectorObj.vars.eval(); err != nil { 25 | return nil, err 26 | } 27 | 28 | return &fieldSelectorClassInstanceVars{newFieldCollectorObj}, nil 29 | } 30 | 31 | //go:generate gotemplate "./templates/basic" "fieldSelectorClass(\"FieldSelector\", newFieldSelectorClassInstanceVars, fieldSelectorClassInstanceVars)" 32 | 33 | func (c *fieldSelectorClass) defineOwnMethods() { 34 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 35 | "to_s": { 36 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 37 | vars, err := c.LookupVars(self) 38 | if err != nil { 39 | return nil, createException(m, err.Error()) 40 | } 41 | 42 | fields := []string{} 43 | for _, e := range vars.collector.vars.fields { 44 | for _, v := range e.values { 45 | fields = append(fields, fmt.Sprintf("%s%s%s", e.key, e.operator, v)) 46 | } 47 | } 48 | 49 | return m.StringValue(strings.Join(fields, ",")), nil 50 | }, 51 | instanceMethod, 52 | }, 53 | }) 54 | } 55 | -------------------------------------------------------------------------------- /rubykube/patches.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | var patches = []string{ 4 | // We need to allow `Struct`-alike access to attributes `Struct` doesn't just work, and we need to do a lot 5 | // of recursion etc, and it gets complicated... There exists `OpenStruct` and `RecursiveOpenStruct`, but 6 | // both depend on `Thread` and `Regexp`. There is a version of `OpenStruct` ported to mruby, but it's 7 | // quite tedious to make it recursive... Monkey-patching `Hash` (like in http://stackoverflow.com/a/38175437/717998) 8 | // works well for our simple DSL case, at least for now. 9 | // We can do something smarter later, but this just does what we want. The only thing we will need to ensure 10 | // is to not try to define methods that already map to attributes, or at least be careful when we do that. 11 | // TODO: how should we handle setters? It seems a big question in general... Pods are immutable, but we should 12 | // let user update a value of some filed and apply it, e.g. 13 | // `my = rc.any; my.rc.spec.template.containers << myHandyDebuggerSideCar; myrc.apply!` 14 | `class Hash 15 | def method_missing(m, *opts) 16 | if self.has_key?(m.to_s) 17 | return self[m.to_s] 18 | elsif self.has_key?(m.to_sym) 19 | return self[m.to_sym] 20 | end 21 | return nil 22 | end 23 | end 24 | `, 25 | //// This is needed for creating lable expressions 26 | //`class String 27 | // def to_l 28 | // RubyKube::LabelKey.new self 29 | // end 30 | // end 31 | //`, 32 | } 33 | 34 | func (rk *RubyKube) applyPatches() error { 35 | for _, p := range patches { 36 | if _, err := rk.mrb.LoadString(p); err != nil { 37 | return err 38 | } 39 | } 40 | return nil 41 | } 42 | -------------------------------------------------------------------------------- /rubykube/helpers_labelSelectorClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | type labelSelectorClassInstanceVars struct { 11 | collector *labelCollectorClassInstance 12 | } 13 | 14 | func newLabelSelectorClassInstanceVars(c *labelSelectorClass, s *mruby.MrbValue, args ...mruby.Value) (*labelSelectorClassInstanceVars, error) { 15 | if len(args) != 1 { 16 | return nil, fmt.Errorf("Exactly one argument must supplied") 17 | } 18 | 19 | newLabelCollectorObj, err := c.rk.classes.LabelCollector.New(args...) 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | if err := newLabelCollectorObj.vars.eval(); err != nil { 25 | return nil, err 26 | } 27 | 28 | return &labelSelectorClassInstanceVars{newLabelCollectorObj}, nil 29 | } 30 | 31 | //go:generate gotemplate "./templates/basic" "labelSelectorClass(\"LabelSelector\", newLabelSelectorClassInstanceVars, labelSelectorClassInstanceVars)" 32 | 33 | func (c *labelSelectorClass) defineOwnMethods() { 34 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 35 | "to_s": { 36 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 37 | vars, err := c.LookupVars(self) 38 | if err != nil { 39 | return nil, createException(m, err.Error()) 40 | } 41 | 42 | labels := []string{} 43 | for _, e := range vars.collector.vars.labels { 44 | if e.operator != "" { 45 | labels = append(labels, fmt.Sprintf("%s %s (%s)", e.key, e.operator, strings.Join(e.values, ", "))) 46 | } else { 47 | labels = append(labels, e.key) 48 | } 49 | } 50 | 51 | return m.StringValue(strings.Join(labels, ",")), nil 52 | }, 53 | instanceMethod, 54 | }, 55 | }) 56 | } 57 | -------------------------------------------------------------------------------- /rubykube/gotemplate_podLogsClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(classNameString, newClassInstanceVars, classInstanceVarsType) 10 | 11 | type podLogsClass struct { 12 | class *mruby.Class 13 | objects []podLogsClassInstance 14 | rk *RubyKube 15 | } 16 | 17 | type podLogsClassInstance struct { 18 | self *mruby.MrbValue 19 | vars *podLogsClassInstanceVars 20 | } 21 | 22 | func newPodLogsClass(rk *RubyKube) *podLogsClass { 23 | c := &podLogsClass{objects: []podLogsClassInstance{}, rk: rk} 24 | c.class = definePodLogsClass(rk, c) 25 | return c 26 | } 27 | 28 | func definePodLogsClass(rk *RubyKube, c *podLogsClass) *mruby.Class { 29 | // common methods 30 | return rk.defineClass("PodLogs", map[string]methodDefintion{ 31 | "object_count": { 32 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 33 | return m.FixnumValue(len(c.objects)), nil 34 | }, 35 | classMethod, 36 | }, 37 | }) 38 | } 39 | 40 | func (c *podLogsClass) New(args ...mruby.Value) (*podLogsClassInstance, error) { 41 | s, err := c.class.New() 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | v, err := newPodLogsClassInstanceVars(c, s, args...) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | o := podLogsClassInstance{ 52 | self: s, 53 | vars: v, 54 | } 55 | c.objects = append(c.objects, o) 56 | return &o, nil 57 | } 58 | 59 | func (c *podLogsClass) LookupVars(this *mruby.MrbValue) (*podLogsClassInstanceVars, error) { 60 | for _, that := range c.objects { 61 | if *this == *that.self { 62 | return that.vars, nil 63 | } 64 | } 65 | return nil, fmt.Errorf("%s: could not find class instance", "PodLogs") 66 | } 67 | -------------------------------------------------------------------------------- /rubykube/resources_podsClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | mruby "github.com/mitchellh/go-mruby" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | corev1 "k8s.io/api/core/v1" 7 | ) 8 | 9 | type podListTypeAlias = corev1.PodList 10 | 11 | //go:generate gotemplate "./templates/resource" "podsClass(\"Pods\", pods, podListTypeAlias)" 12 | 13 | func (c *podsClass) getList(ns string, listOptions metav1.ListOptions) (*corev1.PodList, error) { 14 | return c.rk.clientset.Core().Pods(ns).List(listOptions) 15 | } 16 | 17 | func (c *podsClass) getItem(pods podListTypeAlias, index int) (*podClassInstance, error) { 18 | newPodObj, err := c.rk.classes.Pod.New() 19 | if err != nil { 20 | return nil, err 21 | } 22 | pod := pods.Items[index] 23 | newPodObj.vars.pod = podTypeAlias(pod) 24 | return newPodObj, nil 25 | } 26 | 27 | //go:generate gotemplate "./templates/resource/list" "podsListModule(podsClass, \"Pods\", pods, podListTypeAlias)" 28 | 29 | func (c *podsClass) defineOwnMethods() { 30 | c.defineListMethods() 31 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 32 | "logs": { 33 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 34 | vars, err := c.LookupVars(self) 35 | if err != nil { 36 | return nil, createException(m, err.Error()) 37 | } 38 | 39 | newPodLogsObj, err := c.rk.classes.PodLogs.New() 40 | if err != nil { 41 | return nil, createException(m, err.Error()) 42 | } 43 | newPodLogsObj.vars.pods = vars.pods.Items 44 | return callWithException(m, newPodLogsObj.self, "get!") 45 | }, 46 | instanceMethod, 47 | }, 48 | }) 49 | } 50 | 51 | func (o *podsClassInstance) Update(args ...*mruby.MrbValue) (mruby.Value, error) { 52 | return call(o.self, "get!", args...) 53 | } 54 | -------------------------------------------------------------------------------- /rubykube/gotemplate_fieldKeyClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(classNameString, newClassInstanceVars, classInstanceVarsType) 10 | 11 | type fieldKeyClass struct { 12 | class *mruby.Class 13 | objects []fieldKeyClassInstance 14 | rk *RubyKube 15 | } 16 | 17 | type fieldKeyClassInstance struct { 18 | self *mruby.MrbValue 19 | vars *fieldKeyClassInstanceVars 20 | } 21 | 22 | func newFieldKeyClass(rk *RubyKube) *fieldKeyClass { 23 | c := &fieldKeyClass{objects: []fieldKeyClassInstance{}, rk: rk} 24 | c.class = defineFieldKeyClass(rk, c) 25 | return c 26 | } 27 | 28 | func defineFieldKeyClass(rk *RubyKube, c *fieldKeyClass) *mruby.Class { 29 | // common methods 30 | return rk.defineClass("FieldKey", map[string]methodDefintion{ 31 | "object_count": { 32 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 33 | return m.FixnumValue(len(c.objects)), nil 34 | }, 35 | classMethod, 36 | }, 37 | }) 38 | } 39 | 40 | func (c *fieldKeyClass) New(args ...mruby.Value) (*fieldKeyClassInstance, error) { 41 | s, err := c.class.New() 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | v, err := newFieldKeyClassInstanceVars(c, s, args...) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | o := fieldKeyClassInstance{ 52 | self: s, 53 | vars: v, 54 | } 55 | c.objects = append(c.objects, o) 56 | return &o, nil 57 | } 58 | 59 | func (c *fieldKeyClass) LookupVars(this *mruby.MrbValue) (*fieldKeyClassInstanceVars, error) { 60 | for _, that := range c.objects { 61 | if *this == *that.self { 62 | return that.vars, nil 63 | } 64 | } 65 | return nil, fmt.Errorf("%s: could not find class instance", "FieldKey") 66 | } 67 | -------------------------------------------------------------------------------- /rubykube/gotemplate_labelKeyClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(classNameString, newClassInstanceVars, classInstanceVarsType) 10 | 11 | type labelKeyClass struct { 12 | class *mruby.Class 13 | objects []labelKeyClassInstance 14 | rk *RubyKube 15 | } 16 | 17 | type labelKeyClassInstance struct { 18 | self *mruby.MrbValue 19 | vars *labelKeyClassInstanceVars 20 | } 21 | 22 | func newLabelKeyClass(rk *RubyKube) *labelKeyClass { 23 | c := &labelKeyClass{objects: []labelKeyClassInstance{}, rk: rk} 24 | c.class = defineLabelKeyClass(rk, c) 25 | return c 26 | } 27 | 28 | func defineLabelKeyClass(rk *RubyKube, c *labelKeyClass) *mruby.Class { 29 | // common methods 30 | return rk.defineClass("LabelKey", map[string]methodDefintion{ 31 | "object_count": { 32 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 33 | return m.FixnumValue(len(c.objects)), nil 34 | }, 35 | classMethod, 36 | }, 37 | }) 38 | } 39 | 40 | func (c *labelKeyClass) New(args ...mruby.Value) (*labelKeyClassInstance, error) { 41 | s, err := c.class.New() 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | v, err := newLabelKeyClassInstanceVars(c, s, args...) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | o := labelKeyClassInstance{ 52 | self: s, 53 | vars: v, 54 | } 55 | c.objects = append(c.objects, o) 56 | return &o, nil 57 | } 58 | 59 | func (c *labelKeyClass) LookupVars(this *mruby.MrbValue) (*labelKeyClassInstanceVars, error) { 60 | for _, that := range c.objects { 61 | if *this == *that.self { 62 | return that.vars, nil 63 | } 64 | } 65 | return nil, fmt.Errorf("%s: could not find class instance", "LabelKey") 66 | } 67 | -------------------------------------------------------------------------------- /rubykube/gotemplate_podMakerClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(classNameString, newClassInstanceVars, classInstanceVarsType) 10 | 11 | type podMakerClass struct { 12 | class *mruby.Class 13 | objects []podMakerClassInstance 14 | rk *RubyKube 15 | } 16 | 17 | type podMakerClassInstance struct { 18 | self *mruby.MrbValue 19 | vars *podMakerClassInstanceVars 20 | } 21 | 22 | func newPodMakerClass(rk *RubyKube) *podMakerClass { 23 | c := &podMakerClass{objects: []podMakerClassInstance{}, rk: rk} 24 | c.class = definePodMakerClass(rk, c) 25 | return c 26 | } 27 | 28 | func definePodMakerClass(rk *RubyKube, c *podMakerClass) *mruby.Class { 29 | // common methods 30 | return rk.defineClass("PodMaker", map[string]methodDefintion{ 31 | "object_count": { 32 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 33 | return m.FixnumValue(len(c.objects)), nil 34 | }, 35 | classMethod, 36 | }, 37 | }) 38 | } 39 | 40 | func (c *podMakerClass) New(args ...mruby.Value) (*podMakerClassInstance, error) { 41 | s, err := c.class.New() 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | v, err := newPodMakerClassInstanceVars(c, s, args...) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | o := podMakerClassInstance{ 52 | self: s, 53 | vars: v, 54 | } 55 | c.objects = append(c.objects, o) 56 | return &o, nil 57 | } 58 | 59 | func (c *podMakerClass) LookupVars(this *mruby.MrbValue) (*podMakerClassInstanceVars, error) { 60 | for _, that := range c.objects { 61 | if *this == *that.self { 62 | return that.vars, nil 63 | } 64 | } 65 | return nil, fmt.Errorf("%s: could not find class instance", "PodMaker") 66 | } 67 | -------------------------------------------------------------------------------- /rubykube/gotemplate_fieldSelectorClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(classNameString, newClassInstanceVars, classInstanceVarsType) 10 | 11 | type fieldSelectorClass struct { 12 | class *mruby.Class 13 | objects []fieldSelectorClassInstance 14 | rk *RubyKube 15 | } 16 | 17 | type fieldSelectorClassInstance struct { 18 | self *mruby.MrbValue 19 | vars *fieldSelectorClassInstanceVars 20 | } 21 | 22 | func newFieldSelectorClass(rk *RubyKube) *fieldSelectorClass { 23 | c := &fieldSelectorClass{objects: []fieldSelectorClassInstance{}, rk: rk} 24 | c.class = defineFieldSelectorClass(rk, c) 25 | return c 26 | } 27 | 28 | func defineFieldSelectorClass(rk *RubyKube, c *fieldSelectorClass) *mruby.Class { 29 | // common methods 30 | return rk.defineClass("FieldSelector", map[string]methodDefintion{ 31 | "object_count": { 32 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 33 | return m.FixnumValue(len(c.objects)), nil 34 | }, 35 | classMethod, 36 | }, 37 | }) 38 | } 39 | 40 | func (c *fieldSelectorClass) New(args ...mruby.Value) (*fieldSelectorClassInstance, error) { 41 | s, err := c.class.New() 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | v, err := newFieldSelectorClassInstanceVars(c, s, args...) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | o := fieldSelectorClassInstance{ 52 | self: s, 53 | vars: v, 54 | } 55 | c.objects = append(c.objects, o) 56 | return &o, nil 57 | } 58 | 59 | func (c *fieldSelectorClass) LookupVars(this *mruby.MrbValue) (*fieldSelectorClassInstanceVars, error) { 60 | for _, that := range c.objects { 61 | if *this == *that.self { 62 | return that.vars, nil 63 | } 64 | } 65 | return nil, fmt.Errorf("%s: could not find class instance", "FieldSelector") 66 | } 67 | -------------------------------------------------------------------------------- /rubykube/gotemplate_labelSelectorClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(classNameString, newClassInstanceVars, classInstanceVarsType) 10 | 11 | type labelSelectorClass struct { 12 | class *mruby.Class 13 | objects []labelSelectorClassInstance 14 | rk *RubyKube 15 | } 16 | 17 | type labelSelectorClassInstance struct { 18 | self *mruby.MrbValue 19 | vars *labelSelectorClassInstanceVars 20 | } 21 | 22 | func newLabelSelectorClass(rk *RubyKube) *labelSelectorClass { 23 | c := &labelSelectorClass{objects: []labelSelectorClassInstance{}, rk: rk} 24 | c.class = defineLabelSelectorClass(rk, c) 25 | return c 26 | } 27 | 28 | func defineLabelSelectorClass(rk *RubyKube, c *labelSelectorClass) *mruby.Class { 29 | // common methods 30 | return rk.defineClass("LabelSelector", map[string]methodDefintion{ 31 | "object_count": { 32 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 33 | return m.FixnumValue(len(c.objects)), nil 34 | }, 35 | classMethod, 36 | }, 37 | }) 38 | } 39 | 40 | func (c *labelSelectorClass) New(args ...mruby.Value) (*labelSelectorClassInstance, error) { 41 | s, err := c.class.New() 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | v, err := newLabelSelectorClassInstanceVars(c, s, args...) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | o := labelSelectorClassInstance{ 52 | self: s, 53 | vars: v, 54 | } 55 | c.objects = append(c.objects, o) 56 | return &o, nil 57 | } 58 | 59 | func (c *labelSelectorClass) LookupVars(this *mruby.MrbValue) (*labelSelectorClassInstanceVars, error) { 60 | for _, that := range c.objects { 61 | if *this == *that.self { 62 | return that.vars, nil 63 | } 64 | } 65 | return nil, fmt.Errorf("%s: could not find class instance", "LabelSelector") 66 | } 67 | -------------------------------------------------------------------------------- /rubykube/templates/basic/template.go: -------------------------------------------------------------------------------- 1 | package basic 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(classNameString, newClassInstanceVars, classInstanceVarsType) 10 | 11 | type classNameString string 12 | type newClassInstanceVars int 13 | type classInstanceVarsType int 14 | 15 | type RubyKubeClass struct { 16 | class *mruby.Class 17 | objects []RubyKubeClassInstance 18 | rk *RubyKube 19 | } 20 | 21 | type RubyKubeClassInstance struct { 22 | self *mruby.MrbValue 23 | vars *classInstanceVarsType 24 | } 25 | 26 | func NewRubyKubeClass(rk *RubyKube) *RubyKubeClass { 27 | c := &RubyKubeClass{objects: []RubyKubeClassInstance{}, rk: rk} 28 | c.class = DefineRubyKubeClass(rk, c) 29 | return c 30 | } 31 | 32 | func DefineRubyKubeClass(rk *RubyKube, c *RubyKubeClass) *mruby.Class { 33 | // common methods 34 | return rk.defineClass(classNameString, map[string]methodDefintion{ 35 | "object_count": { 36 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 37 | return m.FixnumValue(len(c.objects)), nil 38 | }, 39 | classMethod, 40 | }, 41 | }) 42 | } 43 | 44 | func (c *RubyKubeClass) New(args ...mruby.Value) (*RubyKubeClassInstance, error) { 45 | s, err := c.class.New() 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | v, err := newClassInstanceVars(c, s, args...) 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | o := RubyKubeClassInstance{ 56 | self: s, 57 | vars: v, 58 | } 59 | c.objects = append(c.objects, o) 60 | return &o, nil 61 | } 62 | 63 | func (c *RubyKubeClass) LookupVars(this *mruby.MrbValue) (*classInstanceVarsType, error) { 64 | for _, that := range c.objects { 65 | if *this == *that.self { 66 | return that.vars, nil 67 | } 68 | } 69 | return nil, fmt.Errorf("%s: could not find class instance", classNameString) 70 | } 71 | -------------------------------------------------------------------------------- /rubykube/gotemplate_fieldCollectorClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(classNameString, newClassInstanceVars, classInstanceVarsType) 10 | 11 | type fieldCollectorClass struct { 12 | class *mruby.Class 13 | objects []fieldCollectorClassInstance 14 | rk *RubyKube 15 | } 16 | 17 | type fieldCollectorClassInstance struct { 18 | self *mruby.MrbValue 19 | vars *fieldCollectorClassInstanceVars 20 | } 21 | 22 | func newFieldCollectorClass(rk *RubyKube) *fieldCollectorClass { 23 | c := &fieldCollectorClass{objects: []fieldCollectorClassInstance{}, rk: rk} 24 | c.class = defineFieldCollectorClass(rk, c) 25 | return c 26 | } 27 | 28 | func defineFieldCollectorClass(rk *RubyKube, c *fieldCollectorClass) *mruby.Class { 29 | // common methods 30 | return rk.defineClass("FieldCollector", map[string]methodDefintion{ 31 | "object_count": { 32 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 33 | return m.FixnumValue(len(c.objects)), nil 34 | }, 35 | classMethod, 36 | }, 37 | }) 38 | } 39 | 40 | func (c *fieldCollectorClass) New(args ...mruby.Value) (*fieldCollectorClassInstance, error) { 41 | s, err := c.class.New() 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | v, err := newFieldCollectorClassInstanceVars(c, s, args...) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | o := fieldCollectorClassInstance{ 52 | self: s, 53 | vars: v, 54 | } 55 | c.objects = append(c.objects, o) 56 | return &o, nil 57 | } 58 | 59 | func (c *fieldCollectorClass) LookupVars(this *mruby.MrbValue) (*fieldCollectorClassInstanceVars, error) { 60 | for _, that := range c.objects { 61 | if *this == *that.self { 62 | return that.vars, nil 63 | } 64 | } 65 | return nil, fmt.Errorf("%s: could not find class instance", "FieldCollector") 66 | } 67 | -------------------------------------------------------------------------------- /rubykube/gotemplate_labelCollectorClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | // template type RubyKubeClass(classNameString, newClassInstanceVars, classInstanceVarsType) 10 | 11 | type labelCollectorClass struct { 12 | class *mruby.Class 13 | objects []labelCollectorClassInstance 14 | rk *RubyKube 15 | } 16 | 17 | type labelCollectorClassInstance struct { 18 | self *mruby.MrbValue 19 | vars *labelCollectorClassInstanceVars 20 | } 21 | 22 | func newLabelCollectorClass(rk *RubyKube) *labelCollectorClass { 23 | c := &labelCollectorClass{objects: []labelCollectorClassInstance{}, rk: rk} 24 | c.class = defineLabelCollectorClass(rk, c) 25 | return c 26 | } 27 | 28 | func defineLabelCollectorClass(rk *RubyKube, c *labelCollectorClass) *mruby.Class { 29 | // common methods 30 | return rk.defineClass("LabelCollector", map[string]methodDefintion{ 31 | "object_count": { 32 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 33 | return m.FixnumValue(len(c.objects)), nil 34 | }, 35 | classMethod, 36 | }, 37 | }) 38 | } 39 | 40 | func (c *labelCollectorClass) New(args ...mruby.Value) (*labelCollectorClassInstance, error) { 41 | s, err := c.class.New() 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | v, err := newLabelCollectorClassInstanceVars(c, s, args...) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | o := labelCollectorClassInstance{ 52 | self: s, 53 | vars: v, 54 | } 55 | c.objects = append(c.objects, o) 56 | return &o, nil 57 | } 58 | 59 | func (c *labelCollectorClass) LookupVars(this *mruby.MrbValue) (*labelCollectorClassInstanceVars, error) { 60 | for _, that := range c.objects { 61 | if *this == *that.self { 62 | return that.vars, nil 63 | } 64 | } 65 | return nil, fmt.Errorf("%s: could not find class instance", "LabelCollector") 66 | } 67 | -------------------------------------------------------------------------------- /rubykube/resources_deploymentClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | mruby "github.com/mitchellh/go-mruby" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | appsv1 "k8s.io/api/apps/v1" 7 | ) 8 | 9 | type deploymentTypeAlias = appsv1.Deployment 10 | 11 | //go:generate gotemplate "./templates/resource" "deploymentClass(\"Deployment\", deployment, deploymentTypeAlias)" 12 | 13 | func (c *deploymentClass) getSingleton(ns, name string) (*appsv1.Deployment, error) { 14 | return c.rk.clientset.Apps().Deployments(ns).Get(name, metav1.GetOptions{}) 15 | } 16 | 17 | //go:generate gotemplate "./templates/resource/singleton" "deploymentSingletonModule(deploymentClass, \"deployment\", deployment, deploymentTypeAlias)" 18 | 19 | //go:generate gotemplate "./templates/resource/podfinder" "deploymentPodFinderModule(deploymentClass, \"deployment\", deployment, deploymentTypeAlias)" 20 | 21 | func (c *deploymentClass) defineOwnMethods() { 22 | c.defineSingletonMethods() 23 | c.definePodFinderMethods() 24 | 25 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 26 | "replicasets": { 27 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 28 | vars, err := c.LookupVars(self) 29 | if err != nil { 30 | return nil, createException(m, err.Error()) 31 | } 32 | 33 | ns := vars.deployment.ObjectMeta.Namespace 34 | 35 | listOptions := metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(vars.deployment.Spec.Selector)} 36 | 37 | replicaSets, err := c.rk.clientset.Apps().ReplicaSets(ns).List(listOptions) 38 | if err != nil { 39 | return nil, createException(m, err.Error()) 40 | } 41 | 42 | newReplicaSetsObj, err := c.rk.classes.ReplicaSets.New() 43 | if err != nil { 44 | return nil, createException(m, err.Error()) 45 | } 46 | newReplicaSetsObj.vars.replicaSets = replicaSetListTypeAlias(*replicaSets) 47 | return newReplicaSetsObj.self, nil 48 | }, 49 | instanceMethod, 50 | }, 51 | }) 52 | } 53 | 54 | func (o *deploymentClassInstance) Update() (mruby.Value, error) { 55 | return call(o.self, "get!") 56 | } 57 | -------------------------------------------------------------------------------- /rubykube/gotemplate_podClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/errordeveloper/kubeplay/rubykube/converter" 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type podClass struct { 13 | class *mruby.Class 14 | objects []podClassInstance 15 | rk *RubyKube 16 | } 17 | 18 | type podClassInstance struct { 19 | self *mruby.MrbValue 20 | vars *podClassInstanceVars 21 | } 22 | 23 | type podClassInstanceVars struct { 24 | pod podTypeAlias 25 | } 26 | 27 | func newPodClass(rk *RubyKube) *podClass { 28 | c := &podClass{objects: []podClassInstance{}, rk: rk} 29 | c.class = definePodClass(rk, c) 30 | return c 31 | } 32 | 33 | func definePodClass(rk *RubyKube, c *podClass) *mruby.Class { 34 | // common methods 35 | return rk.defineClass("Pod", map[string]methodDefintion{ 36 | "to_ruby": { 37 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 38 | vars, err := c.LookupVars(self) 39 | if err != nil { 40 | return nil, createException(m, err.Error()) 41 | } 42 | 43 | rbconv := converter.New(m) 44 | if err := rbconv.Convert(vars.pod); err != nil { 45 | return nil, createException(m, err.Error()) 46 | } 47 | 48 | return rbconv.Value(), nil 49 | }, 50 | instanceMethod, 51 | }, 52 | "to_json": { 53 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 54 | vars, err := c.LookupVars(self) 55 | if err != nil { 56 | return nil, createException(m, err.Error()) 57 | } 58 | return marshalToJSON(vars.pod, m) 59 | }, 60 | instanceMethod, 61 | }, 62 | "object_count": { 63 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 64 | return m.FixnumValue(len(c.objects)), nil 65 | }, 66 | classMethod, 67 | }, 68 | }) 69 | } 70 | 71 | func (c *podClass) New() (*podClassInstance, error) { 72 | s, err := c.class.New() 73 | if err != nil { 74 | return nil, err 75 | } 76 | o := podClassInstance{ 77 | self: s, 78 | vars: &podClassInstanceVars{ 79 | podTypeAlias{}, 80 | }, 81 | } 82 | c.objects = append(c.objects, o) 83 | return &o, nil 84 | } 85 | 86 | func (c *podClass) LookupVars(this *mruby.MrbValue) (*podClassInstanceVars, error) { 87 | for _, that := range c.objects { 88 | if *this == *that.self { 89 | return that.vars, nil 90 | } 91 | } 92 | return nil, fmt.Errorf("%s: could not find class instance", "Pod") 93 | } 94 | -------------------------------------------------------------------------------- /rubykube/gotemplate_podsClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/errordeveloper/kubeplay/rubykube/converter" 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type podsClass struct { 13 | class *mruby.Class 14 | objects []podsClassInstance 15 | rk *RubyKube 16 | } 17 | 18 | type podsClassInstance struct { 19 | self *mruby.MrbValue 20 | vars *podsClassInstanceVars 21 | } 22 | 23 | type podsClassInstanceVars struct { 24 | pods podListTypeAlias 25 | } 26 | 27 | func newPodsClass(rk *RubyKube) *podsClass { 28 | c := &podsClass{objects: []podsClassInstance{}, rk: rk} 29 | c.class = definePodsClass(rk, c) 30 | return c 31 | } 32 | 33 | func definePodsClass(rk *RubyKube, c *podsClass) *mruby.Class { 34 | // common methods 35 | return rk.defineClass("Pods", map[string]methodDefintion{ 36 | "to_ruby": { 37 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 38 | vars, err := c.LookupVars(self) 39 | if err != nil { 40 | return nil, createException(m, err.Error()) 41 | } 42 | 43 | rbconv := converter.New(m) 44 | if err := rbconv.Convert(vars.pods); err != nil { 45 | return nil, createException(m, err.Error()) 46 | } 47 | 48 | return rbconv.Value(), nil 49 | }, 50 | instanceMethod, 51 | }, 52 | "to_json": { 53 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 54 | vars, err := c.LookupVars(self) 55 | if err != nil { 56 | return nil, createException(m, err.Error()) 57 | } 58 | return marshalToJSON(vars.pods, m) 59 | }, 60 | instanceMethod, 61 | }, 62 | "object_count": { 63 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 64 | return m.FixnumValue(len(c.objects)), nil 65 | }, 66 | classMethod, 67 | }, 68 | }) 69 | } 70 | 71 | func (c *podsClass) New() (*podsClassInstance, error) { 72 | s, err := c.class.New() 73 | if err != nil { 74 | return nil, err 75 | } 76 | o := podsClassInstance{ 77 | self: s, 78 | vars: &podsClassInstanceVars{ 79 | podListTypeAlias{}, 80 | }, 81 | } 82 | c.objects = append(c.objects, o) 83 | return &o, nil 84 | } 85 | 86 | func (c *podsClass) LookupVars(this *mruby.MrbValue) (*podsClassInstanceVars, error) { 87 | for _, that := range c.objects { 88 | if *this == *that.self { 89 | return that.vars, nil 90 | } 91 | } 92 | return nil, fmt.Errorf("%s: could not find class instance", "Pods") 93 | } 94 | -------------------------------------------------------------------------------- /rubykube/resources_podClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | mruby "github.com/mitchellh/go-mruby" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | corev1 "k8s.io/api/core/v1" 7 | ) 8 | 9 | type podTypeAlias = corev1.Pod 10 | 11 | //go:generate gotemplate "./templates/resource" "podClass(\"Pod\", pod, podTypeAlias)" 12 | 13 | func (c *podClass) getSingleton(ns, name string) (*corev1.Pod, error) { 14 | return c.rk.clientset.Core().Pods(ns).Get(name, metav1.GetOptions{}) 15 | } 16 | 17 | //go:generate gotemplate "./templates/resource/singleton" "podSingletonModule(podClass, \"Pod\", pod, podTypeAlias)" 18 | 19 | func (c *podClass) defineOwnMethods() { 20 | c.defineSingletonMethods() 21 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 22 | "create!": { 23 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 24 | vars, err := c.LookupVars(self) 25 | if err != nil { 26 | return nil, createException(m, err.Error()) 27 | } 28 | 29 | pod := corev1.Pod(vars.pod) 30 | ns := c.rk.GetDefaultNamespace(pod.ObjectMeta.Namespace) 31 | 32 | if _, err = c.rk.clientset.Core().Pods(ns).Create(&pod); err != nil { 33 | return nil, createException(m, err.Error()) 34 | } 35 | 36 | return self, nil 37 | }, 38 | instanceMethod, 39 | }, 40 | "delete!": { 41 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 42 | vars, err := c.LookupVars(self) 43 | if err != nil { 44 | return nil, createException(m, err.Error()) 45 | } 46 | 47 | ns := c.rk.GetDefaultNamespace(vars.pod.ObjectMeta.Namespace) 48 | 49 | if err = c.rk.clientset.Core().Pods(ns).Delete(vars.pod.ObjectMeta.Name, &metav1.DeleteOptions{}); err != nil { 50 | return nil, createException(m, err.Error()) 51 | } 52 | 53 | return self, nil 54 | }, 55 | instanceMethod, 56 | }, 57 | "logs": { 58 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 59 | vars, err := c.LookupVars(self) 60 | if err != nil { 61 | return nil, createException(m, err.Error()) 62 | } 63 | 64 | newPodLogsObj, err := c.rk.classes.PodLogs.New() 65 | if err != nil { 66 | return nil, createException(m, err.Error()) 67 | } 68 | pod := corev1.Pod(vars.pod) 69 | newPodLogsObj.vars.pods = []corev1.Pod{pod} 70 | return callWithException(m, newPodLogsObj.self, "get!") 71 | }, 72 | instanceMethod, 73 | }, 74 | }) 75 | } 76 | 77 | func (o *podClassInstance) Update() (mruby.Value, error) { 78 | return call(o.self, "get!") 79 | } 80 | -------------------------------------------------------------------------------- /repl/repl.go: -------------------------------------------------------------------------------- 1 | package repl 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "strings" 8 | 9 | "github.com/chzyer/readline" 10 | "github.com/errordeveloper/kubeplay/rubykube" 11 | mruby "github.com/mitchellh/go-mruby" 12 | ) 13 | 14 | // Repl encapsulates a series of items used to create a read-evaluate-print 15 | // loop so that end users can play with quebes & pods. 16 | type Repl struct { 17 | rubykube *rubykube.RubyKube 18 | readline *readline.Instance 19 | } 20 | 21 | // NewRepl constructs a new Repl. 22 | func NewRepl() (*Repl, error) { 23 | rl, err := readline.New("kubeplay ()> ") 24 | if err != nil { 25 | return nil, err 26 | } 27 | 28 | rk, err := rubykube.NewRubyKube([]string{}, rl) 29 | if err != nil { 30 | rl.Close() 31 | return nil, err 32 | } 33 | 34 | return &Repl{rubykube: rk, readline: rl}, nil 35 | } 36 | 37 | // Loop runs the loop. Returns nil on io.EOF, otherwise errors are forwarded. 38 | func (r *Repl) Loop() error { 39 | defer func() { 40 | if err := recover(); err != nil { 41 | panic(fmt.Errorf("repl.Loop: %v", err)) 42 | } 43 | }() 44 | 45 | var line string 46 | var stackKeep int 47 | //var val *mruby.MrbValue 48 | 49 | parser := mruby.NewParser(r.rubykube.Mrb()) 50 | context := mruby.NewCompileContext(r.rubykube.Mrb()) 51 | context.CaptureErrors(true) 52 | 53 | for { 54 | tmp, err := r.readline.Readline() 55 | if err == io.EOF { 56 | return nil 57 | } 58 | 59 | if err != nil && err.Error() == "Interrupt" { 60 | if line != "" { 61 | r.rubykube.NormalPrompt() 62 | } else { 63 | fmt.Println("You can press ^D or type \"quit\", \"exit\" to exit the shell") 64 | } 65 | 66 | line = "" 67 | continue 68 | } 69 | 70 | if err != nil { 71 | fmt.Printf("+++ Error %#v\n", err) 72 | os.Exit(1) 73 | } 74 | 75 | line += tmp + "\n" 76 | 77 | switch strings.TrimSpace(line) { 78 | case "quit": 79 | fallthrough 80 | case "exit": 81 | os.Exit(0) 82 | case "help": 83 | fmt.Println("Please take a look at usage examples\n\t\thttps://github.com/errordeveloper/kubeplay/blob/master/README.md") 84 | } 85 | 86 | if _, err := parser.Parse(line, context); err != nil { 87 | r.rubykube.MultiLinePrompt() 88 | continue 89 | } 90 | 91 | _, stackKeep, err = r.rubykube.RunCode(parser.GenerateCode(), stackKeep) 92 | line = "" 93 | r.rubykube.NormalPrompt() 94 | if err != nil { 95 | fmt.Printf("+++ Error: %v\n", err) 96 | continue 97 | } 98 | 99 | //if val.String() != "" { 100 | // fmt.Println(val) 101 | //} 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /rubykube/gotemplate_serviceClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/errordeveloper/kubeplay/rubykube/converter" 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type serviceClass struct { 13 | class *mruby.Class 14 | objects []serviceClassInstance 15 | rk *RubyKube 16 | } 17 | 18 | type serviceClassInstance struct { 19 | self *mruby.MrbValue 20 | vars *serviceClassInstanceVars 21 | } 22 | 23 | type serviceClassInstanceVars struct { 24 | service serviceTypeAlias 25 | } 26 | 27 | func newServiceClass(rk *RubyKube) *serviceClass { 28 | c := &serviceClass{objects: []serviceClassInstance{}, rk: rk} 29 | c.class = defineServiceClass(rk, c) 30 | return c 31 | } 32 | 33 | func defineServiceClass(rk *RubyKube, c *serviceClass) *mruby.Class { 34 | // common methods 35 | return rk.defineClass("Service", map[string]methodDefintion{ 36 | "to_ruby": { 37 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 38 | vars, err := c.LookupVars(self) 39 | if err != nil { 40 | return nil, createException(m, err.Error()) 41 | } 42 | 43 | rbconv := converter.New(m) 44 | if err := rbconv.Convert(vars.service); err != nil { 45 | return nil, createException(m, err.Error()) 46 | } 47 | 48 | return rbconv.Value(), nil 49 | }, 50 | instanceMethod, 51 | }, 52 | "to_json": { 53 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 54 | vars, err := c.LookupVars(self) 55 | if err != nil { 56 | return nil, createException(m, err.Error()) 57 | } 58 | return marshalToJSON(vars.service, m) 59 | }, 60 | instanceMethod, 61 | }, 62 | "object_count": { 63 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 64 | return m.FixnumValue(len(c.objects)), nil 65 | }, 66 | classMethod, 67 | }, 68 | }) 69 | } 70 | 71 | func (c *serviceClass) New() (*serviceClassInstance, error) { 72 | s, err := c.class.New() 73 | if err != nil { 74 | return nil, err 75 | } 76 | o := serviceClassInstance{ 77 | self: s, 78 | vars: &serviceClassInstanceVars{ 79 | serviceTypeAlias{}, 80 | }, 81 | } 82 | c.objects = append(c.objects, o) 83 | return &o, nil 84 | } 85 | 86 | func (c *serviceClass) LookupVars(this *mruby.MrbValue) (*serviceClassInstanceVars, error) { 87 | for _, that := range c.objects { 88 | if *this == *that.self { 89 | return that.vars, nil 90 | } 91 | } 92 | return nil, fmt.Errorf("%s: could not find class instance", "Service") 93 | } 94 | -------------------------------------------------------------------------------- /rubykube/gotemplate_servicesClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/errordeveloper/kubeplay/rubykube/converter" 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type servicesClass struct { 13 | class *mruby.Class 14 | objects []servicesClassInstance 15 | rk *RubyKube 16 | } 17 | 18 | type servicesClassInstance struct { 19 | self *mruby.MrbValue 20 | vars *servicesClassInstanceVars 21 | } 22 | 23 | type servicesClassInstanceVars struct { 24 | services serviceListTypeAlias 25 | } 26 | 27 | func newServicesClass(rk *RubyKube) *servicesClass { 28 | c := &servicesClass{objects: []servicesClassInstance{}, rk: rk} 29 | c.class = defineServicesClass(rk, c) 30 | return c 31 | } 32 | 33 | func defineServicesClass(rk *RubyKube, c *servicesClass) *mruby.Class { 34 | // common methods 35 | return rk.defineClass("Services", map[string]methodDefintion{ 36 | "to_ruby": { 37 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 38 | vars, err := c.LookupVars(self) 39 | if err != nil { 40 | return nil, createException(m, err.Error()) 41 | } 42 | 43 | rbconv := converter.New(m) 44 | if err := rbconv.Convert(vars.services); err != nil { 45 | return nil, createException(m, err.Error()) 46 | } 47 | 48 | return rbconv.Value(), nil 49 | }, 50 | instanceMethod, 51 | }, 52 | "to_json": { 53 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 54 | vars, err := c.LookupVars(self) 55 | if err != nil { 56 | return nil, createException(m, err.Error()) 57 | } 58 | return marshalToJSON(vars.services, m) 59 | }, 60 | instanceMethod, 61 | }, 62 | "object_count": { 63 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 64 | return m.FixnumValue(len(c.objects)), nil 65 | }, 66 | classMethod, 67 | }, 68 | }) 69 | } 70 | 71 | func (c *servicesClass) New() (*servicesClassInstance, error) { 72 | s, err := c.class.New() 73 | if err != nil { 74 | return nil, err 75 | } 76 | o := servicesClassInstance{ 77 | self: s, 78 | vars: &servicesClassInstanceVars{ 79 | serviceListTypeAlias{}, 80 | }, 81 | } 82 | c.objects = append(c.objects, o) 83 | return &o, nil 84 | } 85 | 86 | func (c *servicesClass) LookupVars(this *mruby.MrbValue) (*servicesClassInstanceVars, error) { 87 | for _, that := range c.objects { 88 | if *this == *that.self { 89 | return that.vars, nil 90 | } 91 | } 92 | return nil, fmt.Errorf("%s: could not find class instance", "Services") 93 | } 94 | -------------------------------------------------------------------------------- /rubykube/gotemplate_daemonSetClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/errordeveloper/kubeplay/rubykube/converter" 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type daemonSetClass struct { 13 | class *mruby.Class 14 | objects []daemonSetClassInstance 15 | rk *RubyKube 16 | } 17 | 18 | type daemonSetClassInstance struct { 19 | self *mruby.MrbValue 20 | vars *daemonSetClassInstanceVars 21 | } 22 | 23 | type daemonSetClassInstanceVars struct { 24 | daemonSet daemonSetTypeAlias 25 | } 26 | 27 | func newDaemonSetClass(rk *RubyKube) *daemonSetClass { 28 | c := &daemonSetClass{objects: []daemonSetClassInstance{}, rk: rk} 29 | c.class = defineDaemonSetClass(rk, c) 30 | return c 31 | } 32 | 33 | func defineDaemonSetClass(rk *RubyKube, c *daemonSetClass) *mruby.Class { 34 | // common methods 35 | return rk.defineClass("DaemonSet", map[string]methodDefintion{ 36 | "to_ruby": { 37 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 38 | vars, err := c.LookupVars(self) 39 | if err != nil { 40 | return nil, createException(m, err.Error()) 41 | } 42 | 43 | rbconv := converter.New(m) 44 | if err := rbconv.Convert(vars.daemonSet); err != nil { 45 | return nil, createException(m, err.Error()) 46 | } 47 | 48 | return rbconv.Value(), nil 49 | }, 50 | instanceMethod, 51 | }, 52 | "to_json": { 53 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 54 | vars, err := c.LookupVars(self) 55 | if err != nil { 56 | return nil, createException(m, err.Error()) 57 | } 58 | return marshalToJSON(vars.daemonSet, m) 59 | }, 60 | instanceMethod, 61 | }, 62 | "object_count": { 63 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 64 | return m.FixnumValue(len(c.objects)), nil 65 | }, 66 | classMethod, 67 | }, 68 | }) 69 | } 70 | 71 | func (c *daemonSetClass) New() (*daemonSetClassInstance, error) { 72 | s, err := c.class.New() 73 | if err != nil { 74 | return nil, err 75 | } 76 | o := daemonSetClassInstance{ 77 | self: s, 78 | vars: &daemonSetClassInstanceVars{ 79 | daemonSetTypeAlias{}, 80 | }, 81 | } 82 | c.objects = append(c.objects, o) 83 | return &o, nil 84 | } 85 | 86 | func (c *daemonSetClass) LookupVars(this *mruby.MrbValue) (*daemonSetClassInstanceVars, error) { 87 | for _, that := range c.objects { 88 | if *this == *that.self { 89 | return that.vars, nil 90 | } 91 | } 92 | return nil, fmt.Errorf("%s: could not find class instance", "DaemonSet") 93 | } 94 | -------------------------------------------------------------------------------- /rubykube/gotemplate_deploymentClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/errordeveloper/kubeplay/rubykube/converter" 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type deploymentClass struct { 13 | class *mruby.Class 14 | objects []deploymentClassInstance 15 | rk *RubyKube 16 | } 17 | 18 | type deploymentClassInstance struct { 19 | self *mruby.MrbValue 20 | vars *deploymentClassInstanceVars 21 | } 22 | 23 | type deploymentClassInstanceVars struct { 24 | deployment deploymentTypeAlias 25 | } 26 | 27 | func newDeploymentClass(rk *RubyKube) *deploymentClass { 28 | c := &deploymentClass{objects: []deploymentClassInstance{}, rk: rk} 29 | c.class = defineDeploymentClass(rk, c) 30 | return c 31 | } 32 | 33 | func defineDeploymentClass(rk *RubyKube, c *deploymentClass) *mruby.Class { 34 | // common methods 35 | return rk.defineClass("Deployment", map[string]methodDefintion{ 36 | "to_ruby": { 37 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 38 | vars, err := c.LookupVars(self) 39 | if err != nil { 40 | return nil, createException(m, err.Error()) 41 | } 42 | 43 | rbconv := converter.New(m) 44 | if err := rbconv.Convert(vars.deployment); err != nil { 45 | return nil, createException(m, err.Error()) 46 | } 47 | 48 | return rbconv.Value(), nil 49 | }, 50 | instanceMethod, 51 | }, 52 | "to_json": { 53 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 54 | vars, err := c.LookupVars(self) 55 | if err != nil { 56 | return nil, createException(m, err.Error()) 57 | } 58 | return marshalToJSON(vars.deployment, m) 59 | }, 60 | instanceMethod, 61 | }, 62 | "object_count": { 63 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 64 | return m.FixnumValue(len(c.objects)), nil 65 | }, 66 | classMethod, 67 | }, 68 | }) 69 | } 70 | 71 | func (c *deploymentClass) New() (*deploymentClassInstance, error) { 72 | s, err := c.class.New() 73 | if err != nil { 74 | return nil, err 75 | } 76 | o := deploymentClassInstance{ 77 | self: s, 78 | vars: &deploymentClassInstanceVars{ 79 | deploymentTypeAlias{}, 80 | }, 81 | } 82 | c.objects = append(c.objects, o) 83 | return &o, nil 84 | } 85 | 86 | func (c *deploymentClass) LookupVars(this *mruby.MrbValue) (*deploymentClassInstanceVars, error) { 87 | for _, that := range c.objects { 88 | if *this == *that.self { 89 | return that.vars, nil 90 | } 91 | } 92 | return nil, fmt.Errorf("%s: could not find class instance", "Deployment") 93 | } 94 | -------------------------------------------------------------------------------- /rubykube/gotemplate_replicaSetClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/errordeveloper/kubeplay/rubykube/converter" 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type replicaSetClass struct { 13 | class *mruby.Class 14 | objects []replicaSetClassInstance 15 | rk *RubyKube 16 | } 17 | 18 | type replicaSetClassInstance struct { 19 | self *mruby.MrbValue 20 | vars *replicaSetClassInstanceVars 21 | } 22 | 23 | type replicaSetClassInstanceVars struct { 24 | replicaSet replicaSetTypeAlias 25 | } 26 | 27 | func newReplicaSetClass(rk *RubyKube) *replicaSetClass { 28 | c := &replicaSetClass{objects: []replicaSetClassInstance{}, rk: rk} 29 | c.class = defineReplicaSetClass(rk, c) 30 | return c 31 | } 32 | 33 | func defineReplicaSetClass(rk *RubyKube, c *replicaSetClass) *mruby.Class { 34 | // common methods 35 | return rk.defineClass("ReplicaSet", map[string]methodDefintion{ 36 | "to_ruby": { 37 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 38 | vars, err := c.LookupVars(self) 39 | if err != nil { 40 | return nil, createException(m, err.Error()) 41 | } 42 | 43 | rbconv := converter.New(m) 44 | if err := rbconv.Convert(vars.replicaSet); err != nil { 45 | return nil, createException(m, err.Error()) 46 | } 47 | 48 | return rbconv.Value(), nil 49 | }, 50 | instanceMethod, 51 | }, 52 | "to_json": { 53 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 54 | vars, err := c.LookupVars(self) 55 | if err != nil { 56 | return nil, createException(m, err.Error()) 57 | } 58 | return marshalToJSON(vars.replicaSet, m) 59 | }, 60 | instanceMethod, 61 | }, 62 | "object_count": { 63 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 64 | return m.FixnumValue(len(c.objects)), nil 65 | }, 66 | classMethod, 67 | }, 68 | }) 69 | } 70 | 71 | func (c *replicaSetClass) New() (*replicaSetClassInstance, error) { 72 | s, err := c.class.New() 73 | if err != nil { 74 | return nil, err 75 | } 76 | o := replicaSetClassInstance{ 77 | self: s, 78 | vars: &replicaSetClassInstanceVars{ 79 | replicaSetTypeAlias{}, 80 | }, 81 | } 82 | c.objects = append(c.objects, o) 83 | return &o, nil 84 | } 85 | 86 | func (c *replicaSetClass) LookupVars(this *mruby.MrbValue) (*replicaSetClassInstanceVars, error) { 87 | for _, that := range c.objects { 88 | if *this == *that.self { 89 | return that.vars, nil 90 | } 91 | } 92 | return nil, fmt.Errorf("%s: could not find class instance", "ReplicaSet") 93 | } 94 | -------------------------------------------------------------------------------- /rubykube/gotemplate_daemonSetsClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/errordeveloper/kubeplay/rubykube/converter" 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type daemonSetsClass struct { 13 | class *mruby.Class 14 | objects []daemonSetsClassInstance 15 | rk *RubyKube 16 | } 17 | 18 | type daemonSetsClassInstance struct { 19 | self *mruby.MrbValue 20 | vars *daemonSetsClassInstanceVars 21 | } 22 | 23 | type daemonSetsClassInstanceVars struct { 24 | daemonSets daemonSetListTypeAlias 25 | } 26 | 27 | func newDaemonSetsClass(rk *RubyKube) *daemonSetsClass { 28 | c := &daemonSetsClass{objects: []daemonSetsClassInstance{}, rk: rk} 29 | c.class = defineDaemonSetsClass(rk, c) 30 | return c 31 | } 32 | 33 | func defineDaemonSetsClass(rk *RubyKube, c *daemonSetsClass) *mruby.Class { 34 | // common methods 35 | return rk.defineClass("DaemonSets", map[string]methodDefintion{ 36 | "to_ruby": { 37 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 38 | vars, err := c.LookupVars(self) 39 | if err != nil { 40 | return nil, createException(m, err.Error()) 41 | } 42 | 43 | rbconv := converter.New(m) 44 | if err := rbconv.Convert(vars.daemonSets); err != nil { 45 | return nil, createException(m, err.Error()) 46 | } 47 | 48 | return rbconv.Value(), nil 49 | }, 50 | instanceMethod, 51 | }, 52 | "to_json": { 53 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 54 | vars, err := c.LookupVars(self) 55 | if err != nil { 56 | return nil, createException(m, err.Error()) 57 | } 58 | return marshalToJSON(vars.daemonSets, m) 59 | }, 60 | instanceMethod, 61 | }, 62 | "object_count": { 63 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 64 | return m.FixnumValue(len(c.objects)), nil 65 | }, 66 | classMethod, 67 | }, 68 | }) 69 | } 70 | 71 | func (c *daemonSetsClass) New() (*daemonSetsClassInstance, error) { 72 | s, err := c.class.New() 73 | if err != nil { 74 | return nil, err 75 | } 76 | o := daemonSetsClassInstance{ 77 | self: s, 78 | vars: &daemonSetsClassInstanceVars{ 79 | daemonSetListTypeAlias{}, 80 | }, 81 | } 82 | c.objects = append(c.objects, o) 83 | return &o, nil 84 | } 85 | 86 | func (c *daemonSetsClass) LookupVars(this *mruby.MrbValue) (*daemonSetsClassInstanceVars, error) { 87 | for _, that := range c.objects { 88 | if *this == *that.self { 89 | return that.vars, nil 90 | } 91 | } 92 | return nil, fmt.Errorf("%s: could not find class instance", "DaemonSets") 93 | } 94 | -------------------------------------------------------------------------------- /rubykube/gotemplate_deploymentsClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/errordeveloper/kubeplay/rubykube/converter" 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type deploymentsClass struct { 13 | class *mruby.Class 14 | objects []deploymentsClassInstance 15 | rk *RubyKube 16 | } 17 | 18 | type deploymentsClassInstance struct { 19 | self *mruby.MrbValue 20 | vars *deploymentsClassInstanceVars 21 | } 22 | 23 | type deploymentsClassInstanceVars struct { 24 | deployments deploymentListTypeAlias 25 | } 26 | 27 | func newDeploymentsClass(rk *RubyKube) *deploymentsClass { 28 | c := &deploymentsClass{objects: []deploymentsClassInstance{}, rk: rk} 29 | c.class = defineDeploymentsClass(rk, c) 30 | return c 31 | } 32 | 33 | func defineDeploymentsClass(rk *RubyKube, c *deploymentsClass) *mruby.Class { 34 | // common methods 35 | return rk.defineClass("Deployments", map[string]methodDefintion{ 36 | "to_ruby": { 37 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 38 | vars, err := c.LookupVars(self) 39 | if err != nil { 40 | return nil, createException(m, err.Error()) 41 | } 42 | 43 | rbconv := converter.New(m) 44 | if err := rbconv.Convert(vars.deployments); err != nil { 45 | return nil, createException(m, err.Error()) 46 | } 47 | 48 | return rbconv.Value(), nil 49 | }, 50 | instanceMethod, 51 | }, 52 | "to_json": { 53 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 54 | vars, err := c.LookupVars(self) 55 | if err != nil { 56 | return nil, createException(m, err.Error()) 57 | } 58 | return marshalToJSON(vars.deployments, m) 59 | }, 60 | instanceMethod, 61 | }, 62 | "object_count": { 63 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 64 | return m.FixnumValue(len(c.objects)), nil 65 | }, 66 | classMethod, 67 | }, 68 | }) 69 | } 70 | 71 | func (c *deploymentsClass) New() (*deploymentsClassInstance, error) { 72 | s, err := c.class.New() 73 | if err != nil { 74 | return nil, err 75 | } 76 | o := deploymentsClassInstance{ 77 | self: s, 78 | vars: &deploymentsClassInstanceVars{ 79 | deploymentListTypeAlias{}, 80 | }, 81 | } 82 | c.objects = append(c.objects, o) 83 | return &o, nil 84 | } 85 | 86 | func (c *deploymentsClass) LookupVars(this *mruby.MrbValue) (*deploymentsClassInstanceVars, error) { 87 | for _, that := range c.objects { 88 | if *this == *that.self { 89 | return that.vars, nil 90 | } 91 | } 92 | return nil, fmt.Errorf("%s: could not find class instance", "Deployments") 93 | } 94 | -------------------------------------------------------------------------------- /rubykube/gotemplate_replicaSetsClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/errordeveloper/kubeplay/rubykube/converter" 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type replicaSetsClass struct { 13 | class *mruby.Class 14 | objects []replicaSetsClassInstance 15 | rk *RubyKube 16 | } 17 | 18 | type replicaSetsClassInstance struct { 19 | self *mruby.MrbValue 20 | vars *replicaSetsClassInstanceVars 21 | } 22 | 23 | type replicaSetsClassInstanceVars struct { 24 | replicaSets replicaSetListTypeAlias 25 | } 26 | 27 | func newReplicaSetsClass(rk *RubyKube) *replicaSetsClass { 28 | c := &replicaSetsClass{objects: []replicaSetsClassInstance{}, rk: rk} 29 | c.class = defineReplicaSetsClass(rk, c) 30 | return c 31 | } 32 | 33 | func defineReplicaSetsClass(rk *RubyKube, c *replicaSetsClass) *mruby.Class { 34 | // common methods 35 | return rk.defineClass("ReplicaSets", map[string]methodDefintion{ 36 | "to_ruby": { 37 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 38 | vars, err := c.LookupVars(self) 39 | if err != nil { 40 | return nil, createException(m, err.Error()) 41 | } 42 | 43 | rbconv := converter.New(m) 44 | if err := rbconv.Convert(vars.replicaSets); err != nil { 45 | return nil, createException(m, err.Error()) 46 | } 47 | 48 | return rbconv.Value(), nil 49 | }, 50 | instanceMethod, 51 | }, 52 | "to_json": { 53 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 54 | vars, err := c.LookupVars(self) 55 | if err != nil { 56 | return nil, createException(m, err.Error()) 57 | } 58 | return marshalToJSON(vars.replicaSets, m) 59 | }, 60 | instanceMethod, 61 | }, 62 | "object_count": { 63 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 64 | return m.FixnumValue(len(c.objects)), nil 65 | }, 66 | classMethod, 67 | }, 68 | }) 69 | } 70 | 71 | func (c *replicaSetsClass) New() (*replicaSetsClassInstance, error) { 72 | s, err := c.class.New() 73 | if err != nil { 74 | return nil, err 75 | } 76 | o := replicaSetsClassInstance{ 77 | self: s, 78 | vars: &replicaSetsClassInstanceVars{ 79 | replicaSetListTypeAlias{}, 80 | }, 81 | } 82 | c.objects = append(c.objects, o) 83 | return &o, nil 84 | } 85 | 86 | func (c *replicaSetsClass) LookupVars(this *mruby.MrbValue) (*replicaSetsClassInstanceVars, error) { 87 | for _, that := range c.objects { 88 | if *this == *that.self { 89 | return that.vars, nil 90 | } 91 | } 92 | return nil, fmt.Errorf("%s: could not find class instance", "ReplicaSets") 93 | } 94 | -------------------------------------------------------------------------------- /rubykube/templates/resource/template.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/errordeveloper/kubeplay/rubykube/converter" 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type classNameString string 13 | type instanceVariableName int 14 | type instanceVariableType int 15 | 16 | type RubyKubeClass struct { 17 | class *mruby.Class 18 | objects []RubyKubeClassInstance 19 | rk *RubyKube 20 | } 21 | 22 | type RubyKubeClassInstance struct { 23 | self *mruby.MrbValue 24 | vars *RubyKubeClassInstanceVars 25 | } 26 | 27 | type RubyKubeClassInstanceVars struct { 28 | instanceVariableName instanceVariableType 29 | } 30 | 31 | func NewRubyKubeClass(rk *RubyKube) *RubyKubeClass { 32 | c := &RubyKubeClass{objects: []RubyKubeClassInstance{}, rk: rk} 33 | c.class = DefineRubyKubeClass(rk, c) 34 | return c 35 | } 36 | 37 | func DefineRubyKubeClass(rk *RubyKube, c *RubyKubeClass) *mruby.Class { 38 | // common methods 39 | return rk.defineClass(classNameString, map[string]methodDefintion{ 40 | "to_ruby": { 41 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 42 | vars, err := c.LookupVars(self) 43 | if err != nil { 44 | return nil, createException(m, err.Error()) 45 | } 46 | 47 | rbconv := converter.New(m) 48 | if err := rbconv.Convert(vars.instanceVariableName); err != nil { 49 | return nil, createException(m, err.Error()) 50 | } 51 | 52 | return rbconv.Value(), nil 53 | }, 54 | instanceMethod, 55 | }, 56 | "to_json": { 57 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 58 | vars, err := c.LookupVars(self) 59 | if err != nil { 60 | return nil, createException(m, err.Error()) 61 | } 62 | return marshalToJSON(vars.instanceVariableName, m) 63 | }, 64 | instanceMethod, 65 | }, 66 | "object_count": { 67 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 68 | return m.FixnumValue(len(c.objects)), nil 69 | }, 70 | classMethod, 71 | }, 72 | }) 73 | } 74 | 75 | func (c *RubyKubeClass) New() (*RubyKubeClassInstance, error) { 76 | s, err := c.class.New() 77 | if err != nil { 78 | return nil, err 79 | } 80 | o := RubyKubeClassInstance{ 81 | self: s, 82 | vars: &RubyKubeClassInstanceVars{ 83 | instanceVariableType{}, 84 | }, 85 | } 86 | c.objects = append(c.objects, o) 87 | return &o, nil 88 | } 89 | 90 | func (c *RubyKubeClass) LookupVars(this *mruby.MrbValue) (*RubyKubeClassInstanceVars, error) { 91 | for _, that := range c.objects { 92 | if *this == *that.self { 93 | return that.vars, nil 94 | } 95 | } 96 | return nil, fmt.Errorf("%s: could not find class instance", classNameString) 97 | } 98 | -------------------------------------------------------------------------------- /rubykube/funcs.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | /* 4 | funcs.go provides simple functions for use within rk that do *not* 5 | They are intended to be used as gathering functions for predicates and templating. 6 | */ 7 | 8 | import ( 9 | _ "fmt" 10 | "io/ioutil" 11 | "os" 12 | _ "strings" 13 | 14 | mruby "github.com/mitchellh/go-mruby" 15 | ) 16 | 17 | type funcDefinition struct { 18 | fun funcFunc 19 | argSpec mruby.ArgSpec 20 | } 21 | 22 | type funcFunc func(rk *RubyKube, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) 23 | 24 | // mrubyJumpTable is the dispatch instructions sent to the mruby interpreter at rk setup. 25 | var funcJumpTable = map[string]funcDefinition{ 26 | "load": {loadFunc, mruby.ArgsReq(1)}, 27 | "getenv": {getenv, mruby.ArgsReq(1)}, 28 | } 29 | 30 | // loadFunc implements the load function. 31 | // 32 | // load loads a new ruby file at the point of the function call. it is 33 | // principally used to extend and consolidate reusable code. 34 | func loadFunc(rk *RubyKube, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 35 | args := m.GetArgs() 36 | if err := checkArgs(args, 1); err != nil { 37 | return nil, createException(m, err.Error()) 38 | } 39 | 40 | content, err := ioutil.ReadFile(args[0].String()) 41 | if err != nil { 42 | return nil, createException(m, err.Error()) 43 | } 44 | 45 | val, err := rk.Run(string(content)) 46 | if err != nil { 47 | return nil, createException(m, err.Error()) 48 | } 49 | 50 | return val, nil 51 | } 52 | 53 | // getenv retrieves a value from the environment (passed in as string) 54 | // and returns a string with the value. If no value exists, an empty string is 55 | // returned. 56 | func getenv(rk *RubyKube, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 57 | args := m.GetArgs() 58 | 59 | if err := standardCheck(rk, args, 1); err != nil { 60 | return nil, createException(m, err.Error()) 61 | } 62 | 63 | return mruby.String(os.Getenv(args[0].String())), nil 64 | } 65 | 66 | const ( 67 | classMethod = iota 68 | instanceMethod 69 | ) 70 | 71 | type methodDefintion struct { 72 | argSpec mruby.ArgSpec 73 | methodFunc mruby.Func 74 | methodType int 75 | } 76 | 77 | func emptyMethod() methodDefintion { 78 | return methodDefintion{ 79 | mruby.ArgsAny(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 80 | return nil, nil 81 | }, 82 | instanceMethod, 83 | } 84 | } 85 | 86 | func (rk *RubyKube) defineClass(name string, methods map[string]methodDefintion) *mruby.Class { 87 | class := rk.mrb.DefineClass(name, rk.classes.Root) 88 | rk.appendMethods(class, methods) 89 | return class 90 | } 91 | 92 | func (rk *RubyKube) appendMethods(class *mruby.Class, methods map[string]methodDefintion) { 93 | for name, m := range methods { 94 | if m.methodType == classMethod { 95 | class.DefineClassMethod(name, m.methodFunc, m.argSpec) 96 | } else { 97 | class.DefineMethod(name, m.methodFunc, m.argSpec) 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /rubykube/helpers_fieldCollectorClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | type fieldCollectorClassInstanceVars struct { 10 | fields []fieldExpression 11 | eval func() error 12 | } 13 | 14 | func newFieldCollectorClassInstanceVars(c *fieldCollectorClass, s *mruby.MrbValue, args ...mruby.Value) (*fieldCollectorClassInstanceVars, error) { 15 | if len(args) != 1 { 16 | return nil, fmt.Errorf("Exactly one argument must supplied") 17 | } 18 | 19 | if args[0].MrbValue(c.rk.mrb).Type() != mruby.TypeProc { 20 | return nil, fmt.Errorf("Block must be given") 21 | } 22 | 23 | o := &fieldCollectorClassInstanceVars{ 24 | fields: []fieldExpression{}, 25 | eval: func() error { 26 | if _, err := s.CallBlock("instance_eval", args[0]); err != nil { 27 | return err 28 | } 29 | return nil 30 | }, 31 | } 32 | for _, v := range wellKnownLabels { 33 | // could do this, but it won't work cause we need to set onMatch somehow... 34 | // c.rk.mrb.LoadString(fmt.Sprintf("@%s = RubyKube::LabelKey.new(%s)", v, v)) 35 | variableName, keyName := c.rk.mrb.StringValue("@"+v), c.rk.mrb.StringValue(v) 36 | 37 | l, err := c.rk.classes.LabelKey.New(keyName) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | l.vars.onMatch = func(e labelExpression) { return } 43 | 44 | if _, err := s.Call("instance_variable_set", variableName, l.self); err != nil { 45 | return nil, err 46 | } 47 | } 48 | 49 | return o, nil 50 | } 51 | 52 | //go:generate gotemplate "./templates/basic" "fieldCollectorClass(\"FieldCollector\", newFieldCollectorClassInstanceVars, fieldCollectorClassInstanceVars)" 53 | 54 | func (c *fieldCollectorClass) makeFieldMethod() methodDefintion { 55 | return methodDefintion{ 56 | mruby.ArgsReq(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 57 | vars, err := c.LookupVars(self) 58 | if err != nil { 59 | return nil, createException(m, err.Error()) 60 | } 61 | 62 | newFieldKeyObj, err := c.rk.classes.FieldKey.New(toValues(m.GetArgs())...) 63 | if err != nil { 64 | return nil, createException(m, err.Error()) 65 | } 66 | 67 | // let it append to my fields 68 | newFieldKeyObj.vars.onMatch = func(e fieldExpression) { vars.fields = append(vars.fields, e) } 69 | 70 | return newFieldKeyObj.self, nil 71 | }, 72 | instanceMethod, 73 | } 74 | } 75 | 76 | func (c *fieldCollectorClass) makeLableMethod() methodDefintion { 77 | return methodDefintion{ 78 | mruby.ArgsAny(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 79 | newLabelKeyObj, err := c.rk.classes.LabelKey.New(toValues(m.GetArgs())...) 80 | if err != nil { 81 | return nil, createException(m, err.Error()) 82 | } 83 | 84 | newLabelKeyObj.vars.onMatch = func(_ labelExpression) { return } 85 | 86 | return newLabelKeyObj.self, nil 87 | }, 88 | instanceMethod, 89 | } 90 | } 91 | 92 | func (c *fieldCollectorClass) defineOwnMethods() { 93 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 94 | "field": c.makeFieldMethod(), 95 | "label": c.makeLableMethod(), 96 | "method_missing": c.makeFieldMethod(), 97 | }) 98 | } 99 | -------------------------------------------------------------------------------- /rubykube/helpers_labelCollectorClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | 6 | mruby "github.com/mitchellh/go-mruby" 7 | ) 8 | 9 | type labelCollectorClassInstanceVars struct { 10 | labels []labelExpression 11 | eval func() error 12 | } 13 | 14 | var wellKnownLabels = []string{ 15 | "app", 16 | "name", 17 | "org", 18 | "owner", 19 | "project", 20 | "revision", 21 | "service", 22 | "team", 23 | "tier", 24 | "v", 25 | "version", 26 | } 27 | 28 | func newLabelCollectorClassInstanceVars(c *labelCollectorClass, s *mruby.MrbValue, args ...mruby.Value) (*labelCollectorClassInstanceVars, error) { 29 | if len(args) != 1 { 30 | return nil, fmt.Errorf("Exactly one argument must supplied") 31 | } 32 | 33 | if args[0].MrbValue(c.rk.mrb).Type() != mruby.TypeProc { 34 | return nil, fmt.Errorf("Block must be given") 35 | } 36 | 37 | o := &labelCollectorClassInstanceVars{ 38 | labels: []labelExpression{}, 39 | eval: func() error { 40 | if _, err := s.CallBlock("instance_eval", args[0]); err != nil { 41 | return err 42 | } 43 | return nil 44 | }, 45 | } 46 | 47 | for _, v := range wellKnownLabels { 48 | // could do this, but it won't work cause we need to set onMatch somehow... 49 | // c.rk.mrb.LoadString(fmt.Sprintf("@%s = RubyKube::LabelKey.new(%s)", v, v)) 50 | variableName, keyName := c.rk.mrb.StringValue("@"+v), c.rk.mrb.StringValue(v) 51 | 52 | l, err := c.rk.classes.LabelKey.New(keyName) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | l.vars.onMatch = func(e labelExpression) { 58 | o.labels = append(o.labels, e) 59 | } 60 | 61 | if _, err := s.Call("instance_variable_set", variableName, l.self); err != nil { 62 | return nil, err 63 | } 64 | } 65 | 66 | return o, nil 67 | } 68 | 69 | //go:generate gotemplate "./templates/basic" "labelCollectorClass(\"LabelCollector\", newLabelCollectorClassInstanceVars, labelCollectorClassInstanceVars)" 70 | 71 | func (c *labelCollectorClass) makeLableMethod() methodDefintion { 72 | return methodDefintion{ 73 | mruby.ArgsReq(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 74 | vars, err := c.LookupVars(self) 75 | if err != nil { 76 | return nil, createException(m, err.Error()) 77 | } 78 | 79 | newLabelKeyObj, err := c.rk.classes.LabelKey.New(toValues(m.GetArgs())...) 80 | if err != nil { 81 | return nil, createException(m, err.Error()) 82 | } 83 | 84 | // let it append to my labels 85 | newLabelKeyObj.vars.onMatch = func(e labelExpression) { 86 | vars.labels = append(vars.labels, e) 87 | } 88 | 89 | return newLabelKeyObj.self, nil 90 | }, 91 | instanceMethod, 92 | } 93 | } 94 | 95 | func (c *labelCollectorClass) makeFieldMethod() methodDefintion { 96 | return methodDefintion{ 97 | mruby.ArgsReq(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 98 | newFieldKeyObj, err := c.rk.classes.FieldKey.New(toValues(m.GetArgs())...) 99 | if err != nil { 100 | return nil, createException(m, err.Error()) 101 | } 102 | 103 | newFieldKeyObj.vars.onMatch = func(_ fieldExpression) { return } 104 | 105 | return newFieldKeyObj.self, nil 106 | }, 107 | instanceMethod, 108 | } 109 | } 110 | 111 | func (c *labelCollectorClass) defineOwnMethods() { 112 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 113 | "field": c.makeFieldMethod(), 114 | "label": c.makeLableMethod(), 115 | "method_missing": c.makeLableMethod(), 116 | }) 117 | } 118 | -------------------------------------------------------------------------------- /rubykube/helpers_labelKeyClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | type labelExpression struct { 11 | key string 12 | operator string 13 | values []string 14 | } 15 | 16 | type labelMatchFunc func(labelExpression) 17 | 18 | type labelKeyClassInstanceVars struct { 19 | name string 20 | onMatch labelMatchFunc 21 | } 22 | 23 | func newLabelKeyClassInstanceVars(c *labelKeyClass, s *mruby.MrbValue, args ...mruby.Value) (*labelKeyClassInstanceVars, error) { 24 | if len(args) != 1 { 25 | return nil, fmt.Errorf("Exactly one argument must supplied") 26 | } 27 | 28 | o := &labelKeyClassInstanceVars{ 29 | name: args[0].MrbValue(s.Mrb()).String(), 30 | onMatch: func(e labelExpression) { 31 | panic("Too early too call me!") 32 | }, 33 | } 34 | return o, nil 35 | } 36 | 37 | //go:generate gotemplate "./templates/basic" "labelKeyClass(\"LabelKey\", newLabelKeyClassInstanceVars, labelKeyClassInstanceVars)" 38 | 39 | func (c *labelKeyClass) makeMatchMethod(operator string) methodDefintion { 40 | return methodDefintion{ 41 | mruby.ArgsReq(0) | mruby.ArgsOpt(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 42 | vars, err := c.LookupVars(self) 43 | if err != nil { 44 | return nil, createException(m, err.Error()) 45 | } 46 | 47 | e := labelExpression{key: vars.name, operator: operator, values: []string{}} 48 | 49 | if err := c.appendSetExpression(&e.values, m.GetArgs()...); err != nil { 50 | return nil, createException(m, err.Error()) 51 | } 52 | 53 | vars.onMatch(e) 54 | 55 | return nil, nil 56 | }, 57 | instanceMethod, 58 | } 59 | } 60 | 61 | func (c *labelKeyClass) appendSetExpression(values *[]string, args ...*mruby.MrbValue) error { 62 | for _, m := range args { 63 | switch m.Type() { 64 | case mruby.TypeArray: 65 | if err := iterateArray(m, func(i int, v *mruby.MrbValue) error { 66 | if err := c.appendSetExpression(values, v); err != nil { 67 | return nil 68 | } 69 | return nil 70 | }); err != nil { 71 | return err 72 | } 73 | case mruby.TypeHash: 74 | return fmt.Errorf("a hash is an invalid type for label value set expression") 75 | default: 76 | s := m.String() 77 | if strings.TrimSpace(s) == "" { 78 | return fmt.Errorf("found an invalid string %q", s) 79 | } 80 | *values = append(*values, s) 81 | } 82 | } 83 | return nil 84 | } 85 | 86 | func (c *labelKeyClass) defineOwnMethods() { 87 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 88 | "=~": c.makeMatchMethod("in"), 89 | "==": c.makeMatchMethod("in"), 90 | "in": c.makeMatchMethod("in"), 91 | "in?": c.makeMatchMethod("in"), 92 | "is_in": c.makeMatchMethod("in"), 93 | "is_in?": c.makeMatchMethod("in"), 94 | "!~": c.makeMatchMethod("notin"), 95 | "!=": c.makeMatchMethod("notin"), 96 | "notin": c.makeMatchMethod("notin"), 97 | "notin?": c.makeMatchMethod("notin"), 98 | "not_in": c.makeMatchMethod("notin"), 99 | "not_in?": c.makeMatchMethod("notin"), 100 | "is_not_in": c.makeMatchMethod("notin"), 101 | "is_not_in?": c.makeMatchMethod("notin"), 102 | "any?": c.makeMatchMethod(""), 103 | "is_set?": c.makeMatchMethod(""), 104 | "defined?": c.makeMatchMethod(""), 105 | "present?": c.makeMatchMethod(""), 106 | "anything?": c.makeMatchMethod(""), 107 | "is_present?": c.makeMatchMethod(""), 108 | "method_missing": emptyMethod(), 109 | }) 110 | } 111 | -------------------------------------------------------------------------------- /rubykube/helpers_fieldKeyClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | type fieldExpression struct { 11 | key string 12 | operator string 13 | values []string 14 | } 15 | 16 | type fieldMatchFunc func(fieldExpression) 17 | 18 | type fieldKeyClassInstanceVars struct { 19 | name []string 20 | onMatch fieldMatchFunc 21 | } 22 | 23 | func newFieldKeyClassInstanceVars(c *fieldKeyClass, s *mruby.MrbValue, args ...mruby.Value) (*fieldKeyClassInstanceVars, error) { 24 | o := &fieldKeyClassInstanceVars{ 25 | name: []string{}, 26 | onMatch: func(e fieldExpression) { 27 | panic("Too early too call me!") 28 | }, 29 | } 30 | 31 | if len(args) > 0 { 32 | for _, v := range args { 33 | o.name = append(o.name, v.MrbValue(s.Mrb()).String()) 34 | } 35 | } 36 | 37 | return o, nil 38 | } 39 | 40 | //go:generate gotemplate "./templates/basic" "fieldKeyClass(\"FieldKey\", newFieldKeyClassInstanceVars, fieldKeyClassInstanceVars)" 41 | 42 | func (c *fieldKeyClass) makeMatchMethod(operator string) methodDefintion { 43 | return methodDefintion{ 44 | mruby.ArgsReq(0) | mruby.ArgsOpt(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 45 | vars, err := c.LookupVars(self) 46 | if err != nil { 47 | return nil, createException(m, err.Error()) 48 | } 49 | 50 | e := fieldExpression{key: strings.Join(vars.name, "."), operator: operator, values: []string{}} 51 | 52 | if err := c.appendSetExpression(&e.values, m.GetArgs()...); err != nil { 53 | return nil, createException(m, err.Error()) 54 | } 55 | 56 | vars.onMatch(e) 57 | 58 | return nil, nil 59 | }, 60 | instanceMethod, 61 | } 62 | } 63 | 64 | func (c *fieldKeyClass) appendSetExpression(values *[]string, args ...*mruby.MrbValue) error { 65 | for _, m := range args { 66 | switch m.Type() { 67 | case mruby.TypeArray: 68 | if err := iterateArray(m, func(i int, v *mruby.MrbValue) error { 69 | if err := c.appendSetExpression(values, v); err != nil { 70 | return nil 71 | } 72 | return nil 73 | }); err != nil { 74 | return err 75 | } 76 | case mruby.TypeHash: 77 | return fmt.Errorf("a hash is an invalid type for field value expression") 78 | default: 79 | s := m.String() 80 | if strings.TrimSpace(s) == "" { 81 | return fmt.Errorf("found an invalid string %q", s) 82 | } 83 | *values = append(*values, s) 84 | } 85 | } 86 | return nil 87 | } 88 | 89 | func (c *fieldKeyClass) defineOwnMethods() { 90 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 91 | "=~": c.makeMatchMethod("=="), 92 | "==": c.makeMatchMethod("=="), 93 | "!~": c.makeMatchMethod("!="), 94 | "!=": c.makeMatchMethod("!="), 95 | "to_s": { 96 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 97 | vars, err := c.LookupVars(self) 98 | if err != nil { 99 | return nil, createException(m, err.Error()) 100 | } 101 | 102 | return m.StringValue(strings.Join(vars.name, ".")), nil 103 | }, 104 | instanceMethod, 105 | }, 106 | "method_missing": { 107 | mruby.ArgsReq(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 108 | vars, err := c.LookupVars(self) 109 | if err != nil { 110 | return nil, createException(m, err.Error()) 111 | } 112 | 113 | newFieldKeyObj, err := c.New(toValues(m.GetArgs())...) 114 | if err != nil { 115 | return nil, createException(m, err.Error()) 116 | } 117 | 118 | newFieldKeyObj.vars.name = append(vars.name, newFieldKeyObj.vars.name...) 119 | newFieldKeyObj.vars.onMatch = vars.onMatch 120 | 121 | return newFieldKeyObj.self, nil 122 | }, 123 | instanceMethod, 124 | }, 125 | }) 126 | } 127 | -------------------------------------------------------------------------------- /rubykube/helpers_podMakerClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | corev1 "k8s.io/api/core/v1" 10 | ) 11 | 12 | type podMakerClassInstanceVars struct { 13 | pod *mruby.MrbValue 14 | } 15 | 16 | func newPodMakerClassInstanceVars(c *podMakerClass, s *mruby.MrbValue, args ...mruby.Value) (*podMakerClassInstanceVars, error) { 17 | return &podMakerClassInstanceVars{nil}, nil 18 | } 19 | 20 | //go:generate gotemplate "./templates/basic" "podMakerClass(\"PodMaker\", newPodMakerClassInstanceVars, podMakerClassInstanceVars)" 21 | 22 | func (c *podMakerClass) defineOwnMethods() { 23 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 24 | "pod!": { 25 | mruby.ArgsReq(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 26 | vars, err := c.LookupVars(self) 27 | if err != nil { 28 | return nil, createException(m, err.Error()) 29 | } 30 | 31 | args := m.GetArgs() 32 | if err := standardCheck(c.rk, args, 1); err != nil { 33 | return nil, createException(m, err.Error()) 34 | } 35 | 36 | if args[0].Type() != mruby.TypeHash { 37 | return nil, createException(m, "First argument must be a hash") 38 | } 39 | 40 | // TODO: handle arrays of hashes, for multi-container pods 41 | stringParamsCol, err := NewParamsCollection(args[0], 42 | params{ 43 | allowed: []string{"image", "name", "namespace"}, 44 | required: []string{"image"}, 45 | skipKnown: []string{"labels", "env", "command"}, 46 | valueType: mruby.TypeString, 47 | }, 48 | ) 49 | 50 | if err != nil { 51 | return nil, createException(m, err.Error()) 52 | } 53 | 54 | stringParams := stringParamsCol.ToMapOfStrings() 55 | 56 | hashParamsCol, err := NewParamsCollection(args[0], 57 | params{ 58 | allowed: []string{"labels", "env"}, 59 | required: []string{}, 60 | skipKnown: []string{"image", "name", "namespace", "command"}, 61 | valueType: mruby.TypeHash, 62 | }, 63 | ) 64 | 65 | if err != nil { 66 | return nil, createException(m, err.Error()) 67 | } 68 | 69 | arrayParamsCol, err := NewParamsCollection(args[0], 70 | params{ 71 | allowed: []string{"command"}, 72 | required: []string{}, 73 | skipKnown: []string{"image", "name", "namespace", "labels", "env"}, 74 | valueType: mruby.TypeArray, 75 | }, 76 | ) 77 | 78 | if err != nil { 79 | return nil, createException(m, err.Error()) 80 | } 81 | 82 | fmt.Printf("stringParams=%+v\nhashParams=%+v\narrayParams=%+v\n", stringParams, hashParamsCol.ToMapOfMapsOfStrings(), arrayParamsCol.ToMapOfSlicesOfStrings()) 83 | 84 | container := corev1.Container{} 85 | var name string 86 | 87 | // `hashArgsToSimpleMap` will validate that "image" key was given, so we don't need to 88 | // check for it; we try to split it into parts to determine the name automatically 89 | container.Image = stringParams["image"] 90 | imageParts := strings.Split(strings.Split(container.Image, ":")[0], "/") 91 | name = imageParts[len(imageParts)-1] 92 | 93 | // if name was given, use it to override automatic name we determined from the image 94 | if v, ok := stringParams["name"]; ok { 95 | name = v 96 | } 97 | 98 | container.Name = name 99 | labels := map[string]string{"name": name} 100 | 101 | newPodObj, err := c.rk.classes.Pod.New() 102 | if err != nil { 103 | return nil, createException(m, err.Error()) 104 | } 105 | 106 | pod := corev1.Pod{ 107 | ObjectMeta: metav1.ObjectMeta{ 108 | Name: name, 109 | Labels: labels, 110 | }, 111 | Spec: corev1.PodSpec{ 112 | Containers: []corev1.Container{container}, 113 | }, 114 | } 115 | 116 | if v, ok := stringParams["namespace"]; ok { 117 | pod.ObjectMeta.Namespace = v 118 | } 119 | 120 | newPodObj.vars.pod = podTypeAlias(pod) 121 | 122 | vars.pod = newPodObj.self 123 | return vars.pod, nil 124 | }, 125 | instanceMethod, 126 | }, 127 | }) 128 | } 129 | 130 | func (o *podMakerClassInstance) Update(args ...mruby.Value) (mruby.Value, error) { 131 | return nil, nil 132 | } 133 | -------------------------------------------------------------------------------- /rubykube/helpers_podLogsClass.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "io" 8 | "regexp" 9 | 10 | mruby "github.com/mitchellh/go-mruby" 11 | corev1 "k8s.io/api/core/v1" 12 | ) 13 | 14 | type podLogsClassInstanceVars struct { 15 | pods []corev1.Pod 16 | logs map[string]*bytes.Buffer 17 | } 18 | 19 | func newPodLogsClassInstanceVars(c *podLogsClass, s *mruby.MrbValue, args ...mruby.Value) (*podLogsClassInstanceVars, error) { 20 | return &podLogsClassInstanceVars{logs: make(map[string]*bytes.Buffer)}, nil 21 | } 22 | 23 | //go:generate gotemplate "./templates/basic" "podLogsClass(\"PodLogs\", newPodLogsClassInstanceVars, podLogsClassInstanceVars)" 24 | 25 | func (c *podLogsClass) defineOwnMethods() { 26 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 27 | "get!": { 28 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 29 | vars, err := c.LookupVars(self) 30 | if err != nil { 31 | return nil, createException(m, err.Error()) 32 | } 33 | 34 | for _, pod := range vars.pods { 35 | logBuffer := bytes.Buffer{} 36 | 37 | for _, container := range pod.Spec.Containers { 38 | name := fmt.Sprintf("%s/%s:%s", pod.ObjectMeta.Namespace, pod.ObjectMeta.Name, container.Name) 39 | stream, err := c.rk.clientset.Core().Pods(pod.ObjectMeta.Namespace).GetLogs(pod.ObjectMeta.Name, &corev1.PodLogOptions{Container: container.Name}).Stream() 40 | if err != nil { 41 | return nil, createException(m, err.Error()) 42 | } 43 | defer stream.Close() 44 | io.Copy(&logBuffer, stream) 45 | vars.logs[name] = &logBuffer 46 | } 47 | } 48 | return self, nil 49 | }, 50 | instanceMethod, 51 | }, 52 | "to_s": { 53 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 54 | //vars, err := c.LookupVars(self) 55 | //if err != nil { 56 | // return nil, createException(m, err.Error()) 57 | //} 58 | 59 | return self, nil 60 | }, 61 | instanceMethod, 62 | }, 63 | "puts": { 64 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 65 | vars, err := c.LookupVars(self) 66 | if err != nil { 67 | return nil, createException(m, err.Error()) 68 | } 69 | 70 | for name, logBuffer := range vars.logs { 71 | scanner := bufio.NewScanner(logBuffer) 72 | for scanner.Scan() { 73 | fmt.Printf("[%s] %s\n", name, scanner.Text()) 74 | } 75 | if err := scanner.Err(); err != nil { 76 | return nil, createException(m, err.Error()) 77 | } 78 | } 79 | 80 | return self, nil 81 | }, 82 | instanceMethod, 83 | }, 84 | "grep": { 85 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 86 | vars, err := c.LookupVars(self) 87 | if err != nil { 88 | return nil, createException(m, err.Error()) 89 | } 90 | 91 | args := m.GetArgs() 92 | 93 | if len(args) == 0 { 94 | return nil, createException(m, "At least one argument must be specified") 95 | } 96 | 97 | matchAgainst := []*regexp.Regexp{} 98 | for _, arg := range args { 99 | if arg.Type() == mruby.TypeString { 100 | re, err := regexp.Compile(arg.String()) 101 | if err != nil { 102 | return nil, createException(m, err.Error()) 103 | } 104 | matchAgainst = append(matchAgainst, re) 105 | } 106 | } 107 | 108 | grep := func(name string, logBuffer *bytes.Buffer) error { 109 | scanner := bufio.NewScanner(logBuffer) 110 | for scanner.Scan() { 111 | line := scanner.Text() 112 | for _, re := range matchAgainst { 113 | if re.MatchString(line) { 114 | fmt.Printf("[%s] %s\n", name, line) 115 | } 116 | } 117 | } 118 | 119 | if err := scanner.Err(); err != nil { 120 | return err 121 | } 122 | return nil 123 | } 124 | 125 | for name, logBuffer := range vars.logs { 126 | if err := grep(name, logBuffer); err != nil { 127 | return nil, createException(m, err.Error()) 128 | } 129 | } 130 | 131 | return self, nil 132 | }, 133 | instanceMethod, 134 | }, 135 | }) 136 | } 137 | 138 | func (o *podLogsClassInstance) Update() (mruby.Value, error) { 139 | return call(o.self, "get!") 140 | } 141 | -------------------------------------------------------------------------------- /rubykube/gotemplate_podsListModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type podsListModule struct{} 13 | 14 | func (c *podsClass) defineListMethods() { 15 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 16 | "get!": { 17 | mruby.ArgsReq(0) | mruby.ArgsOpt(2), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 18 | vars, err := c.LookupVars(self) 19 | if err != nil { 20 | return nil, createException(m, err.Error()) 21 | } 22 | 23 | ns, nameRegexp, listOptions, err := c.rk.resourceArgs(m.GetArgs()) 24 | if err != nil { 25 | return nil, createException(m, err.Error()) 26 | } 27 | 28 | pods, err := c.getList(c.rk.GetNamespace(ns), *listOptions) 29 | if err != nil { 30 | return nil, createException(m, err.Error()) 31 | } 32 | 33 | if nameRegexp != nil { 34 | for _, item := range pods.Items { 35 | if nameRegexp.MatchString(item.ObjectMeta.Name) { 36 | vars.pods.Items = append(vars.pods.Items, item) 37 | } 38 | } 39 | } else { 40 | vars.pods = podListTypeAlias(*pods) 41 | } 42 | return self, nil 43 | }, 44 | instanceMethod, 45 | }, 46 | "inspect": { 47 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 48 | vars, err := c.LookupVars(self) 49 | if err != nil { 50 | return nil, createException(m, err.Error()) 51 | } 52 | 53 | for n, item := range vars.pods.Items { 54 | fmt.Printf("%d: %s/%s\n", n, item.ObjectMeta.Namespace, item.ObjectMeta.Name) 55 | } 56 | return self, nil 57 | }, 58 | instanceMethod, 59 | }, 60 | "count": { 61 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 62 | vars, err := c.LookupVars(self) 63 | if err != nil { 64 | return nil, createException(m, err.Error()) 65 | } 66 | 67 | return m.FixnumValue(len(vars.pods.Items)), nil 68 | }, 69 | instanceMethod, 70 | }, 71 | "[]": { 72 | mruby.ArgsReq(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 73 | vars, err := c.LookupVars(self) 74 | if err != nil { 75 | return nil, createException(m, err.Error()) 76 | } 77 | 78 | args := m.GetArgs() 79 | err = standardCheck(c.rk, args, 1) 80 | if err != nil { 81 | return nil, createException(m, err.Error()) 82 | } 83 | n := args[0] 84 | if n.Type() != mruby.TypeFixnum { 85 | return nil, createException(m, "Argument must be an integer") 86 | } 87 | 88 | l := len(vars.pods.Items) 89 | i := n.Fixnum() 90 | 91 | if i >= l { 92 | return nil, nil 93 | } 94 | 95 | if i < 0 { 96 | // handle negative index in the way Ruby does it, i.e. no infinit wrapping 97 | if -i <= l { 98 | i %= l 99 | i *= -1 // in Go, unlike Ruby this needs to be converted to positive value 100 | } else { 101 | return nil, nil 102 | } 103 | } 104 | 105 | obj, err := c.getItem(vars.pods, i) 106 | if err != nil { 107 | return nil, createException(m, err.Error()) 108 | } 109 | return obj.self, nil 110 | }, 111 | instanceMethod, 112 | }, 113 | "first": { 114 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 115 | vars, err := c.LookupVars(self) 116 | if err != nil { 117 | return nil, createException(m, err.Error()) 118 | } 119 | 120 | if len(vars.pods.Items) > 0 { 121 | obj, err := c.getItem(vars.pods, 0) 122 | if err != nil { 123 | return nil, createException(m, err.Error()) 124 | } 125 | return obj.self, nil 126 | } 127 | return nil, nil 128 | }, 129 | instanceMethod, 130 | }, 131 | "any": { 132 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 133 | vars, err := c.LookupVars(self) 134 | if err != nil { 135 | return nil, createException(m, err.Error()) 136 | } 137 | 138 | l := len(vars.pods.Items) 139 | if l > 0 { 140 | obj, err := c.getItem(vars.pods, rand.Intn(l)) 141 | if err != nil { 142 | return nil, createException(m, err.Error()) 143 | } 144 | return obj.self, nil 145 | } 146 | return nil, nil 147 | }, 148 | instanceMethod, 149 | }, 150 | "last": { 151 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 152 | vars, err := c.LookupVars(self) 153 | if err != nil { 154 | return nil, createException(m, err.Error()) 155 | } 156 | 157 | l := len(vars.pods.Items) 158 | 159 | if l > 0 { 160 | obj, err := c.getItem(vars.pods, l-1) 161 | if err != nil { 162 | return nil, createException(m, err.Error()) 163 | } 164 | return obj.self, nil 165 | } 166 | return nil, nil 167 | }, 168 | instanceMethod, 169 | }, 170 | }) 171 | } 172 | -------------------------------------------------------------------------------- /rubykube/gotemplate_servicesListModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type servicesListModule struct{} 13 | 14 | func (c *servicesClass) defineListMethods() { 15 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 16 | "get!": { 17 | mruby.ArgsReq(0) | mruby.ArgsOpt(2), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 18 | vars, err := c.LookupVars(self) 19 | if err != nil { 20 | return nil, createException(m, err.Error()) 21 | } 22 | 23 | ns, nameRegexp, listOptions, err := c.rk.resourceArgs(m.GetArgs()) 24 | if err != nil { 25 | return nil, createException(m, err.Error()) 26 | } 27 | 28 | services, err := c.getList(c.rk.GetNamespace(ns), *listOptions) 29 | if err != nil { 30 | return nil, createException(m, err.Error()) 31 | } 32 | 33 | if nameRegexp != nil { 34 | for _, item := range services.Items { 35 | if nameRegexp.MatchString(item.ObjectMeta.Name) { 36 | vars.services.Items = append(vars.services.Items, item) 37 | } 38 | } 39 | } else { 40 | vars.services = serviceListTypeAlias(*services) 41 | } 42 | return self, nil 43 | }, 44 | instanceMethod, 45 | }, 46 | "inspect": { 47 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 48 | vars, err := c.LookupVars(self) 49 | if err != nil { 50 | return nil, createException(m, err.Error()) 51 | } 52 | 53 | for n, item := range vars.services.Items { 54 | fmt.Printf("%d: %s/%s\n", n, item.ObjectMeta.Namespace, item.ObjectMeta.Name) 55 | } 56 | return self, nil 57 | }, 58 | instanceMethod, 59 | }, 60 | "count": { 61 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 62 | vars, err := c.LookupVars(self) 63 | if err != nil { 64 | return nil, createException(m, err.Error()) 65 | } 66 | 67 | return m.FixnumValue(len(vars.services.Items)), nil 68 | }, 69 | instanceMethod, 70 | }, 71 | "[]": { 72 | mruby.ArgsReq(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 73 | vars, err := c.LookupVars(self) 74 | if err != nil { 75 | return nil, createException(m, err.Error()) 76 | } 77 | 78 | args := m.GetArgs() 79 | err = standardCheck(c.rk, args, 1) 80 | if err != nil { 81 | return nil, createException(m, err.Error()) 82 | } 83 | n := args[0] 84 | if n.Type() != mruby.TypeFixnum { 85 | return nil, createException(m, "Argument must be an integer") 86 | } 87 | 88 | l := len(vars.services.Items) 89 | i := n.Fixnum() 90 | 91 | if i >= l { 92 | return nil, nil 93 | } 94 | 95 | if i < 0 { 96 | // handle negative index in the way Ruby does it, i.e. no infinit wrapping 97 | if -i <= l { 98 | i %= l 99 | i *= -1 // in Go, unlike Ruby this needs to be converted to positive value 100 | } else { 101 | return nil, nil 102 | } 103 | } 104 | 105 | obj, err := c.getItem(vars.services, i) 106 | if err != nil { 107 | return nil, createException(m, err.Error()) 108 | } 109 | return obj.self, nil 110 | }, 111 | instanceMethod, 112 | }, 113 | "first": { 114 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 115 | vars, err := c.LookupVars(self) 116 | if err != nil { 117 | return nil, createException(m, err.Error()) 118 | } 119 | 120 | if len(vars.services.Items) > 0 { 121 | obj, err := c.getItem(vars.services, 0) 122 | if err != nil { 123 | return nil, createException(m, err.Error()) 124 | } 125 | return obj.self, nil 126 | } 127 | return nil, nil 128 | }, 129 | instanceMethod, 130 | }, 131 | "any": { 132 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 133 | vars, err := c.LookupVars(self) 134 | if err != nil { 135 | return nil, createException(m, err.Error()) 136 | } 137 | 138 | l := len(vars.services.Items) 139 | if l > 0 { 140 | obj, err := c.getItem(vars.services, rand.Intn(l)) 141 | if err != nil { 142 | return nil, createException(m, err.Error()) 143 | } 144 | return obj.self, nil 145 | } 146 | return nil, nil 147 | }, 148 | instanceMethod, 149 | }, 150 | "last": { 151 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 152 | vars, err := c.LookupVars(self) 153 | if err != nil { 154 | return nil, createException(m, err.Error()) 155 | } 156 | 157 | l := len(vars.services.Items) 158 | 159 | if l > 0 { 160 | obj, err := c.getItem(vars.services, l-1) 161 | if err != nil { 162 | return nil, createException(m, err.Error()) 163 | } 164 | return obj.self, nil 165 | } 166 | return nil, nil 167 | }, 168 | instanceMethod, 169 | }, 170 | }) 171 | } 172 | -------------------------------------------------------------------------------- /rubykube/gotemplate_daemonSetsListModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type daemonSetsListModule struct{} 13 | 14 | func (c *daemonSetsClass) defineListMethods() { 15 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 16 | "get!": { 17 | mruby.ArgsReq(0) | mruby.ArgsOpt(2), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 18 | vars, err := c.LookupVars(self) 19 | if err != nil { 20 | return nil, createException(m, err.Error()) 21 | } 22 | 23 | ns, nameRegexp, listOptions, err := c.rk.resourceArgs(m.GetArgs()) 24 | if err != nil { 25 | return nil, createException(m, err.Error()) 26 | } 27 | 28 | daemonSets, err := c.getList(c.rk.GetNamespace(ns), *listOptions) 29 | if err != nil { 30 | return nil, createException(m, err.Error()) 31 | } 32 | 33 | if nameRegexp != nil { 34 | for _, item := range daemonSets.Items { 35 | if nameRegexp.MatchString(item.ObjectMeta.Name) { 36 | vars.daemonSets.Items = append(vars.daemonSets.Items, item) 37 | } 38 | } 39 | } else { 40 | vars.daemonSets = daemonSetListTypeAlias(*daemonSets) 41 | } 42 | return self, nil 43 | }, 44 | instanceMethod, 45 | }, 46 | "inspect": { 47 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 48 | vars, err := c.LookupVars(self) 49 | if err != nil { 50 | return nil, createException(m, err.Error()) 51 | } 52 | 53 | for n, item := range vars.daemonSets.Items { 54 | fmt.Printf("%d: %s/%s\n", n, item.ObjectMeta.Namespace, item.ObjectMeta.Name) 55 | } 56 | return self, nil 57 | }, 58 | instanceMethod, 59 | }, 60 | "count": { 61 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 62 | vars, err := c.LookupVars(self) 63 | if err != nil { 64 | return nil, createException(m, err.Error()) 65 | } 66 | 67 | return m.FixnumValue(len(vars.daemonSets.Items)), nil 68 | }, 69 | instanceMethod, 70 | }, 71 | "[]": { 72 | mruby.ArgsReq(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 73 | vars, err := c.LookupVars(self) 74 | if err != nil { 75 | return nil, createException(m, err.Error()) 76 | } 77 | 78 | args := m.GetArgs() 79 | err = standardCheck(c.rk, args, 1) 80 | if err != nil { 81 | return nil, createException(m, err.Error()) 82 | } 83 | n := args[0] 84 | if n.Type() != mruby.TypeFixnum { 85 | return nil, createException(m, "Argument must be an integer") 86 | } 87 | 88 | l := len(vars.daemonSets.Items) 89 | i := n.Fixnum() 90 | 91 | if i >= l { 92 | return nil, nil 93 | } 94 | 95 | if i < 0 { 96 | // handle negative index in the way Ruby does it, i.e. no infinit wrapping 97 | if -i <= l { 98 | i %= l 99 | i *= -1 // in Go, unlike Ruby this needs to be converted to positive value 100 | } else { 101 | return nil, nil 102 | } 103 | } 104 | 105 | obj, err := c.getItem(vars.daemonSets, i) 106 | if err != nil { 107 | return nil, createException(m, err.Error()) 108 | } 109 | return obj.self, nil 110 | }, 111 | instanceMethod, 112 | }, 113 | "first": { 114 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 115 | vars, err := c.LookupVars(self) 116 | if err != nil { 117 | return nil, createException(m, err.Error()) 118 | } 119 | 120 | if len(vars.daemonSets.Items) > 0 { 121 | obj, err := c.getItem(vars.daemonSets, 0) 122 | if err != nil { 123 | return nil, createException(m, err.Error()) 124 | } 125 | return obj.self, nil 126 | } 127 | return nil, nil 128 | }, 129 | instanceMethod, 130 | }, 131 | "any": { 132 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 133 | vars, err := c.LookupVars(self) 134 | if err != nil { 135 | return nil, createException(m, err.Error()) 136 | } 137 | 138 | l := len(vars.daemonSets.Items) 139 | if l > 0 { 140 | obj, err := c.getItem(vars.daemonSets, rand.Intn(l)) 141 | if err != nil { 142 | return nil, createException(m, err.Error()) 143 | } 144 | return obj.self, nil 145 | } 146 | return nil, nil 147 | }, 148 | instanceMethod, 149 | }, 150 | "last": { 151 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 152 | vars, err := c.LookupVars(self) 153 | if err != nil { 154 | return nil, createException(m, err.Error()) 155 | } 156 | 157 | l := len(vars.daemonSets.Items) 158 | 159 | if l > 0 { 160 | obj, err := c.getItem(vars.daemonSets, l-1) 161 | if err != nil { 162 | return nil, createException(m, err.Error()) 163 | } 164 | return obj.self, nil 165 | } 166 | return nil, nil 167 | }, 168 | instanceMethod, 169 | }, 170 | }) 171 | } 172 | -------------------------------------------------------------------------------- /rubykube/gotemplate_deploymentsListModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type deploymentsListModule struct{} 13 | 14 | func (c *deploymentsClass) defineListMethods() { 15 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 16 | "get!": { 17 | mruby.ArgsReq(0) | mruby.ArgsOpt(2), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 18 | vars, err := c.LookupVars(self) 19 | if err != nil { 20 | return nil, createException(m, err.Error()) 21 | } 22 | 23 | ns, nameRegexp, listOptions, err := c.rk.resourceArgs(m.GetArgs()) 24 | if err != nil { 25 | return nil, createException(m, err.Error()) 26 | } 27 | 28 | deployments, err := c.getList(c.rk.GetNamespace(ns), *listOptions) 29 | if err != nil { 30 | return nil, createException(m, err.Error()) 31 | } 32 | 33 | if nameRegexp != nil { 34 | for _, item := range deployments.Items { 35 | if nameRegexp.MatchString(item.ObjectMeta.Name) { 36 | vars.deployments.Items = append(vars.deployments.Items, item) 37 | } 38 | } 39 | } else { 40 | vars.deployments = deploymentListTypeAlias(*deployments) 41 | } 42 | return self, nil 43 | }, 44 | instanceMethod, 45 | }, 46 | "inspect": { 47 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 48 | vars, err := c.LookupVars(self) 49 | if err != nil { 50 | return nil, createException(m, err.Error()) 51 | } 52 | 53 | for n, item := range vars.deployments.Items { 54 | fmt.Printf("%d: %s/%s\n", n, item.ObjectMeta.Namespace, item.ObjectMeta.Name) 55 | } 56 | return self, nil 57 | }, 58 | instanceMethod, 59 | }, 60 | "count": { 61 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 62 | vars, err := c.LookupVars(self) 63 | if err != nil { 64 | return nil, createException(m, err.Error()) 65 | } 66 | 67 | return m.FixnumValue(len(vars.deployments.Items)), nil 68 | }, 69 | instanceMethod, 70 | }, 71 | "[]": { 72 | mruby.ArgsReq(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 73 | vars, err := c.LookupVars(self) 74 | if err != nil { 75 | return nil, createException(m, err.Error()) 76 | } 77 | 78 | args := m.GetArgs() 79 | err = standardCheck(c.rk, args, 1) 80 | if err != nil { 81 | return nil, createException(m, err.Error()) 82 | } 83 | n := args[0] 84 | if n.Type() != mruby.TypeFixnum { 85 | return nil, createException(m, "Argument must be an integer") 86 | } 87 | 88 | l := len(vars.deployments.Items) 89 | i := n.Fixnum() 90 | 91 | if i >= l { 92 | return nil, nil 93 | } 94 | 95 | if i < 0 { 96 | // handle negative index in the way Ruby does it, i.e. no infinit wrapping 97 | if -i <= l { 98 | i %= l 99 | i *= -1 // in Go, unlike Ruby this needs to be converted to positive value 100 | } else { 101 | return nil, nil 102 | } 103 | } 104 | 105 | obj, err := c.getItem(vars.deployments, i) 106 | if err != nil { 107 | return nil, createException(m, err.Error()) 108 | } 109 | return obj.self, nil 110 | }, 111 | instanceMethod, 112 | }, 113 | "first": { 114 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 115 | vars, err := c.LookupVars(self) 116 | if err != nil { 117 | return nil, createException(m, err.Error()) 118 | } 119 | 120 | if len(vars.deployments.Items) > 0 { 121 | obj, err := c.getItem(vars.deployments, 0) 122 | if err != nil { 123 | return nil, createException(m, err.Error()) 124 | } 125 | return obj.self, nil 126 | } 127 | return nil, nil 128 | }, 129 | instanceMethod, 130 | }, 131 | "any": { 132 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 133 | vars, err := c.LookupVars(self) 134 | if err != nil { 135 | return nil, createException(m, err.Error()) 136 | } 137 | 138 | l := len(vars.deployments.Items) 139 | if l > 0 { 140 | obj, err := c.getItem(vars.deployments, rand.Intn(l)) 141 | if err != nil { 142 | return nil, createException(m, err.Error()) 143 | } 144 | return obj.self, nil 145 | } 146 | return nil, nil 147 | }, 148 | instanceMethod, 149 | }, 150 | "last": { 151 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 152 | vars, err := c.LookupVars(self) 153 | if err != nil { 154 | return nil, createException(m, err.Error()) 155 | } 156 | 157 | l := len(vars.deployments.Items) 158 | 159 | if l > 0 { 160 | obj, err := c.getItem(vars.deployments, l-1) 161 | if err != nil { 162 | return nil, createException(m, err.Error()) 163 | } 164 | return obj.self, nil 165 | } 166 | return nil, nil 167 | }, 168 | instanceMethod, 169 | }, 170 | }) 171 | } 172 | -------------------------------------------------------------------------------- /rubykube/gotemplate_replicaSetsListModule.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type replicaSetsListModule struct{} 13 | 14 | func (c *replicaSetsClass) defineListMethods() { 15 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 16 | "get!": { 17 | mruby.ArgsReq(0) | mruby.ArgsOpt(2), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 18 | vars, err := c.LookupVars(self) 19 | if err != nil { 20 | return nil, createException(m, err.Error()) 21 | } 22 | 23 | ns, nameRegexp, listOptions, err := c.rk.resourceArgs(m.GetArgs()) 24 | if err != nil { 25 | return nil, createException(m, err.Error()) 26 | } 27 | 28 | replicaSets, err := c.getList(c.rk.GetNamespace(ns), *listOptions) 29 | if err != nil { 30 | return nil, createException(m, err.Error()) 31 | } 32 | 33 | if nameRegexp != nil { 34 | for _, item := range replicaSets.Items { 35 | if nameRegexp.MatchString(item.ObjectMeta.Name) { 36 | vars.replicaSets.Items = append(vars.replicaSets.Items, item) 37 | } 38 | } 39 | } else { 40 | vars.replicaSets = replicaSetListTypeAlias(*replicaSets) 41 | } 42 | return self, nil 43 | }, 44 | instanceMethod, 45 | }, 46 | "inspect": { 47 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 48 | vars, err := c.LookupVars(self) 49 | if err != nil { 50 | return nil, createException(m, err.Error()) 51 | } 52 | 53 | for n, item := range vars.replicaSets.Items { 54 | fmt.Printf("%d: %s/%s\n", n, item.ObjectMeta.Namespace, item.ObjectMeta.Name) 55 | } 56 | return self, nil 57 | }, 58 | instanceMethod, 59 | }, 60 | "count": { 61 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 62 | vars, err := c.LookupVars(self) 63 | if err != nil { 64 | return nil, createException(m, err.Error()) 65 | } 66 | 67 | return m.FixnumValue(len(vars.replicaSets.Items)), nil 68 | }, 69 | instanceMethod, 70 | }, 71 | "[]": { 72 | mruby.ArgsReq(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 73 | vars, err := c.LookupVars(self) 74 | if err != nil { 75 | return nil, createException(m, err.Error()) 76 | } 77 | 78 | args := m.GetArgs() 79 | err = standardCheck(c.rk, args, 1) 80 | if err != nil { 81 | return nil, createException(m, err.Error()) 82 | } 83 | n := args[0] 84 | if n.Type() != mruby.TypeFixnum { 85 | return nil, createException(m, "Argument must be an integer") 86 | } 87 | 88 | l := len(vars.replicaSets.Items) 89 | i := n.Fixnum() 90 | 91 | if i >= l { 92 | return nil, nil 93 | } 94 | 95 | if i < 0 { 96 | // handle negative index in the way Ruby does it, i.e. no infinit wrapping 97 | if -i <= l { 98 | i %= l 99 | i *= -1 // in Go, unlike Ruby this needs to be converted to positive value 100 | } else { 101 | return nil, nil 102 | } 103 | } 104 | 105 | obj, err := c.getItem(vars.replicaSets, i) 106 | if err != nil { 107 | return nil, createException(m, err.Error()) 108 | } 109 | return obj.self, nil 110 | }, 111 | instanceMethod, 112 | }, 113 | "first": { 114 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 115 | vars, err := c.LookupVars(self) 116 | if err != nil { 117 | return nil, createException(m, err.Error()) 118 | } 119 | 120 | if len(vars.replicaSets.Items) > 0 { 121 | obj, err := c.getItem(vars.replicaSets, 0) 122 | if err != nil { 123 | return nil, createException(m, err.Error()) 124 | } 125 | return obj.self, nil 126 | } 127 | return nil, nil 128 | }, 129 | instanceMethod, 130 | }, 131 | "any": { 132 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 133 | vars, err := c.LookupVars(self) 134 | if err != nil { 135 | return nil, createException(m, err.Error()) 136 | } 137 | 138 | l := len(vars.replicaSets.Items) 139 | if l > 0 { 140 | obj, err := c.getItem(vars.replicaSets, rand.Intn(l)) 141 | if err != nil { 142 | return nil, createException(m, err.Error()) 143 | } 144 | return obj.self, nil 145 | } 146 | return nil, nil 147 | }, 148 | instanceMethod, 149 | }, 150 | "last": { 151 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 152 | vars, err := c.LookupVars(self) 153 | if err != nil { 154 | return nil, createException(m, err.Error()) 155 | } 156 | 157 | l := len(vars.replicaSets.Items) 158 | 159 | if l > 0 { 160 | obj, err := c.getItem(vars.replicaSets, l-1) 161 | if err != nil { 162 | return nil, createException(m, err.Error()) 163 | } 164 | return obj.self, nil 165 | } 166 | return nil, nil 167 | }, 168 | instanceMethod, 169 | }, 170 | }) 171 | } 172 | -------------------------------------------------------------------------------- /rubykube/templates/resource/list/template.go: -------------------------------------------------------------------------------- 1 | package resourcelist 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | // template type RubyKubeClass(parentClass, classNameString, instanceVariableName, instanceVariableType) 11 | 12 | type RubyKubeClass struct{} 13 | 14 | type parentClass int 15 | type classNameString string 16 | type instanceVariableName int 17 | type instanceVariableType int 18 | 19 | func (c *parentClass) defineListMethods() { 20 | c.rk.appendMethods(c.class, map[string]methodDefintion{ 21 | "get!": { 22 | mruby.ArgsReq(0) | mruby.ArgsOpt(2), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 23 | vars, err := c.LookupVars(self) 24 | if err != nil { 25 | return nil, createException(m, err.Error()) 26 | } 27 | 28 | ns, nameRegexp, listOptions, err := c.rk.resourceArgs(m.GetArgs()) 29 | if err != nil { 30 | return nil, createException(m, err.Error()) 31 | } 32 | 33 | instanceVariableName, err := c.getList(c.rk.GetNamespace(ns), *listOptions) 34 | if err != nil { 35 | return nil, createException(m, err.Error()) 36 | } 37 | 38 | if nameRegexp != nil { 39 | for _, item := range instanceVariableName.Items { 40 | if nameRegexp.MatchString(item.ObjectMeta.Name) { 41 | vars.instanceVariableName.Items = append(vars.instanceVariableName.Items, item) 42 | } 43 | } 44 | } else { 45 | vars.instanceVariableName = instanceVariableType(*instanceVariableName) 46 | } 47 | return self, nil 48 | }, 49 | instanceMethod, 50 | }, 51 | "inspect": { 52 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 53 | vars, err := c.LookupVars(self) 54 | if err != nil { 55 | return nil, createException(m, err.Error()) 56 | } 57 | 58 | for n, item := range vars.instanceVariableName.Items { 59 | fmt.Printf("%d: %s/%s\n", n, item.ObjectMeta.Namespace, item.ObjectMeta.Name) 60 | } 61 | return self, nil 62 | }, 63 | instanceMethod, 64 | }, 65 | "count": { 66 | mruby.ArgsReq(0), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 67 | vars, err := c.LookupVars(self) 68 | if err != nil { 69 | return nil, createException(m, err.Error()) 70 | } 71 | 72 | return m.FixnumValue(len(vars.instanceVariableName.Items)), nil 73 | }, 74 | instanceMethod, 75 | }, 76 | "[]": { 77 | mruby.ArgsReq(1), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 78 | vars, err := c.LookupVars(self) 79 | if err != nil { 80 | return nil, createException(m, err.Error()) 81 | } 82 | 83 | args := m.GetArgs() 84 | err = standardCheck(c.rk, args, 1) 85 | if err != nil { 86 | return nil, createException(m, err.Error()) 87 | } 88 | n := args[0] 89 | if n.Type() != mruby.TypeFixnum { 90 | return nil, createException(m, "Argument must be an integer") 91 | } 92 | 93 | l := len(vars.instanceVariableName.Items) 94 | i := n.Fixnum() 95 | 96 | if i >= l { 97 | return nil, nil 98 | } 99 | 100 | if i < 0 { 101 | // handle negative index in the way Ruby does it, i.e. no infinit wrapping 102 | if -i <= l { 103 | i %= l 104 | i *= -1 // in Go, unlike Ruby this needs to be converted to positive value 105 | } else { 106 | return nil, nil 107 | } 108 | } 109 | 110 | obj, err := c.getItem(vars.instanceVariableName, i) 111 | if err != nil { 112 | return nil, createException(m, err.Error()) 113 | } 114 | return obj.self, nil 115 | }, 116 | instanceMethod, 117 | }, 118 | "first": { 119 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 120 | vars, err := c.LookupVars(self) 121 | if err != nil { 122 | return nil, createException(m, err.Error()) 123 | } 124 | 125 | if len(vars.instanceVariableName.Items) > 0 { 126 | obj, err := c.getItem(vars.instanceVariableName, 0) 127 | if err != nil { 128 | return nil, createException(m, err.Error()) 129 | } 130 | return obj.self, nil 131 | } 132 | return nil, nil 133 | }, 134 | instanceMethod, 135 | }, 136 | "any": { 137 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 138 | vars, err := c.LookupVars(self) 139 | if err != nil { 140 | return nil, createException(m, err.Error()) 141 | } 142 | 143 | l := len(vars.instanceVariableName.Items) 144 | if l > 0 { 145 | obj, err := c.getItem(vars.instanceVariableName, rand.Intn(l)) 146 | if err != nil { 147 | return nil, createException(m, err.Error()) 148 | } 149 | return obj.self, nil 150 | } 151 | return nil, nil 152 | }, 153 | instanceMethod, 154 | }, 155 | "last": { 156 | mruby.ArgsNone(), func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 157 | vars, err := c.LookupVars(self) 158 | if err != nil { 159 | return nil, createException(m, err.Error()) 160 | } 161 | 162 | l := len(vars.instanceVariableName.Items) 163 | 164 | if l > 0 { 165 | obj, err := c.getItem(vars.instanceVariableName, l-1) 166 | if err != nil { 167 | return nil, createException(m, err.Error()) 168 | } 169 | return obj.self, nil 170 | } 171 | return nil, nil 172 | }, 173 | instanceMethod, 174 | }, 175 | }) 176 | } 177 | -------------------------------------------------------------------------------- /rubykube/converter/converter.go: -------------------------------------------------------------------------------- 1 | package converter 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | mruby "github.com/mitchellh/go-mruby" 8 | ) 9 | 10 | type converterBranch struct { 11 | self *mruby.MrbValue 12 | // TODO get rid of selfType and use self.Type() once we moved to proper arrays 13 | selfType mruby.ValueType // this to say whether we are working with a hash or an array 14 | parent *converterBranch // pointer to the parent, so we know where to go back once done 15 | hashKey *mruby.MrbValue // hash key to use for the current value (if it is in a hash) 16 | value *mruby.MrbValue // current value we are handling 17 | index int // our index in the tree 18 | } 19 | 20 | type Converter struct { 21 | branches []*converterBranch // list of tree branches – hashes and arrays 22 | branchIndex int // maps to the current position in the tree 23 | values []*mruby.MrbValue // used to store all values we find 24 | isRoot bool // idiates we are at the root of the tree 25 | mrb *mruby.Mrb // local instance of mruby 26 | } 27 | 28 | // New returns a new converter for any Kubernetes API object to Ruby 29 | func New(m *mruby.Mrb) *Converter { 30 | return &Converter{isRoot: true, mrb: m} 31 | } 32 | 33 | // Convert performs conversion from any Kubernetes API object to Ruby, 34 | // it may panic, if there is something terribly wrong; it's effective 35 | // in wire-format and uses lower-case keys, unlike Go structs. 36 | func (c *Converter) Convert(obj interface{}) error { 37 | // It may be possible to rewrite this with channels and goroutines, 38 | // but not sure if that will be needed (and how safe it would play 39 | // with mruby?); Passing errors via channel might make sense... 40 | if len(c.values) > 0 || len(c.branches) > 0 || !c.isRoot { 41 | return fmt.Errorf("Convert: don't call me again, I'm stupid!") 42 | } 43 | 44 | // As user is expected to be falimial with wire format of the API, 45 | // we convert it to JSON first. Also, it'd require a code generator 46 | // to provide conversion if we didn't do this. 47 | data, err := json.Marshal(obj) 48 | if err != nil { 49 | return err 50 | } 51 | 52 | // Re-encode JSON data into an interface and store it 53 | var tree interface{} 54 | if err := json.Unmarshal(data, &tree); err != nil { 55 | return err 56 | } 57 | 58 | c.walkTree(tree) 59 | return nil 60 | } 61 | 62 | // Value returns converted Ruby value (currently a hash) 63 | func (c *Converter) Value() mruby.Value { 64 | if len(c.values) > 0 { 65 | return c.values[0] 66 | } 67 | return nil 68 | } 69 | 70 | func (c *Converter) appendSimpleValue(v *mruby.MrbValue) { 71 | if c.isRoot { 72 | c.values = append(c.values, v) 73 | return 74 | } 75 | c.values = append(c.values, v) // keep this for consistency 76 | c.thisBranch().value = v 77 | } 78 | 79 | func (c *Converter) appendBranch(newBranch *converterBranch) { 80 | if c.isRoot { 81 | c.isRoot = false 82 | } else { 83 | newBranch.parent = c.thisBranch() 84 | } 85 | c.values = append(c.values, newBranch.self) 86 | c.branches = append(c.branches, newBranch) 87 | i := len(c.branches) - 1 88 | c.branchIndex, newBranch.index = i, i 89 | } 90 | 91 | func (c *Converter) thisBranch() *converterBranch { 92 | return c.branches[c.branchIndex] 93 | } 94 | 95 | func (c *Converter) flipBranch() { 96 | if c.thisBranch().parent != nil { 97 | // fmt.Printf("c.branchIndex = (%d => %d)\n", c.branchIndex, c.thisBranch().parent.index) 98 | c.branchIndex = c.thisBranch().parent.index 99 | c.thisBranch().value = nil // reset the value, so we don't inherit it unitentionally 100 | } 101 | } 102 | 103 | func (c *Converter) walkTree(v interface{}) { 104 | // we enter an interface and look at its type 105 | switch vv := v.(type) { 106 | // it may be a simple one (e.g. bool, string or float64), 107 | // in which case we simple pick up the value and append it 108 | // to the internal list of values 109 | // this code is generic enough to treat simple non-nested values 110 | case bool: 111 | if vv { 112 | c.appendSimpleValue(c.mrb.TrueValue()) 113 | } else { 114 | c.appendSimpleValue(c.mrb.FalseValue()) 115 | } 116 | case string: 117 | c.appendSimpleValue(c.mrb.StringValue(vv)) 118 | case float64: 119 | // TODO figure out if go-mruby can do it already, or it needs a patch 120 | // XXX should it always be a float in ruby also? (check JSON spec 121 | // and implementation docs for both of the parsers) 122 | c.appendSimpleValue(c.mrb.StringValue(fmt.Sprintf("%f", vv))) 123 | // the root is going to be an map, but we also handle slices 124 | // in both cases we recurse into the data and collect all what's there 125 | case map[string]interface{}: 126 | c.convertMapBranch(vv) 127 | case []interface{}: 128 | c.convertSliceBranch(vv) 129 | case nil: 130 | c.appendSimpleValue(c.mrb.NilValue()) 131 | default: 132 | // XXX: should we panic here? 133 | fmt.Printf("(walkTree: unknown type? => %+v) thisBranch[%d] = %+v\n", vv, c.branchIndex, c.thisBranch()) 134 | } 135 | } 136 | 137 | func (c *Converter) newMapBranch() *converterBranch { 138 | newBranch := &converterBranch{selfType: mruby.TypeHash} 139 | newHash, err := c.mrb.LoadString("{}") 140 | if err != nil { 141 | panic(fmt.Errorf("newMapBranch: %v", err)) 142 | } 143 | newBranch.self = newHash 144 | c.appendBranch(newBranch) 145 | if newBranch.parent != nil { 146 | switch newBranch.parent.selfType { 147 | case mruby.TypeHash: 148 | newBranch.parent.self.Hash().Set(newBranch.parent.hashKey, newHash) 149 | case mruby.TypeArray: // TODO patch go-mruby to mutate arrays 150 | newBranch.parent.self.Hash().Set(newBranch.parent.hashKey, newHash) 151 | } 152 | } 153 | return newBranch 154 | } 155 | 156 | func (c *Converter) convertMapBranch(x map[string]interface{}) { 157 | thisBranch := c.newMapBranch() 158 | for k, v := range x { 159 | thisBranch.hashKey = c.mrb.StringValue(k) 160 | c.walkTree(v) 161 | if thisBranch.value != nil { 162 | thisBranch.self.Hash().Set(thisBranch.hashKey, thisBranch.value) 163 | } 164 | } 165 | c.flipBranch() 166 | } 167 | 168 | func (c *Converter) newSliceBranch() *converterBranch { 169 | newBranch := &converterBranch{selfType: mruby.TypeArray} 170 | newHash, err := c.mrb.LoadString("{}") 171 | if err != nil { 172 | panic(fmt.Errorf("newSliceBranch: %v", err)) 173 | } 174 | newBranch.self = newHash 175 | c.appendBranch(newBranch) 176 | if newBranch.parent != nil { 177 | switch newBranch.parent.selfType { 178 | case mruby.TypeHash: 179 | newBranch.parent.self.Hash().Set(newBranch.parent.hashKey, newHash) 180 | case mruby.TypeArray: 181 | newBranch.parent.self.Hash().Set(newBranch.parent.hashKey, newHash) 182 | } 183 | } 184 | return newBranch 185 | } 186 | 187 | func (c *Converter) convertSliceBranch(x []interface{}) { 188 | thisBranch := c.newSliceBranch() 189 | for k, v := range x { 190 | thisBranch.hashKey = c.mrb.StringValue(fmt.Sprintf("%d", k)) 191 | c.walkTree(v) 192 | if thisBranch.value != nil { 193 | thisBranch.self.Hash().Set(thisBranch.hashKey, thisBranch.value) 194 | } 195 | } 196 | c.flipBranch() 197 | } 198 | -------------------------------------------------------------------------------- /glide.lock: -------------------------------------------------------------------------------- 1 | hash: 78c23b0823f100ec8fd858a3808293e78a39ae8cc9cfaa6bebfcba7d5dd84e33 2 | updated: 2018-02-10T07:48:48.748212Z 3 | imports: 4 | - name: github.com/chzyer/readline 5 | version: 62c6fe6193755f722b8b8788aa7357be55a50ff1 6 | - name: github.com/emicklei/go-restful 7 | version: ff4f55a206334ef123e4f79bbf348980da81ca46 8 | subpackages: 9 | - log 10 | - name: github.com/ghodss/yaml 11 | version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee 12 | - name: github.com/go-openapi/jsonpointer 13 | version: 46af16f9f7b149af66e5d1bd010e3574dc06de98 14 | - name: github.com/go-openapi/jsonreference 15 | version: 13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272 16 | - name: github.com/go-openapi/spec 17 | version: 7abd5745472fff5eb3685386d5fb8bf38683154d 18 | - name: github.com/go-openapi/swag 19 | version: f3f9494671f93fcff853e3c6e9e948b3eb71e590 20 | - name: github.com/gogo/protobuf 21 | version: c0656edd0d9eab7c66d1eb0c568f9039345796f7 22 | subpackages: 23 | - proto 24 | - sortkeys 25 | - name: github.com/golang/glog 26 | version: 44145f04b68cf362d9c4df2182967c2275eaefed 27 | - name: github.com/golang/protobuf 28 | version: 1643683e1b54a9e88ad26d98f81400c8c9d9f4f9 29 | subpackages: 30 | - proto 31 | - ptypes 32 | - ptypes/any 33 | - ptypes/duration 34 | - ptypes/timestamp 35 | - name: github.com/google/btree 36 | version: 7d79101e329e5a3adf994758c578dab82b90c017 37 | - name: github.com/google/gofuzz 38 | version: 44d81051d367757e1c7c6a5a86423ece9afcf63c 39 | - name: github.com/googleapis/gnostic 40 | version: 0c5108395e2debce0d731cf0287ddf7242066aba 41 | subpackages: 42 | - OpenAPIv2 43 | - compiler 44 | - extensions 45 | - name: github.com/gregjones/httpcache 46 | version: 787624de3eb7bd915c329cba748687a3b22666a6 47 | subpackages: 48 | - diskcache 49 | - name: github.com/howeyc/gopass 50 | version: bf9dde6d0d2c004a008c27aaee91170c786f6db8 51 | - name: github.com/imdario/mergo 52 | version: 6633656539c1639d9d78127b7d47c622b5d7b6dc 53 | - name: github.com/json-iterator/go 54 | version: 36b14963da70d11297d313183d7e6388c8510e1e 55 | - name: github.com/juju/ratelimit 56 | version: 5b9ff866471762aa2ab2dced63c9fb6f53921342 57 | - name: github.com/mailru/easyjson 58 | version: 2f5df55504ebc322e4d52d34df6a1f5b503bf26d 59 | subpackages: 60 | - buffer 61 | - jlexer 62 | - jwriter 63 | - name: github.com/mitchellh/go-mruby 64 | version: 4ec0d648296c92c7a1df4827f19b14928d3af707 65 | - name: github.com/peterbourgon/diskv 66 | version: 5f041e8faa004a95c88a202771f4cc3e991971e6 67 | - name: github.com/PuerkitoBio/purell 68 | version: 8a290539e2e8629dbc4e6bad948158f790ec31f4 69 | - name: github.com/PuerkitoBio/urlesc 70 | version: 5bd2802263f21d8788851d5305584c82a5c75d7e 71 | - name: github.com/spf13/pflag 72 | version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7 73 | - name: golang.org/x/crypto 74 | version: 81e90905daefcd6fd217b62423c0908922eadb30 75 | subpackages: 76 | - ssh/terminal 77 | - name: golang.org/x/net 78 | version: 1c05540f6879653db88113bc4a2b70aec4bd491f 79 | subpackages: 80 | - http2 81 | - http2/hpack 82 | - idna 83 | - lex/httplex 84 | - name: golang.org/x/sys 85 | version: 95c6576299259db960f6c5b9b69ea52422860fce 86 | subpackages: 87 | - unix 88 | - windows 89 | - name: golang.org/x/text 90 | version: b19bf474d317b857955b12035d2c5acb57ce8b01 91 | subpackages: 92 | - cases 93 | - internal 94 | - internal/tag 95 | - language 96 | - runes 97 | - secure/bidirule 98 | - secure/precis 99 | - transform 100 | - unicode/bidi 101 | - unicode/norm 102 | - width 103 | - name: gopkg.in/inf.v0 104 | version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 105 | - name: gopkg.in/yaml.v2 106 | version: 53feefa2559fb8dfa8d81baad31be332c97d6c77 107 | - name: k8s.io/api 108 | version: 11147472b7c934c474a2c484af3c0c5210b7a3af 109 | subpackages: 110 | - admissionregistration/v1alpha1 111 | - admissionregistration/v1beta1 112 | - apps/v1 113 | - apps/v1beta1 114 | - apps/v1beta2 115 | - authentication/v1 116 | - authentication/v1beta1 117 | - authorization/v1 118 | - authorization/v1beta1 119 | - autoscaling/v1 120 | - autoscaling/v2beta1 121 | - batch/v1 122 | - batch/v1beta1 123 | - batch/v2alpha1 124 | - certificates/v1beta1 125 | - core/v1 126 | - events/v1beta1 127 | - extensions/v1beta1 128 | - networking/v1 129 | - policy/v1beta1 130 | - rbac/v1 131 | - rbac/v1alpha1 132 | - rbac/v1beta1 133 | - scheduling/v1alpha1 134 | - settings/v1alpha1 135 | - storage/v1 136 | - storage/v1alpha1 137 | - storage/v1beta1 138 | - name: k8s.io/apimachinery 139 | version: 180eddb345a5be3a157cea1c624700ad5bd27b8f 140 | subpackages: 141 | - pkg/api/errors 142 | - pkg/api/meta 143 | - pkg/api/resource 144 | - pkg/apis/meta/v1 145 | - pkg/apis/meta/v1/unstructured 146 | - pkg/apis/meta/v1alpha1 147 | - pkg/conversion 148 | - pkg/conversion/queryparams 149 | - pkg/fields 150 | - pkg/labels 151 | - pkg/runtime 152 | - pkg/runtime/schema 153 | - pkg/runtime/serializer 154 | - pkg/runtime/serializer/json 155 | - pkg/runtime/serializer/protobuf 156 | - pkg/runtime/serializer/recognizer 157 | - pkg/runtime/serializer/streaming 158 | - pkg/runtime/serializer/versioning 159 | - pkg/selection 160 | - pkg/types 161 | - pkg/util/clock 162 | - pkg/util/errors 163 | - pkg/util/framer 164 | - pkg/util/intstr 165 | - pkg/util/json 166 | - pkg/util/net 167 | - pkg/util/runtime 168 | - pkg/util/sets 169 | - pkg/util/validation 170 | - pkg/util/validation/field 171 | - pkg/util/wait 172 | - pkg/util/yaml 173 | - pkg/version 174 | - pkg/watch 175 | - third_party/forked/golang/reflect 176 | - name: k8s.io/client-go 177 | version: 78700dec6369ba22221b72770783300f143df150 178 | subpackages: 179 | - discovery 180 | - kubernetes 181 | - kubernetes/scheme 182 | - kubernetes/typed/admissionregistration/v1alpha1 183 | - kubernetes/typed/admissionregistration/v1beta1 184 | - kubernetes/typed/apps/v1 185 | - kubernetes/typed/apps/v1beta1 186 | - kubernetes/typed/apps/v1beta2 187 | - kubernetes/typed/authentication/v1 188 | - kubernetes/typed/authentication/v1beta1 189 | - kubernetes/typed/authorization/v1 190 | - kubernetes/typed/authorization/v1beta1 191 | - kubernetes/typed/autoscaling/v1 192 | - kubernetes/typed/autoscaling/v2beta1 193 | - kubernetes/typed/batch/v1 194 | - kubernetes/typed/batch/v1beta1 195 | - kubernetes/typed/batch/v2alpha1 196 | - kubernetes/typed/certificates/v1beta1 197 | - kubernetes/typed/core/v1 198 | - kubernetes/typed/events/v1beta1 199 | - kubernetes/typed/extensions/v1beta1 200 | - kubernetes/typed/networking/v1 201 | - kubernetes/typed/policy/v1beta1 202 | - kubernetes/typed/rbac/v1 203 | - kubernetes/typed/rbac/v1alpha1 204 | - kubernetes/typed/rbac/v1beta1 205 | - kubernetes/typed/scheduling/v1alpha1 206 | - kubernetes/typed/settings/v1alpha1 207 | - kubernetes/typed/storage/v1 208 | - kubernetes/typed/storage/v1alpha1 209 | - kubernetes/typed/storage/v1beta1 210 | - pkg/version 211 | - rest 212 | - rest/watch 213 | - tools/auth 214 | - tools/clientcmd 215 | - tools/clientcmd/api 216 | - tools/clientcmd/api/latest 217 | - tools/clientcmd/api/v1 218 | - tools/metrics 219 | - tools/reference 220 | - transport 221 | - util/cert 222 | - util/flowcontrol 223 | - util/homedir 224 | - util/integer 225 | - name: k8s.io/kube-openapi 226 | version: 39a7bf85c140f972372c2a0d1ee40adbf0c8bfe1 227 | subpackages: 228 | - pkg/common 229 | - name: k8s.io/kubernetes 230 | version: 5fa2db2bd46ac79e5e00a4e6ed24191080aa463b 231 | subpackages: 232 | - pkg/printers 233 | testImports: [] 234 | -------------------------------------------------------------------------------- /rubykube/verbs.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | /* 4 | verbs.go is a collection of the verbs used to do stuff. 5 | */ 6 | 7 | import ( 8 | "fmt" 9 | 10 | mruby "github.com/mitchellh/go-mruby" 11 | ) 12 | 13 | // Definition is a jump table definition used for programming the DSL into the 14 | // mruby interpreter. 15 | type verbDefinition struct { 16 | verbFunc verbFunc 17 | argSpec mruby.ArgSpec 18 | } 19 | 20 | // verbJumpTable is the dispatch instructions sent to the builder at preparation time. 21 | var verbJumpTable map[string]verbDefinition 22 | 23 | func init() { 24 | // This is to avoid initialisation loop error from the compiler 25 | verbJumpTable = map[string]verbDefinition{ 26 | "pods": {pods, mruby.ArgsReq(0) | mruby.ArgsOpt(2)}, 27 | "services": {services, mruby.ArgsReq(0) | mruby.ArgsOpt(2)}, 28 | "deployments": {deployments, mruby.ArgsReq(0) | mruby.ArgsOpt(2)}, 29 | "replicasets": {replicaSets, mruby.ArgsReq(0) | mruby.ArgsOpt(2)}, 30 | "daemonsets": {daemonSets, mruby.ArgsReq(0) | mruby.ArgsOpt(2)}, 31 | "make_pod": {makePod, mruby.ArgsReq(1)}, 32 | "make_label_selector": {makeLabelSelector, mruby.ArgsReq(1)}, 33 | "make_field_selector": {makeFieldSelector, mruby.ArgsReq(1)}, 34 | "using": {using, mruby.ArgsReq(0) | mruby.ArgsOpt(2)}, 35 | "namespace": {namespace, mruby.ArgsReq(0) | mruby.ArgsOpt(2)}, 36 | "def_alias": {defAlias, mruby.ArgsReq(2)}, 37 | } 38 | } 39 | 40 | type verbFunc func(rk *RubyKube, args []*mruby.MrbValue, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) 41 | 42 | func pods(rk *RubyKube, args []*mruby.MrbValue, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 43 | var ( 44 | value mruby.Value 45 | err error 46 | ) 47 | 48 | newPodsObj, err := rk.classes.Pods.New() 49 | if err != nil { 50 | return nil, createException(m, err.Error()) 51 | } 52 | 53 | if value, err = newPodsObj.Update(args...); err != nil { 54 | return nil, createException(m, err.Error()) 55 | } 56 | return value, nil 57 | } 58 | 59 | func services(rk *RubyKube, args []*mruby.MrbValue, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 60 | var ( 61 | value mruby.Value 62 | err error 63 | ) 64 | 65 | newServicesObj, err := rk.classes.Services.New() 66 | if err != nil { 67 | return nil, createException(m, err.Error()) 68 | } 69 | 70 | if value, err = newServicesObj.Update(args...); err != nil { 71 | return nil, createException(m, err.Error()) 72 | } 73 | return value, nil 74 | } 75 | 76 | func deployments(rk *RubyKube, args []*mruby.MrbValue, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 77 | var ( 78 | value mruby.Value 79 | err error 80 | ) 81 | 82 | newDeploymentsObj, err := rk.classes.Deployments.New() 83 | if err != nil { 84 | return nil, createException(m, err.Error()) 85 | } 86 | 87 | if value, err = newDeploymentsObj.Update(args...); err != nil { 88 | return nil, createException(m, err.Error()) 89 | } 90 | return value, nil 91 | } 92 | 93 | func replicaSets(rk *RubyKube, args []*mruby.MrbValue, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 94 | var ( 95 | value mruby.Value 96 | err error 97 | ) 98 | 99 | newReplicaSetsObj, err := rk.classes.ReplicaSets.New() 100 | if err != nil { 101 | return nil, createException(m, err.Error()) 102 | } 103 | 104 | if value, err = newReplicaSetsObj.Update(args...); err != nil { 105 | return nil, createException(m, err.Error()) 106 | } 107 | return value, nil 108 | } 109 | 110 | func daemonSets(rk *RubyKube, args []*mruby.MrbValue, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 111 | var ( 112 | value mruby.Value 113 | err error 114 | ) 115 | 116 | newReplicaSetsObj, err := rk.classes.DaemonSets.New() 117 | if err != nil { 118 | return nil, createException(m, err.Error()) 119 | } 120 | 121 | if value, err = newReplicaSetsObj.Update(args...); err != nil { 122 | return nil, createException(m, err.Error()) 123 | } 124 | return value, nil 125 | } 126 | 127 | func makePod(rk *RubyKube, args []*mruby.MrbValue, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 128 | var ( 129 | err error 130 | ) 131 | 132 | newPodMakerObj, err := rk.classes.PodMaker.New() 133 | 134 | if err != nil { 135 | return nil, createException(m, err.Error()) 136 | } 137 | 138 | value, err := newPodMakerObj.self.Call("pod!", toValues(args)...) 139 | if err != nil { 140 | return nil, createException(m, err.Error()) 141 | } 142 | 143 | return value, nil 144 | } 145 | 146 | func makeLabelSelector(rk *RubyKube, args []*mruby.MrbValue, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 147 | if err := checkArgs(args, 1); err != nil { 148 | return nil, createException(m, err.Error()) 149 | } 150 | 151 | newLabelNameObj, err := rk.classes.LabelSelector.New(toValues(args)...) 152 | if err != nil { 153 | return nil, createException(m, err.Error()) 154 | } 155 | 156 | return newLabelNameObj.self, nil 157 | } 158 | 159 | func makeFieldSelector(rk *RubyKube, args []*mruby.MrbValue, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 160 | if err := checkArgs(args, 1); err != nil { 161 | return nil, createException(m, err.Error()) 162 | } 163 | 164 | newFieldNameObj, err := rk.classes.FieldSelector.New(toValues(args)...) 165 | if err != nil { 166 | return nil, createException(m, err.Error()) 167 | } 168 | 169 | return newFieldNameObj.self, nil 170 | } 171 | 172 | func using(rk *RubyKube, args []*mruby.MrbValue, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 173 | if len(args) == 0 { 174 | fmt.Println("%+v", rk.state) 175 | return nil, nil 176 | 177 | } 178 | 179 | if args[0].Type() != mruby.TypeHash { 180 | return nil, createException(m, "First argument must be a hash") 181 | } 182 | 183 | pc, err := NewParamsCollection(args[0], 184 | params{ 185 | allowed: []string{"namespace", "cluster", "context"}, 186 | required: []string{"namespace"}, 187 | valueType: mruby.TypeString, 188 | }, 189 | ) 190 | 191 | if err != nil { 192 | return nil, createException(m, err.Error()) 193 | } 194 | 195 | p := pc.ToMapOfStrings() 196 | 197 | rk.SetNamespace(p["namespace"]) 198 | 199 | if len(args) == 2 { 200 | //TODO: allow calling with a block 201 | } 202 | 203 | return nil, nil 204 | } 205 | 206 | func namespace(rk *RubyKube, args []*mruby.MrbValue, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 207 | if len(args) == 0 { 208 | return m.StringValue(rk.state.Namespace), nil 209 | } 210 | 211 | if args[0].Type() != mruby.TypeString { 212 | return nil, createException(m, "First argument must be a string") 213 | } 214 | 215 | ns := ValidString(args[0]) 216 | if ns == nil { 217 | return nil, createException(m, "First argument must be a non-empty string") 218 | } 219 | 220 | rk.SetNamespace(*ns) 221 | 222 | if len(args) == 2 { 223 | //TODO: allow calling with a block 224 | } 225 | 226 | return nil, nil 227 | } 228 | 229 | func defAlias(rk *RubyKube, args []*mruby.MrbValue, m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 230 | if len(args) != 2 { 231 | return nil, createException(m, "Must provide exactly two arguments") 232 | } 233 | 234 | if args[0].Type() != mruby.TypeSymbol && args[1].Type() != mruby.TypeSymbol { 235 | return nil, createException(m, "Both arguments must be symbols") 236 | } 237 | 238 | alias := args[0].String() 239 | verb := args[1].String() 240 | 241 | if _, ok := verbJumpTable[verb]; !ok { 242 | return nil, createException(m, fmt.Sprintf("Unknown verb %q", verb)) 243 | } 244 | 245 | aliasFunc := func(m *mruby.Mrb, _ *mruby.MrbValue) (mruby.Value, mruby.Value) { 246 | value, err := self.Call(verb, toValues(m.GetArgs())...) 247 | if err != nil { 248 | return nil, createException(m, err.Error()) 249 | } 250 | return value, nil 251 | } 252 | 253 | rk.mrb.TopSelf().SingletonClass().DefineMethod(alias, aliasFunc, mruby.ArgsAny()) 254 | 255 | return nil, nil 256 | } 257 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `kubeplay` – a new way to interact with Kubernetes 2 | 3 | > NOTE: _this project is still in an early stage_ 4 | 5 | > If you like this project, please checkout [TODOs](#todos) and open an issue if you'd like to contribute or discuss anything in particular. 6 | 7 | ## Usage example: easy REPL with Ruby syntax 8 | 9 | ```console 10 | > ./kubeplay 11 | kubeplay (namespace="*")> pods # list pods in the cluster 12 | 13 | kubeplay (namespace="*")> @pod = _.any # pick a random pod from the list 14 | kubeplay (namespace="*")> puts @pod.to_json # output the pod definition in JSON 15 | { 16 | "metadata": { 17 | ... 18 | }, 19 | "spec": { 20 | ... 21 | "containers": [ 22 | { 23 | ... 24 | } 25 | ], 26 | }, 27 | "status": { 28 | ... 29 | } 30 | } 31 | kubeplay (namespace="*")> puts @pod.to_ruby # output the same as a Ruby hash 32 | { ... } 33 | kubeplay (namespace="*")> @pod.delete! # I am a chaos monkey :) 34 | ``` 35 | 36 | ## Resource Verbs 37 | 38 | Currently implemented verbs are the following: 39 | 40 | - `pods` 41 | - `services` 42 | - `replicasets` 43 | - `daemonsets` 44 | 45 | Each of these can be used with index operator, e.g. `services[10]`, as well as `first`, `last` and `any` methonds. 46 | Any resource object can be converted to a JSON string with `to_json` method, or a Ruby object with `to_ruby`. 47 | 48 | With a Ruby object reprsentation you can do things like this: 49 | ```ruby 50 | @metadata = replicasets("*/").to_ruby.items.map do |k,v| 51 | v.metadata 52 | end 53 | 54 | @metadata.each do |i| 55 | puts "Name:\t#{i.name}" 56 | puts "Labels:\t#{i.labels}" 57 | puts 58 | end 59 | ``` 60 | 61 | You can define a verb aliases with `def_alias`, e.g. to create an `rs` verb alias for `replicasets` use 62 | ```Ruby 63 | def_alias :rs, :replicasets 64 | ``` 65 | 66 | By default a verb operates on all namespaces, hence `(namespace="*")` is shown in the prompt. 67 | You can switch current namespaces with `namespace` verb, e.g. 68 | ```console 69 | kubeplay (namespace="*")> namespace "kube-system" 70 | kubeplay (namespace="kube-system")> 71 | ``` 72 | To go back to all-namespaces mode, use `namespace "*"`. 73 | 74 | ### Resource Arguments 75 | 76 | A verb may take up two arguments in any order - a glob string and a block or hash. 77 | 78 | #### TL;DR 79 | 80 | To get all replica sets in `default` namespaces which have label `app` not matching `foo` or `bar` and label `version` matching `0.1` or `0.2` use 81 | 82 | ```ruby 83 | replicasets "default/", labels: -> { @app !~ %w(foo bar) ; @version =~ %w(0.1 0.2) ; } 84 | ``` 85 | 86 | To get all running pods with label `app` matching `foo` or `bar` use 87 | ```ruby 88 | pods { @app =~ %w(foo bar) ; status.phase == "Running" ; } 89 | ``` 90 | 91 | #### Glob Expressions 92 | 93 | Here are some examples illustrating the types of glob expressions that `kubeplay` understands. 94 | 95 | Get all pods in `kube-systems` namespace: 96 | ```ruby 97 | pods "kube-system/" 98 | ``` 99 | 100 | Get all pods in all namespace: 101 | ```ruby 102 | pods "*/" 103 | ``` 104 | 105 | Get all pods in current namespace with name matching `*foo*`: 106 | ```ruby 107 | pods "*foo*" 108 | ``` 109 | 110 | More specifically, this enables getting pods in a namespace other then current like this: 111 | ```console 112 | kubeplay (namespace="default")> pods "kube-system/foo-*" 113 | ``` 114 | Or, gettin pods with name matching `"bar-*` in all namespace like this: 115 | ```console 116 | kubeplay (namespace="default")> pods "*/bar-*" 117 | ``` 118 | 119 | > NOTE: if current namespace is `"*"`, `pods "*"` is the same as `pods`; `pods "*/*"` is always the same as `pods "*/"`. 120 | 121 | #### Label & Field Selectors 122 | 123 | Another argument a resource verb understand is a block specifying label and field selectors using special syntax outlined below. 124 | 125 | ##### Label Selector Syntax 126 | 127 | To match a label agains a set of values, use `label("name") =~ %w(foo bar)`, or `!~`. 128 | 129 | If you want to just get resources with a certain label to set anything, use `label("baz").defined?` 130 | 131 | This 132 | ```ruby 133 | { 134 | label("name") =~ %w(foo bar) 135 | label("baz").defined? 136 | } 137 | ``` 138 | will compile a selector string `name in (foo, bar),myapp`. 139 | 140 | And this 141 | ```ruby 142 | { 143 | label("name") !~ %w(foo bar) 144 | label("baz").defined? 145 | } 146 | ``` 147 | will compile a selector string `name notin (foo, bar),myapp`. 148 | 149 | Some well-known labels have shortuct, e.g. 150 | ```ruby 151 | { 152 | @app !~ %w(foo bar) 153 | @version =~ %w(0.1 0.2) 154 | @tier =~ %w(frontend backend) 155 | } 156 | ``` 157 | 158 | Simply pass a block like this: 159 | ```ruby 160 | replicasets { @app !~ %w(foo bar); @version =~ %w(0.1 0.2); @tier =~ %w(frontend backend); } 161 | ``` 162 | 163 | You can also use `make_label_selector` verb to construct these expressions and save those to variabels etc. 164 | 165 | ##### Field Selector Syntax 166 | 167 | This syntax is different, yet somewhat simpler. 168 | 169 | Here is a selector mathing all running pods: 170 | ```ruby 171 | { status.phase != :Running } 172 | ``` 173 | 174 | #### Using Slectors 175 | 176 | To get all running pods with label `tier` mathcing `backend`: 177 | ```ruby 178 | pods { status.phase != :Running ; @tier =~ "backend" ; } 179 | ``` 180 | 181 | Alternatively, if you prefer to be more explicit, you can use a hash: 182 | ```ruby 183 | pods fields: -> { status.phase != :Running }, labels: -> { @tier =~ "backend" } 184 | ``` 185 | 186 | You can also use compose selector expressions diretly as strings, if you prefer: 187 | ```ruby 188 | pods fields: "status.phase != Running", labels: "tier in (backend)" 189 | ``` 190 | 191 | ### Inspecting the Logs 192 | 193 | To get grep logs for any pod matching given selector 194 | 195 | ```ruby 196 | pods{ @name =~ "launch-generator" ; }.any.logs.grep ".*INFO:.*", ".*user-agent:.*" 197 | ``` 198 | 199 | ## Usage example: object generator with minimal input 200 | 201 | ```console 202 | > ./kubeplay -kubeconfig ~/.kube/config 203 | kubeplay (namespace="*")> @pod = make_pod(image: "errordeveloper/foo:latest") 204 | kubeplay (namespace="*")> puts _.to_json 205 | { 206 | "metadata": { 207 | "creationTimestamp": null, 208 | "labels": { 209 | "name": "foo" 210 | } 211 | }, 212 | "spec": { 213 | "containers": [ 214 | { 215 | "name": "foo", 216 | "image": "errordeveloper/foo:latest", 217 | "resources": {} 218 | } 219 | ] 220 | }, 221 | "status": {} 222 | } 223 | kubeplay (namespace="*")> @pod.create! 224 | kubeplay (namespace="*")> @pod.delete! 225 | 226 | kubeplay (namespace="*")> ^D 227 | > 228 | ``` 229 | 230 | ### TODOs 231 | 232 | Here are some TODO items and ideas. 233 | 234 | - [x] `pod.delete!` 235 | - [x] `pod.create!` 236 | - [x] `pod.logs` & `pod.logs.grep` 237 | - [x] `pods.logs` & `pods.logs.grep` 238 | - [ ] `pod.logs.pager` and `pod.logs.grep.pager` 239 | - [ ] grep logs in any set of resources 240 | - [ ] more fluent behaviour of set resources, e.g. `replicasets.pods` and not `replicasets.any.pods` 241 | - [ ] reverse lookup, e.g. given `@rs = replicasets.any`, `@rs.pods.any.owner` should be the same as `@rs` 242 | - [ ] way to run scripts and not just REPL 243 | - [ ] extend resource generator functionality 244 | - [ ] `ReplicaSet`+`Service` 245 | - [ ] `Kubefile` DSL 246 | 247 | #### Ideas 248 | 249 | - simple framework for controllers and 3rd-party resource (e.g. chaos monkey of sorts, or use terraform to create an exteranl resource and store URL in a secret, custom policy controller made easy) 250 | - multi-cluster support 251 | - resource diff 252 | - network policy tester framework 253 | - eval/exec code in a pod 254 | - test framework for apps, e.g. "Here is my app, it has a configmap and a secrete, and I want to test if it works" 255 | 256 | ### Building 257 | 258 | Get the source code and build the dependencies: 259 | 260 | ```bash 261 | go get github.com/Masterminds/glide 262 | go get -d github.com/errordeveloper/kubeplay 263 | cd $GOPATH/src/github.com/errordeveloper/kubeplay 264 | $GOPATH/bin/glide up -v 265 | make -C vendor/github.com/mitchellh/go-mruby libmruby.a 266 | go install ./rubykube 267 | ``` 268 | 269 | Build `kubeplay`: 270 | ```bash 271 | go build . 272 | ``` 273 | 274 | ### Credits 275 | 276 | The mruby integration was inspired by [@erikh's box](https://github.com/erikh/box), and some of the code was initially copied from there. 277 | -------------------------------------------------------------------------------- /rubykube/util.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "encoding/json" 5 | _ "errors" 6 | "fmt" 7 | "regexp" 8 | "runtime/debug" 9 | "strings" 10 | 11 | mruby "github.com/mitchellh/go-mruby" 12 | ) 13 | 14 | func init() { 15 | debug.SetPanicOnFault(true) 16 | } 17 | 18 | func createException(m *mruby.Mrb, msg string) mruby.Value { 19 | val, err := m.Class("Exception", nil).New(mruby.String(msg)) 20 | if err != nil { 21 | panic(fmt.Sprintf("could not construct exception for return: %v", err)) 22 | } 23 | 24 | return val 25 | } 26 | 27 | func extractStringArgs(args []*mruby.MrbValue) []string { 28 | strArgs := []string{} 29 | 30 | for _, arg := range args { 31 | if arg != nil && arg.Type() != mruby.TypeProc { 32 | strArgs = append(strArgs, arg.String()) 33 | } 34 | } 35 | 36 | return strArgs 37 | } 38 | 39 | func iterateHash(arg *mruby.MrbValue, fn func(*mruby.MrbValue, *mruby.MrbValue) error) error { 40 | hash := arg.Hash() 41 | 42 | // mruby does not expose native maps, just ruby primitives, so we have to 43 | // iterate through it with indexing functions instead of typical idioms. 44 | keys, err := hash.Keys() 45 | if err != nil { 46 | return err 47 | } 48 | 49 | for i := 0; i < keys.Array().Len(); i++ { 50 | key, err := keys.Array().Get(i) 51 | if err != nil { 52 | return err 53 | } 54 | 55 | value, err := hash.Get(key) 56 | if err != nil { 57 | return err 58 | } 59 | 60 | if err := fn(key, value); err != nil { 61 | return err 62 | } 63 | } 64 | 65 | return nil 66 | } 67 | 68 | func iterateArray(arg *mruby.MrbValue, fn func(int, *mruby.MrbValue) error) error { 69 | array := arg.Array() 70 | for i := 0; i < array.Len(); i++ { 71 | value, err := array.Get(i) 72 | if err != nil { 73 | return err 74 | } 75 | 76 | if err := fn(i, value); err != nil { 77 | return err 78 | } 79 | } 80 | 81 | return nil 82 | } 83 | 84 | func marshalToJSON(obj interface{}, m *mruby.Mrb) (mruby.Value, mruby.Value) { 85 | data, err := json.MarshalIndent(obj, "", " ") 86 | if err != nil { 87 | return nil, createException(m, err.Error()) 88 | } 89 | 90 | return m.StringValue(string(data)), nil 91 | } 92 | 93 | type paramProcHandler func(*mruby.MrbValue) error 94 | type params struct { 95 | allowed []string 96 | required []string 97 | skipKnown []string 98 | valueType mruby.ValueType 99 | procHandlers map[string]paramProcHandler 100 | } 101 | 102 | type paramsCollection struct { 103 | params map[string]interface{} 104 | valueType mruby.ValueType 105 | } 106 | 107 | func sliceToSet(slice []string) map[string]bool { 108 | set := map[string]bool{} 109 | for _, x := range slice { 110 | set[x] = true 111 | } 112 | return set 113 | } 114 | 115 | func ValidString(value *mruby.MrbValue) *string { 116 | v := value.String() 117 | if strings.TrimSpace(v) == "" { 118 | return nil 119 | } 120 | return &v 121 | } 122 | 123 | func NewParamsCollection(hash *mruby.MrbValue, spec params) (*paramsCollection, error) { 124 | params := make(map[string]interface{}) 125 | validKeys := append(spec.allowed, spec.skipKnown...) 126 | validKeySet := sliceToSet(validKeys) 127 | skipKeySet := sliceToSet(spec.skipKnown) 128 | 129 | const ( 130 | invalidValueTypeError = "invalid value type for %q parameter – should be %s" 131 | iterationError = "failed to iterte over %s value for %q parameter – %v" 132 | ) 133 | 134 | // Our params may have string, slice and map values, however there will be no nesting; 135 | // maps and slices are mostly to support labels and command args 136 | // there exist some more complex fields, e.g. volumes, but these are too complicated 137 | // to support with our simple generator, so we will have to provide a flattend version 138 | // and user will have to set things manually for the start, but eventually we can provide 139 | // separate helpers for volumes and other similar such stuff 140 | 141 | if err := iterateHash(hash, func(key0, value *mruby.MrbValue) error { 142 | k0 := key0.String() 143 | if _, ok := validKeySet[k0]; !ok { 144 | return fmt.Errorf("unknown parameter %q – not one of %v", k0, validKeys) 145 | } 146 | if _, ok := skipKeySet[k0]; ok { 147 | return nil 148 | } 149 | 150 | switch spec.valueType { 151 | case mruby.TypeHash: 152 | out := map[string]string{} 153 | if value.Type() != spec.valueType { 154 | return fmt.Errorf(invalidValueTypeError, k0, "a hash") 155 | } 156 | if err := iterateHash(value, func(key1, value *mruby.MrbValue) error { 157 | k1 := key1.String() 158 | if value.Type() != mruby.TypeString { 159 | return fmt.Errorf(invalidValueTypeError, fmt.Sprintf("%s::%s", k0, k1), "a string") 160 | } 161 | out[k1] = value.String() 162 | return nil 163 | }); err != nil { 164 | return fmt.Errorf(iterationError, "hash", k0, err) 165 | } 166 | params[k0] = out 167 | case mruby.TypeArray: 168 | out := &[]string{} 169 | if value.Type() != spec.valueType { 170 | return fmt.Errorf(invalidValueTypeError, k0, "an array") 171 | } 172 | if err := iterateArray(value, func(i1 int, value *mruby.MrbValue) error { 173 | if value.Type() != mruby.TypeString { 174 | return fmt.Errorf(invalidValueTypeError, fmt.Sprintf("%s[%d]", k0, i1), "a string") 175 | } 176 | *out = append(*out, value.String()) 177 | return nil 178 | }); err != nil { 179 | return fmt.Errorf(iterationError, "array", k0, err) 180 | } 181 | params[k0] = *out 182 | 183 | default: 184 | if value.Type() == mruby.TypeProc { 185 | if fn, ok := spec.procHandlers[k0]; ok { 186 | if err := fn(value); err != nil { 187 | return err 188 | } 189 | } else { 190 | return fmt.Errorf("parameter %q is a proc, but no handler found", k0) 191 | } 192 | return nil 193 | } 194 | // assume it may convert into a valid string, so it works for object that implement `to_s` 195 | v := ValidString(value) 196 | if v == nil { 197 | return fmt.Errorf("found invalid or empty string value for %q parameter", k0) 198 | } 199 | params[k0] = *v 200 | } 201 | 202 | return nil 203 | }); err != nil { 204 | return nil, fmt.Errorf("failed to parse given parameters – %v", err) 205 | } 206 | 207 | for _, x := range spec.required { 208 | if _, ok := params[x]; !ok { 209 | return nil, fmt.Errorf("missing required parameter %q", x) 210 | } 211 | } 212 | 213 | return ¶msCollection{params, spec.valueType}, nil 214 | } 215 | 216 | func (c *paramsCollection) ToMapOfStrings() map[string]string { 217 | if c.valueType != mruby.TypeString { 218 | return nil 219 | } 220 | 221 | out := map[string]string{} 222 | for k, v := range c.params { 223 | out[k] = v.(string) 224 | } 225 | return out 226 | } 227 | 228 | func (c *paramsCollection) ToMapOfMapsOfStrings() map[string]map[string]string { 229 | if c.valueType != mruby.TypeHash { 230 | return nil 231 | } 232 | 233 | out := map[string]map[string]string{} 234 | for k, v := range c.params { 235 | out[k] = v.(map[string]string) 236 | } 237 | return out 238 | } 239 | 240 | func (c *paramsCollection) ToMapOfSlicesOfStrings() map[string][]string { 241 | if c.valueType != mruby.TypeArray { 242 | return nil 243 | } 244 | 245 | out := map[string][]string{} 246 | for k, v := range c.params { 247 | out[k] = v.([]string) 248 | } 249 | return out 250 | } 251 | 252 | func checkArgs(args []*mruby.MrbValue, l int) error { 253 | if len(args) != l { 254 | return fmt.Errorf("Expected %d arg, got %d", l, len(args)) 255 | } 256 | 257 | return nil 258 | } 259 | 260 | func standardCheck(rk *RubyKube, args []*mruby.MrbValue, l int) error { 261 | if err := checkArgs(args, l); err != nil { 262 | return err 263 | } 264 | 265 | return nil 266 | } 267 | 268 | func getNamedMatch(re *regexp.Regexp, matchString string, submatchName string, target *string) { 269 | submatches := re.FindStringSubmatch(matchString) 270 | for i, name := range re.SubexpNames() { 271 | if name == submatchName { 272 | *target = submatches[i] 273 | } 274 | } 275 | } 276 | 277 | func toValues(args []*mruby.MrbValue) []mruby.Value { 278 | argv := []mruby.Value{} 279 | for _, arg := range args { 280 | argv = append(argv, mruby.Value(arg)) 281 | } 282 | return argv 283 | } 284 | 285 | func call(self *mruby.MrbValue, method string, args ...*mruby.MrbValue) (mruby.Value, error) { 286 | v, err := self.Call(method, toValues(args)...) 287 | if err != nil { 288 | return nil, err 289 | } 290 | return v, nil 291 | } 292 | 293 | func callWithException(m *mruby.Mrb, self *mruby.MrbValue, method string, args ...*mruby.MrbValue) (mruby.Value, mruby.Value) { 294 | v, err := call(self, method, args...) 295 | if err != nil { 296 | return nil, createException(m, err.Error()) 297 | } 298 | return v, nil 299 | } 300 | -------------------------------------------------------------------------------- /rubykube/rubykube.go: -------------------------------------------------------------------------------- 1 | package rubykube 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | "regexp" 8 | 9 | "github.com/chzyer/readline" 10 | //"github.com/erikh/box/signal" 11 | mruby "github.com/mitchellh/go-mruby" 12 | 13 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 | "k8s.io/client-go/kubernetes" 15 | "k8s.io/client-go/tools/clientcmd" 16 | ) 17 | 18 | var kubeconfig = flag.String("kubeconfig", os.ExpandEnv("${HOME}/.kube/config"), "absolute path to the kubeconfig file") 19 | 20 | type RubyKube struct { 21 | mrb *mruby.Mrb 22 | clientset *kubernetes.Clientset 23 | classes Classes 24 | readline *readline.Instance 25 | state *CurrentState 26 | } 27 | 28 | type Classes struct { 29 | Root *mruby.Class 30 | 31 | Pods *podsClass 32 | Pod *podClass 33 | 34 | Service *serviceClass 35 | Services *servicesClass 36 | 37 | Deployments *deploymentsClass 38 | Deployment *deploymentClass 39 | 40 | ReplicaSets *replicaSetsClass 41 | ReplicaSet *replicaSetClass 42 | 43 | DaemonSets *daemonSetsClass 44 | DaemonSet *daemonSetClass 45 | 46 | PodLogs *podLogsClass 47 | 48 | PodMaker *podMakerClass 49 | 50 | LabelSelector *labelSelectorClass 51 | LabelCollector *labelCollectorClass 52 | LabelKey *labelKeyClass 53 | 54 | FieldSelector *fieldSelectorClass 55 | FieldCollector *fieldCollectorClass 56 | FieldKey *fieldKeyClass 57 | } 58 | 59 | type CurrentState struct { 60 | Namespace string 61 | Cluster string 62 | Context string 63 | } 64 | 65 | func keep(omitFuncs []string, name string) bool { 66 | for _, fun := range omitFuncs { 67 | if name == fun { 68 | return false 69 | } 70 | } 71 | return true 72 | } 73 | 74 | // NewRubyKube may return an error on mruby or k8s.io/client-go issues. 75 | func NewRubyKube(omitFuncs []string, rl *readline.Instance) (*RubyKube, error) { 76 | flag.Parse() 77 | 78 | config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 79 | if err != nil { 80 | panic(fmt.Errorf("clientcmd.BuildConfigFromFlags: %v", err)) 81 | } 82 | 83 | fmt.Printf("kubeconfig=%+v\n", config) 84 | 85 | rk := &RubyKube{mrb: mruby.NewMrb(), readline: rl, state: &CurrentState{}} 86 | 87 | rk.mrb.DisableGC() 88 | 89 | for name, def := range verbJumpTable { 90 | if keep(omitFuncs, name) { 91 | rk.AddVerb(name, def.verbFunc, def.argSpec) 92 | } 93 | } 94 | 95 | for name, def := range funcJumpTable { 96 | if keep(omitFuncs, name) { 97 | inner := def.fun 98 | fn := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 99 | return inner(rk, m, self) 100 | } 101 | 102 | rk.mrb.TopSelf().SingletonClass().DefineMethod(name, fn, def.argSpec) 103 | } 104 | } 105 | 106 | //signal.SignalHandler(nil) 107 | 108 | rk.clientset, err = kubernetes.NewForConfig(config) 109 | if err != nil { 110 | panic(fmt.Errorf("kubernetes.NewForConfig: %v", err)) 111 | } 112 | 113 | rk.classes = Classes{Root: rk.mrb.DefineClass("RubyKube", nil)} 114 | 115 | rk.classes.Pods = newPodsClass(rk) 116 | rk.classes.Pods.defineOwnMethods() 117 | 118 | rk.classes.Pod = newPodClass(rk) 119 | rk.classes.Pod.defineOwnMethods() 120 | 121 | rk.classes.Services = newServicesClass(rk) 122 | rk.classes.Services.defineOwnMethods() 123 | 124 | rk.classes.Service = newServiceClass(rk) 125 | rk.classes.Service.defineOwnMethods() 126 | 127 | rk.classes.Deployments = newDeploymentsClass(rk) 128 | rk.classes.Deployments.defineOwnMethods() 129 | 130 | rk.classes.Deployment = newDeploymentClass(rk) 131 | rk.classes.Deployment.defineOwnMethods() 132 | 133 | rk.classes.ReplicaSets = newReplicaSetsClass(rk) 134 | rk.classes.ReplicaSets.defineOwnMethods() 135 | 136 | rk.classes.ReplicaSet = newReplicaSetClass(rk) 137 | rk.classes.ReplicaSet.defineOwnMethods() 138 | 139 | rk.classes.DaemonSets = newDaemonSetsClass(rk) 140 | rk.classes.DaemonSets.defineOwnMethods() 141 | 142 | rk.classes.DaemonSet = newDaemonSetClass(rk) 143 | rk.classes.DaemonSet.defineOwnMethods() 144 | 145 | rk.classes.PodLogs = newPodLogsClass(rk) 146 | rk.classes.PodLogs.defineOwnMethods() 147 | 148 | rk.classes.PodMaker = newPodMakerClass(rk) 149 | rk.classes.PodMaker.defineOwnMethods() 150 | 151 | rk.classes.LabelSelector = newLabelSelectorClass(rk) 152 | rk.classes.LabelSelector.defineOwnMethods() 153 | 154 | rk.classes.LabelCollector = newLabelCollectorClass(rk) 155 | rk.classes.LabelCollector.defineOwnMethods() 156 | 157 | rk.classes.LabelKey = newLabelKeyClass(rk) 158 | rk.classes.LabelKey.defineOwnMethods() 159 | 160 | rk.classes.FieldSelector = newFieldSelectorClass(rk) 161 | rk.classes.FieldSelector.defineOwnMethods() 162 | 163 | rk.classes.FieldCollector = newFieldCollectorClass(rk) 164 | rk.classes.FieldCollector.defineOwnMethods() 165 | 166 | rk.classes.FieldKey = newFieldKeyClass(rk) 167 | rk.classes.FieldKey.defineOwnMethods() 168 | 169 | rk.SetNamespace("*") 170 | if err := rk.applyPatches(); err != nil { 171 | return nil, err 172 | } 173 | 174 | return rk, nil 175 | } 176 | 177 | // AddVerb adds a function to the mruby dispatch as well as adding hooks around 178 | // the call to ensure containers are committed and intermediate layers are 179 | // cleared. 180 | func (rk *RubyKube) AddVerb(name string, fn verbFunc, args mruby.ArgSpec) { 181 | hookFunc := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { 182 | args := m.GetArgs() 183 | return fn(rk, args, m, self) 184 | } 185 | 186 | rk.mrb.TopSelf().SingletonClass().DefineMethod(name, hookFunc, args) 187 | } 188 | 189 | // Run the script. 190 | func (rk *RubyKube) Run(script string) (*mruby.MrbValue, error) { 191 | var value *mruby.MrbValue 192 | 193 | value, err := rk.mrb.LoadString(script) 194 | if err != nil { 195 | return nil, err 196 | } 197 | 198 | if _, err := value.Call("inspect"); err != nil { 199 | return value, fmt.Errorf("could not call `#inspect` [%q]", err) 200 | } 201 | 202 | getLastValue := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { return value, nil } 203 | 204 | if value.Type() != mruby.TypeNil { 205 | rk.mrb.TopSelf().SingletonClass().DefineMethod("_", getLastValue, mruby.ArgsReq(0)) 206 | } 207 | 208 | rk.mrb.TopSelf().SingletonClass().DefineMethod("$?", getLastValue, mruby.ArgsReq(0)) 209 | 210 | return value, nil 211 | } 212 | 213 | // RunCode runs the ruby value (a proc) and returns the result. 214 | func (rk *RubyKube) RunCode(block *mruby.MrbValue, stackKeep int) (*mruby.MrbValue, int, error) { 215 | var value *mruby.MrbValue 216 | 217 | keep, value, err := rk.mrb.RunWithContext(block, rk.mrb.TopSelf(), stackKeep) 218 | if err != nil { 219 | return nil, keep, err 220 | } 221 | 222 | if _, err := value.Call("inspect"); err != nil { 223 | return value, keep, fmt.Errorf("could not call `#inspect` [%q]", err) 224 | } 225 | 226 | getLastValue := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { return value, nil } 227 | 228 | if value.Type() != mruby.TypeNil { 229 | rk.mrb.TopSelf().SingletonClass().DefineMethod("_", getLastValue, mruby.ArgsReq(0)) 230 | } 231 | 232 | rk.mrb.TopSelf().SingletonClass().DefineMethod("$?", getLastValue, mruby.ArgsReq(0)) 233 | 234 | return value, keep, nil 235 | 236 | } 237 | 238 | func (rk *RubyKube) NormalPrompt() { 239 | rk.readline.SetPrompt(fmt.Sprintf("kubeplay (namespace=%q)> ", rk.state.Namespace)) 240 | } 241 | 242 | func (rk *RubyKube) MultiLinePrompt() { 243 | rk.readline.SetPrompt(fmt.Sprintf("kubeplay (namespace=%q)> ....| ", rk.state.Namespace)) 244 | } 245 | 246 | func (rk *RubyKube) SetNamespace(ns string) { 247 | if ns == "" { 248 | ns = "*" 249 | } 250 | rk.state.Namespace = ns 251 | rk.readline.SetPrompt(fmt.Sprintf("kubeplay (namespace=%q)> ", rk.state.Namespace)) 252 | } 253 | 254 | func (rk *RubyKube) GetNamespace(override string) string { 255 | ns := rk.state.Namespace 256 | if override != "" { 257 | ns = override 258 | } 259 | 260 | if ns == "*" { 261 | return "" 262 | } 263 | return ns 264 | } 265 | 266 | func (rk *RubyKube) GetDefaultNamespace(override string) string { 267 | ns := rk.state.Namespace 268 | if override != "" { 269 | ns = override 270 | } 271 | 272 | if ns == "*" { 273 | return "default" 274 | } 275 | return ns 276 | } 277 | 278 | func (rk *RubyKube) resourceArgs(args []*mruby.MrbValue) (string, *regexp.Regexp, *metav1.ListOptions, error) { 279 | var ( 280 | ns string 281 | nameRegexp *regexp.Regexp 282 | listOptions metav1.ListOptions 283 | ) 284 | 285 | validName := "[a-z0-9]([-a-z0-9]*[a-z0-9])?" 286 | namespacePrefix := fmt.Sprintf(`?P%s|\*`, validName) 287 | 288 | // pods "foo/" 289 | // pods "*/" 290 | allWithinNamespace := regexp.MustCompile( 291 | fmt.Sprintf(`^(%s)\/(\*)?$`, 292 | namespacePrefix)) 293 | // pods "*-bar" 294 | nameBeginsWith := regexp.MustCompile( 295 | fmt.Sprintf(`^((%s)\/)?(?P%s(-)?)\*$`, 296 | namespacePrefix, 297 | validName)) 298 | // pods "bar-*" 299 | nameEndsWith := regexp.MustCompile( 300 | fmt.Sprintf(`^((%s)\/)?\*(?P(-)?%s)$`, 301 | namespacePrefix, 302 | validName)) 303 | // pods "*-bar-*" 304 | nameContains := regexp.MustCompile( 305 | fmt.Sprintf(`^((%s)\/)?\*(?P(-)?%s(-)?)\*$`, 306 | namespacePrefix, 307 | validName)) 308 | 309 | // TODO pods "*-foo-*-bar-*" 310 | 311 | hasNameGlob := false 312 | hasSelectors := false 313 | 314 | parseNameGlob := func(arg *mruby.MrbValue) error { 315 | s := arg.String() 316 | var p string 317 | switch { 318 | case allWithinNamespace.MatchString(s): 319 | getNamedMatch(allWithinNamespace, s, "namespace", &ns) 320 | case nameBeginsWith.MatchString(s): 321 | getNamedMatch(nameBeginsWith, s, "namespace", &ns) 322 | getNamedMatch(nameBeginsWith, s, "name", &p) 323 | nameRegexp = regexp.MustCompile(fmt.Sprintf("^(%s)-?(%s)$", p, validName)) 324 | case nameEndsWith.MatchString(s): 325 | getNamedMatch(nameEndsWith, s, "namespace", &ns) 326 | getNamedMatch(nameEndsWith, s, "name", &p) 327 | nameRegexp = regexp.MustCompile(fmt.Sprintf("^(%s)-?(%s)$", validName, p)) 328 | case nameContains.MatchString(s): 329 | getNamedMatch(nameContains, s, "namespace", &ns) 330 | getNamedMatch(nameContains, s, "name", &p) 331 | nameRegexp = regexp.MustCompile(fmt.Sprintf("^(%s)?-?(%s)-?(%s)?$", validName, p, validName)) 332 | default: 333 | if s != "*" { 334 | return fmt.Errorf("Invalid glob expression - try `pods \"/\"`, `pods \"*/\"` or `pods \"*/foo-*\"`\n") 335 | } 336 | } 337 | 338 | hasNameGlob = true 339 | return nil 340 | } 341 | 342 | evalLabelSelector := func(block *mruby.MrbValue) error { 343 | newLabelNameObj, err := rk.classes.LabelSelector.New(block) 344 | if err != nil { 345 | return err 346 | } 347 | 348 | listOptions.LabelSelector = newLabelNameObj.self.String() 349 | 350 | return nil 351 | } 352 | 353 | evalFieldSelector := func(block *mruby.MrbValue) error { 354 | newFieldNameObj, err := rk.classes.FieldSelector.New(block) 355 | if err != nil { 356 | return err 357 | } 358 | 359 | listOptions.FieldSelector = newFieldNameObj.self.String() 360 | 361 | return nil 362 | } 363 | 364 | parseSelectors := func(arg *mruby.MrbValue) error { 365 | stringCollection, err := NewParamsCollection(arg, 366 | params{ 367 | allowed: []string{"labels", "fields"}, 368 | required: []string{}, 369 | valueType: mruby.TypeString, 370 | procHandlers: map[string]paramProcHandler{ 371 | "labels": evalLabelSelector, 372 | "fields": evalFieldSelector, 373 | }, 374 | }, 375 | ) 376 | 377 | if err != nil { 378 | return err 379 | } 380 | 381 | p := stringCollection.ToMapOfStrings() 382 | 383 | if v, ok := p["labels"]; ok { 384 | listOptions.LabelSelector = v 385 | } 386 | if v, ok := p["fields"]; ok { 387 | listOptions.FieldSelector = v 388 | } 389 | 390 | hasSelectors = true 391 | return nil 392 | } 393 | 394 | fail := func(err error) (string, *regexp.Regexp, *metav1.ListOptions, error) { 395 | return "", nil, nil, err 396 | } 397 | 398 | secondArgError := func(kind string) error { 399 | return fmt.Errorf("Found second " + kind + " argument, only single one is allowed - use array notation for mulptiple queries") 400 | } 401 | 402 | if len(args) >= 1 { 403 | switch args[0].Type() { 404 | case mruby.TypeString: 405 | if err := parseNameGlob(args[0]); err != nil { 406 | return fail(err) 407 | } 408 | case mruby.TypeHash: 409 | if err := parseSelectors(args[0]); err != nil { 410 | return fail(err) 411 | } 412 | case mruby.TypeProc: 413 | if err := evalLabelSelector(args[0]); err != nil { 414 | return fail(err) 415 | } 416 | if err := evalFieldSelector(args[0]); err != nil { 417 | return fail(err) 418 | } 419 | case mruby.TypeArray: 420 | // TODO: we could allow users to collect object matching multiple globs 421 | return fail(fmt.Errorf("Not yet implemented!")) 422 | } 423 | } 424 | 425 | if len(args) >= 2 { 426 | 427 | switch args[1].Type() { 428 | case mruby.TypeString: 429 | if hasNameGlob { 430 | return fail(secondArgError("glob")) 431 | 432 | } 433 | if err := parseNameGlob(args[1]); err != nil { 434 | return fail(err) 435 | } 436 | case mruby.TypeHash: 437 | if hasSelectors { 438 | return fail(secondArgError("selector")) 439 | } 440 | if err := parseSelectors(args[1]); err != nil { 441 | return fail(err) 442 | } 443 | case mruby.TypeProc: 444 | if hasSelectors { 445 | return fail(secondArgError("selector")) 446 | } 447 | if err := evalLabelSelector(args[1]); err != nil { 448 | return fail(err) 449 | } 450 | if err := evalFieldSelector(args[0]); err != nil { 451 | return fail(err) 452 | } 453 | case mruby.TypeArray: 454 | return fail(fmt.Errorf("Only single array argument is allowed")) 455 | } 456 | } 457 | 458 | if len(args) >= 3 { 459 | return fail(fmt.Errorf("Maximum 2 arguments allowed")) 460 | } 461 | 462 | return ns, nameRegexp, &listOptions, nil 463 | } 464 | 465 | // Mrb returns the mrb (mruby) instance the builder is using. 466 | func (rk *RubyKube) Mrb() *mruby.Mrb { 467 | return rk.mrb 468 | } 469 | 470 | // Close tears down all functions of the RubyKube, preparing it for exit. 471 | func (rk *RubyKube) Close() error { 472 | rk.mrb.EnableGC() 473 | rk.mrb.FullGC() 474 | rk.mrb.Close() 475 | return nil 476 | } 477 | --------------------------------------------------------------------------------