Skip to content

Commit

Permalink
refactor(runner): rework exec and init functions
Browse files Browse the repository at this point in the history
  • Loading branch information
corrieriluca committed Aug 21, 2024
1 parent b953339 commit c2202a7
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 63 deletions.
23 changes: 21 additions & 2 deletions internal/runner/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,24 @@ import (

const PlanArtifact string = "/tmp/plan.out"

func (r *Runner) plan() (string, error) {
// Run the `init` command
func (r *Runner) execInit() error {
log.Infof("launching terraform init in %s", r.workingDir)
if r.exec == nil {
err := errors.New("terraform or terragrunt binary not installed")
return err
}
err := r.exec.Init(r.workingDir)
if err != nil {
log.Errorf("error executing terraform init: %s", err)
return err
}
return nil
}

// Run the `plan` command and save the plan artifact in the datastore
// Returns the sha256 sum of the plan artifact
func (r *Runner) execPlan() (string, error) {
log.Infof("starting terraform plan")
if r.exec == nil {
err := errors.New("terraform or terragrunt binary not installed")
Expand Down Expand Up @@ -72,7 +89,9 @@ func (r *Runner) plan() (string, error) {
return b64.StdEncoding.EncodeToString(sum[:]), nil
}

func (r *Runner) apply() (string, error) {
// Run the `apply` command, by default with the plan artifact from the previous plan run
// Returns the sha256 sum of the plan artifact used
func (r *Runner) execApply() (string, error) {
log.Infof("starting terraform apply")
if r.exec == nil {
err := errors.New("terraform or terragrunt binary not installed")
Expand Down
2 changes: 1 addition & 1 deletion internal/runner/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func FetchRepositoryContent(repo *configv1alpha1.TerraformRepository, branch str
if err != nil {
return &git.Repository{}, err
}
return git.PlainClone(WorkingDir, false, cloneOptions)
return git.PlainClone(RepositoryDir, false, cloneOptions)
}

func getCloneOptions(repository config.RepositoryConfig, URL, branch string) (*git.CloneOptions, error) {
Expand Down
109 changes: 49 additions & 60 deletions internal/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"os"
"path/filepath"
"strconv"
"time"

Expand All @@ -15,19 +16,16 @@ import (
"github.com/padok-team/burrito/internal/annotations"
"github.com/padok-team/burrito/internal/burrito/config"
datastore "github.com/padok-team/burrito/internal/datastore/client"
"k8s.io/apimachinery/pkg/runtime"
"github.com/padok-team/burrito/internal/utils"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"

utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/padok-team/burrito/internal/runner/tools"
runnerutils "github.com/padok-team/burrito/internal/utils/runner"
)

const WorkingDir string = "/runner/repository"
const RepositoryDir string = "/runner/repository"

type Runner struct {
config *config.Config
Expand All @@ -38,6 +36,7 @@ type Runner struct {
run *configv1alpha1.TerraformRun
repository *configv1alpha1.TerraformRepository
gitRepository *git.Repository
workingDir string
}

func New(c *config.Config) *Runner {
Expand All @@ -46,71 +45,58 @@ func New(c *config.Config) *Runner {
}
}

// Entrypoint function of the runner. Initializes the runner, executes the action and updates the layer annotations.
func (r *Runner) Exec() error {
client := datastore.NewDefaultClient()
if r.config.Datastore.TLS {
log.Info("using TLS for datastore")
client.Scheme = "https"
}
r.datastore = client
var commit string
ann := map[string]string{}

err := r.init()
if err != nil {
log.Errorf("error initializing runner: %s", err)
return err
}
if r.gitRepository != nil {
ref, _ := r.gitRepository.Head()
commit = ref.Hash().String()

err = r.execInit()
if err != nil {
log.Errorf("error executing init: %s", err)
return err
}

ann := map[string]string{}
ref, _ := r.gitRepository.Head()
commit := ref.Hash().String()

switch r.config.Runner.Action {
case "plan":
sum, err := r.plan()
ann[annotations.LastPlanDate] = time.Now().Format(time.UnixDate)
if err == nil {
ann[annotations.LastPlanCommit] = commit
sum, err := r.execPlan()
if err != nil {
return err
}
ann[annotations.LastPlanDate] = time.Now().Format(time.UnixDate)
ann[annotations.LastPlanRun] = fmt.Sprintf("%s/%s", r.run.Name, strconv.Itoa(r.run.Status.Retries))
ann[annotations.LastPlanSum] = sum
ann[annotations.LastPlanCommit] = commit

case "apply":
sum, err := r.apply()
sum, err := r.execApply()
if err != nil {
return err
}
ann[annotations.LastApplyDate] = time.Now().Format(time.UnixDate)
ann[annotations.LastApplySum] = sum
if err == nil {
ann[annotations.LastApplyCommit] = commit
}
ann[annotations.LastApplyCommit] = commit
default:
err = errors.New("unrecognized runner action, if this is happening there might be a version mismatch between the controller and runner")
return errors.New("unrecognized runner action, if this is happening there might be a version mismatch between the controller and runner")
}

err = annotations.Add(context.TODO(), r.client, r.layer, ann)
if err != nil {
log.Errorf("error during runner execution: %s", err)
}

annotErr := annotations.Add(context.TODO(), r.client, r.layer, ann)
if annotErr != nil {
log.Errorf("could not update terraform layer annotations: %s", err)
return err
}
log.Infof("successfully updated terraform layer annotations")

return err
}

func newK8SClient() (client.Client, error) {
scheme := runtime.NewScheme()
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(configv1alpha1.AddToScheme(scheme))
cl, err := client.New(ctrl.GetConfigOrDie(), client.Options{
Scheme: scheme,
})
if err != nil {
return nil, err
}
return cl, err
return nil
}

// Retrieve linked resources (layer, run, repository) from the Kubernetes API.
func (r *Runner) getResources() error {
layer := &configv1alpha1.TerraformLayer{}
log.Infof("getting layer %s/%s", r.config.Runner.Layer.Namespace, r.config.Runner.Layer.Name)
Expand All @@ -123,6 +109,8 @@ func (r *Runner) getResources() error {
}
log.Infof("successfully retrieved layer")
r.layer = layer
r.workingDir = filepath.Join(RepositoryDir, r.layer.Spec.Path)

r.run = &configv1alpha1.TerraformRun{}
log.Infof("getting run %s/%s", layer.Namespace, layer.Status.LastRun.Name)
err = r.client.Get(context.TODO(), types.NamespacedName{
Expand All @@ -133,6 +121,7 @@ func (r *Runner) getResources() error {
return err
}
log.Infof("successfully retrieved run")

repository := &configv1alpha1.TerraformRepository{}
log.Infof("getting repo %s/%s", layer.Spec.Repository.Namespace, layer.Spec.Repository.Name)
err = r.client.Get(context.TODO(), types.NamespacedName{
Expand All @@ -144,35 +133,44 @@ func (r *Runner) getResources() error {
}
log.Infof("successfully retrieved repo")
r.repository = repository

log.Infof("kubernetes resources successfully retrieved")
return nil
}

// Initialize the runner's clients, retrieve linked resources (layer, run, repository),
// fetch the repository content, install the binaries and configure Hermitcrab mirror.
func (r *Runner) init() error {
cl, err := newK8SClient()
kubeClient, err := utils.NewK8SClient()
if err != nil {
log.Errorf("error creating kubernetes client: %s", err)
return err
}
r.client = cl
r.client = kubeClient

datastoreClient := datastore.NewDefaultClient()
if r.config.Datastore.TLS {
log.Info("using TLS for datastore")
datastoreClient.Scheme = "https"
}
r.datastore = datastoreClient

log.Infof("retrieving linked TerraformLayer and TerraformRepository")
err = r.getResources()
if err != nil {
log.Errorf("error getting kubernetes resources: %s", err)
return err
}
log.Infof("kubernetes resources successfully retrieved")

r.gitRepository, err = FetchRepositoryContent(r.repository, r.layer.Spec.Branch, r.config.Runner.Repository)
if err != nil {
r.gitRepository = nil // reset git repository for the caller
log.Errorf("error fetching repository: %s", err)
return err
}
log.Infof("repository fetched successfully")

log.Infof("installing binaries...")
err = os.Chdir(fmt.Sprintf("%s/%s", WorkingDir, r.layer.Spec.Path)) // need to cd into the repo to detect tf versions
err = os.Chdir(r.workingDir) // need to cd into the repo to detect tf versions
if err != nil {
log.Errorf("error changing directory: %s", err)
return err
Expand All @@ -182,23 +180,14 @@ func (r *Runner) init() error {
log.Errorf("error installing binaries: %s", err)
return err
}
log.Infof("binaries successfully installed")

if r.config.Hermitcrab.Enabled {
log.Infof("Hermitcrab configuration detected, creating network mirror configuration...")
err := runnerutils.CreateNetworkMirrorConfig(WorkingDir, r.config.Hermitcrab.URL)
err := runnerutils.CreateNetworkMirrorConfig(RepositoryDir, r.config.Hermitcrab.URL)
if err != nil {
log.Errorf("error creating network mirror configuration: %s", err)
}
log.Infof("network mirror configuration created")
}

workingDir := fmt.Sprintf("%s/%s", WorkingDir, r.layer.Spec.Path)
log.Infof("Launching terraform init in %s", workingDir)
err = r.exec.Init(workingDir)
if err != nil {
log.Errorf("error executing terraform init: %s", err)
return err
}
return nil
}
1 change: 1 addition & 0 deletions internal/runner/tools/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,6 @@ func InstallBinaries(layer *configv1alpha1.TerraformLayer, repo *configv1alpha1.
}, nil
}

log.Infof("binaries successfully installed")
return tf, nil
}
24 changes: 24 additions & 0 deletions internal/utils/k8s_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package utils

import (
configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// Create a new Kubernetes client with standard resources and Burrito CRDs
func NewK8SClient() (client.Client, error) {
scheme := runtime.NewScheme()
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(configv1alpha1.AddToScheme(scheme))
cl, err := client.New(ctrl.GetConfigOrDie(), client.Options{
Scheme: scheme,
})
if err != nil {
return nil, err
}
return cl, err
}
3 changes: 3 additions & 0 deletions internal/utils/runner/network_mirror.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package runner
import (
"fmt"
"os"

log "github.com/sirupsen/logrus"
)

// Creates a network mirror configuration file for Terraform with the given endpoint
Expand All @@ -22,5 +24,6 @@ provider_installation {
if err != nil {
return err
}
log.Infof("network mirror configuration created")
return nil
}

0 comments on commit c2202a7

Please sign in to comment.