func (n *Impl) Create(ctx context.Context) error {
	if err := n.CreateConfig(ctx); err != nil {
		return fmt.Errorf("node %s failed to create config-map %w", n.Name(), err)
	}
	if err := n.CreatePod(ctx); err != nil {
		return fmt.Errorf("node %s failed to create pod %w", n.Name(), err)
	}
	if err := n.CreateService(ctx); err != nil {
		return fmt.Errorf("node %s failed to create service %w", n.Name(), err)
	}
	return nil
}
Create will create the node in the k8s cluster with all services and config
maps.
package node
import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"path/filepath"
	"sync"
	log "github.com/sirupsen/logrus"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/remotecommand"
	"k8s.io/utils/pointer"
	tpb "github.com/google/kne/proto/topo"
)
type Interface interface {
	Name() string
	GetNamespace() string
	GetProto() *tpb.Node
}
type Implementation interface {
	Create(context.Context) error
	Status(context.Context) (corev1.PodPhase, error)
	Delete(context.Context) error
	Pod(context.Context) (*corev1.Pod, error)
	Service(context.Context) (*corev1.Service, error)
}
type Certer interface {
	GenerateSelfSigned(context.Context) error
}
type ConfigPusher interface {
	ConfigPush(context.Context, io.Reader) error
}
type Resetter interface {
	ResetCfg(ctx context.Context) error
}
type Node interface {
	Interface
	Implementation
}
type NewNodeFn func(n *Impl) (Node, error)
var (
	mu          sync.Mutex
	nodeTypes   = map[tpb.Node_Type]NewNodeFn{}
	vendorTypes = map[tpb.Vendor]NewNodeFn{}
)
func Register(t tpb.Node_Type, fn NewNodeFn) {
	mu.Lock()
	if _, ok := nodeTypes[t]; ok {
		panic(fmt.Sprintf("duplicate registration for %T", t))
	}
	nodeTypes[t] = fn
	mu.Unlock()
}
func Vendor(v tpb.Vendor, fn NewNodeFn) {
	mu.Lock()
	if _, ok := vendorTypes[v]; ok {
		panic(fmt.Sprintf("duplicate registration for %T", v))
	}
	vendorTypes[v] = fn
	mu.Unlock()
}
type Impl struct {
	Namespace  string
	KubeClient kubernetes.Interface
	RestConfig *rest.Config
	Proto      *tpb.Node
	BasePath   string
}
func New(namespace string, pb *tpb.Node, kClient kubernetes.Interface, rCfg *rest.Config, bp string) (Node, error) {
	return getImpl(&Impl{
		Namespace:  namespace,
		Proto:      pb,
		KubeClient: kClient,
		RestConfig: rCfg,
		BasePath:   bp,
	})
}
func (n *Impl) GetProto() *tpb.Node {
	return n.Proto
}
func (n *Impl) GetNamespace() string {
	return n.Namespace
}
const (
	defaultInitContainerImage = "networkop/init-wait:latest"
)
func ToEnvVar(kv map[string]string) []corev1.EnvVar {
	var envVar []corev1.EnvVar
	for k, v := range kv {
		envVar = append(envVar, corev1.EnvVar{
			Name:  k,
			Value: v,
		})
	}
	return envVar
}
func ToResourceRequirements(kv map[string]string) corev1.ResourceRequirements {
	r := corev1.ResourceRequirements{
		Requests: map[corev1.ResourceName]resource.Quantity{},
	}
	if v, ok := kv["cpu"]; ok {
		r.Requests["cpu"] = resource.MustParse(v)
	}
	if v, ok := kv["memory"]; ok {
		r.Requests["memory"] = resource.MustParse(v)
	}
	return r
}