Skip to content
This repository was archived by the owner on Mar 7, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
# runner
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fyabslabs%2Frunner.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fyabslabs%2Frunner?ref=badge_shield)

## implemented executors

## executors to be implemented

- docker
- kubernetes
- shell (what shell?)

## project structure

## License
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fyabslabs%2Frunner.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fyabslabs%2Frunner?ref=badge_large)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fyabslabs%2Frunner.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fyabslabs%2Frunner?ref=badge_large)
3 changes: 3 additions & 0 deletions common/README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Common Package

This package fakes the common Package until it's fully implemented.
70 changes: 70 additions & 0 deletions common/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2018 VRSG | Verwaltungsrechenzentrum AG, St.Gallen
* All Rights Reserved.
*/

package common

import (
"fmt"
"io/ioutil"
"os"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

type ConfigReader interface {
Unmarshal(data []byte, o interface{}) error
}

type ValidateableConfiguration interface {
Validate() error
}

type ConfigReaderFunc func(data []byte, o interface{}) error

func (c ConfigReaderFunc) Unmarshal(data []byte, o interface{}) error {
return c(data, o)
}

func readConfigFile(configReader ConfigReader, configFile string, obj interface{}) error {
configFile = os.ExpandEnv(configFile)

if _, err := os.Stat(configFile); err != nil {
fmt.Println("CONF-3e126710", err, configFile)
return nil
}

configStr, err := ioutil.ReadFile(configFile) //nolint: gosec

if err != nil {
return status.Errorf(codes.Internal, "failed to read config file %s: %v", configFile, err)
}

configStr = []byte(os.ExpandEnv(string(configStr)))

if err := configReader.Unmarshal(configStr, obj); err != nil {
return status.Errorf(codes.Internal, "error parse config file %s: %v", configFile, err)
}

return nil
}

// ReadConfig deserializes each configfile to the target obj using the configReader
// env vars are replaced in the file path
func ReadConfig(configReader ConfigReader, obj interface{}, configFiles ...string) error {
for _, cf := range configFiles {
if err := readConfigFile(configReader, cf, obj); err != nil {
return err
}
}

if validateable, ok := obj.(ValidateableConfiguration); ok {
if err := validateable.Validate(); err != nil {
return err
}
}

return nil
}
24 changes: 24 additions & 0 deletions common/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package common

// JobStatus that represents the Status of a Job
type JobStatus int

// JobStatus implementation as enum
const (

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is aligned to the yabs/api, looks good

UNKNOWN JobStatus = iota
CREATED
PENDING
RUNNING
FAILED
SUCCESS
CANCELED
SKIPPED
MANUAL
STUCK
RETRIED
PAUSED
SUSPENDED
)

type Job struct {
}
20 changes: 20 additions & 0 deletions configuration/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package configuration

import (
"git.workshop21.ch/go/abraxas/configuration/yaml"
)

type Config struct {
Env string
GRPCPort string
GatewayPort string
ImageBaseUrl string
HttpsPort int32
}

func ReadConfig() (*Config, error) {
config := &Config{}
err := yaml.ReadConfig(config,
"./config/config.yaml")
return config, err
}
21 changes: 21 additions & 0 deletions configuration/yaml/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2018 VRSG | Verwaltungsrechenzentrum AG, St.Gallen
* All Rights Reserved.
*/

package yaml

import (
"git.workshop21.ch/go/abraxas/configuration"
"github.com/ghodss/yaml"
)

var ConfigReader = configuration.ConfigReaderFunc(yamlUnmarshalNoOpts)

func yamlUnmarshalNoOpts(y []byte, o interface{}) error {
return yaml.Unmarshal(y, o)
}

func ReadConfig(obj interface{}, configFiles ...string) error {
return configuration.ReadConfig(ConfigReader, obj, configFiles...)
}
5 changes: 5 additions & 0 deletions executors/engine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package executors

type ExecutionEngine struct {
Executors []Executor
}
16 changes: 16 additions & 0 deletions executors/executor_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package executors

import (
"github.com/yabslabs/runner/common"
"github.com/yabslabs/runner/executors/kubernetes"
"github.com/yabslabs/runner/runner"
)

var types = []Executor{&kubernetes.KubernetesExecutor{}}

type Executor interface {
GetKind() string
GetStatus() runner.RunnerStatus
GetJobStatus() common.JobStatus
Run(common.Job) common.JobStatus
}
161 changes: 161 additions & 0 deletions executors/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package kubernetes

import (
"fmt"
"io/ioutil"
"io"
"os"

"github.com/yabslabs/runner/common"
"github.com/yabslabs/runner/runner"
"sigs.k8s.io/controller-runtime/pkg/client/config"

"github.com/sirupsen/logrus"
api "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
restclient "k8s.io/client-go/rest"
)

// RemoteExecutor defines the interface accepted by the Exec command - provided for test stubbing
type RemoteExecutor interface {
Execute(method string, url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool) error
}

// DefaultRemoteExecutor is the standard implementation of remote command execution
type DefaultRemoteExecutor struct{}

func (*DefaultRemoteExecutor) Execute(method string, url *url.URL, config *restclient.Config, stdin io.Reader, stdout, stderr io.Writer, tty bool) error {
exec, err := remotecommand.NewSPDYExecutor(config, method, url)
if err != nil {
return err
}

return exec.Stream(remotecommand.StreamOptions{
Stdin: stdin,
Stdout: stdout,
Stderr: stderr,
Tty: tty,
})
}


func (e *KubernetesExecutor) GetKind() string {
return "Kubernetes Executor"
}

func (e *KubernetesExecutor) GetStatus() runner.RunnerStatus {
return 1
}

func (e *KubernetesExecutor) GetJobStatus() common.JobStatus {
return 1
}

func (e *KubernetesExecutor) Run(job common.Job) common.JobStatus {
pod, err := e.Client.CoreV1().Pods(e.Namespace).Get(e.PodName, metav1.GetOptions{})
if err != nil {
return err
}

if pod.Status.Phase != api.PodRunning {
return fmt.Errorf("Pod '%s' (on namespace '%s') is not running and cannot execute commands; current phase is '%s'",
e.PodName, e.Namespace, pod.Status.Phase)
}

containerName := e.ContainerName
if len(containerName) == 0 {
logrus.Infof("defaulting container name to '%s'", pod.Spec.Containers[0].Name)
containerName = pod.Spec.Containers[0].Name
}

// TODO: refactor with terminal helpers from the edit utility once that is merged
var stdin io.Reader
if e.Stdin {
stdin = e.In
}

// TODO: consider abstracting into a client invocation or client helper
req := e.Client.CoreV1().RESTClient().Post().
Resource("pods").
Name(pod.Name).
Namespace(pod.Namespace).
SubResource("exec").
Param("container", containerName)
req.VersionedParams(&api.PodExecOptions{
Container: containerName,
Command: e.Command,
Stdin: stdin != nil,
Stdout: e.Out != nil,
Stderr: e.Err != nil,
}, scheme.ParameterCodec)

return e.Executor.Execute("POST", req.URL(), e.Config, stdin, e.Out, e.Err, false)

}

type KubernetesExecutor struct {
Namespace string
PodName string
ContainerName string
Stdin bool
Command []string

In io.Reader
Out io.Writer
Err io.Writer

Executor RemoteExecutor
Client *kubernetes.Clientset
Config *restclient.Config
}

func CreateKubernetesExecutor()(*KubernetesExecutor, error){
config, err := configuration.ReadConfig()
if err != nil {
log.Error(err, "unable to set up client config")
return nil, err
}
cfg, err := config.GetConfig()
if err != nil {
log.Error(err, "unable to set up client config")
return nil, err
}
hostname, err := os.Hostname()
if err != nil {
log.Error(err, "unable to get hostname")
return nil, err
}
clientset, err := GetClientSet(cfg)
if err != nil {
log.Error(err, "unable to get clientset")
return nil, err
}
namespace, err := GetNamespaceFromFile()
if err != nil {
log.Error(err, "unable to read namespacefile")
return nil, err
}
return KubernetesExecutor{
PodName: hostname,
Client: clientset,
Config: cfg,
Namespace: namespace,
}, nil
}


func GetClientSet(config *rest.Config) (*kubernetes.Clientset, error) {
return kubernetes.NewForConfig(config)
}

func GetNamespaceFromFile()(string,error){

b, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
if err != nil {
fmt.Print(err)

}
return b,err
}
8 changes: 8 additions & 0 deletions executors/register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package executors

func (e *ExecutionEngine) RegisterTypes() error {
for _, eType := range types {
e.Executors = append(e.Executors, eType)
}
return nil
}
40 changes: 40 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module github.com/yabslabs/runner

require (
git.workshop21.ch/go/abraxas v0.0.0-20190128134023-1863c65a9857
github.com/aws/aws-sdk-go v1.16.26 // indirect
github.com/ghodss/yaml v1.0.0
github.com/go-logr/logr v0.1.0 // indirect
github.com/go-logr/zapr v0.1.0 // indirect
github.com/gogo/protobuf v1.2.0 // indirect
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect
github.com/googleapis/gnostic v0.2.0 // indirect
github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f // indirect
github.com/imdario/mergo v0.3.7 // indirect
github.com/json-iterator/go v1.1.5 // indirect
github.com/kubernetes/client-go v10.0.0+incompatible // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/onsi/ginkgo v1.7.0 // indirect
github.com/onsi/gomega v1.4.3 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/sirupsen/logrus v1.3.0
github.com/spf13/pflag v1.0.3 // indirect
go.uber.org/atomic v1.3.2 // indirect
go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.9.1 // indirect
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 // indirect
golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1 // indirect
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c // indirect
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922 // indirect
google.golang.org/grpc v1.18.0
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
k8s.io/api v0.0.0-20190202010521-49be0e3344fe
k8s.io/apimachinery v0.0.0-20190201131811-df262fa1a1ba
k8s.io/client-go v10.0.0+incompatible
k8s.io/klog v0.1.0 // indirect
sigs.k8s.io/controller-runtime v0.1.10
sigs.k8s.io/yaml v1.1.0 // indirect
)
Loading