<commit_before>package knative

import (
	"fmt"
	"strings"
	"time"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	servinglib "knative.dev/client/pkg/serving"
	"knative.dev/client/pkg/wait"
	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
	v1 "knative.dev/serving/pkg/apis/serving/v1"

	"github.com/boson-project/faas"
	"github.com/boson-project/faas/k8s"
)

type Deployer struct {
	// Namespace with which to override that set on the default configuration (such as the ~/.kube/config).
	// If left blank, deployment will commence to the configured namespace.
	Namespace string
	// Verbose logging enablement flag.
	Verbose bool
}

func NewDeployer(namespaceOverride string) (deployer *Deployer, err error) {
	deployer = &Deployer{}
	namespace, err := GetNamespace(namespaceOverride)
	if err != nil {
		return
	}
	deployer.Namespace = namespace
	return
}

func (d *Deployer) Deploy(f faas.Function) (err error) {

	// k8s does not support service names with dots. so encode it such that
	// www.my-domain,com -> www-my--domain-com
	serviceName, err := k8s.ToK8sAllowedName(f.Name)
	if err != nil {
		return
	}

	client, err := NewServingClient(d.Namespace)
	if err != nil {
		return
	}

	_, err = client.GetService(serviceName)
	if err != nil {
		if errors.IsNotFound(err) {

			// Let's create a new Service
			if d.Verbose {
				fmt.Printf("Creating Knative Service: %v\n", serviceName)
			}
			err := client.CreateService(generateNewService(serviceName, f.Image))
			if err != nil {
				err = fmt.Errorf("knative deployer failed to deploy the service: %v", err)
				return err
			}

			if d.Verbose {
				fmt.Println("Waiting for Knative Service to become ready")
			}
			err, _ = client.WaitForService(serviceName, DefaultWaitingTimeout, wait.NoopMessageCallback())
			if err != nil {
				err = fmt.Errorf("knative deployer failed to wait for the service to become ready: %v", err)
				return err
			}

			route, err := client.GetRoute(serviceName)
			if err != nil {
				err = fmt.Errorf("knative deployer failed to get the route: %v", err)
				return err
			}

			fmt.Println("Function deployed at URL: " + route.Status.URL.String())

		} else {
			err = fmt.Errorf("knative deployer failed to get the service: %v", err)
			return err
		}
	} else {
		// Update the existing Service
		if d.Verbose {
			fmt.Printf("Updating existing Knative Service: %v\n", serviceName)
		}
		err = client.UpdateServiceWithRetry(serviceName, updateEnvVars(f.EnvVars), 3)
		if err != nil {
			err = fmt.Errorf("knative deployer failed to update the service: %v", err)
			return err
		}
	}

	return nil
}

func generateNewService(name, image string) *servingv1.Service {
	containers := []corev1.Container{
		{
			Image: image,
			Env: []corev1.EnvVar{
				{Name: "VERBOSE", Value: "true"},
			},
		},
	}

	return &v1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
			Labels: map[string]string{<commit_msg>feat: add health probes to node & go services (#174)<commit_after>package knative

import (
	"fmt"
	"strings"
	"time"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	servinglib "knative.dev/client/pkg/serving"
	"knative.dev/client/pkg/wait"
	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
	v1 "knative.dev/serving/pkg/apis/serving/v1"

	"github.com/boson-project/faas"
	"github.com/boson-project/faas/k8s"
)

type Deployer struct {
	// Namespace with which to override that set on the default configuration (such as the ~/.kube/config).
	// If left blank, deployment will commence to the configured namespace.
	Namespace string
	// Verbose logging enablement flag.
	Verbose bool
}

func NewDeployer(namespaceOverride string) (deployer *Deployer, err error) {
	deployer = &Deployer{}
	namespace, err := GetNamespace(namespaceOverride)
	if err != nil {
		return
	}
	deployer.Namespace = namespace
	return
}

func (d *Deployer) Deploy(f faas.Function) (err error) {

	// k8s does not support service names with dots. so encode it such that
	// www.my-domain,com -> www-my--domain-com
	serviceName, err := k8s.ToK8sAllowedName(f.Name)
	if err != nil {
		return
	}

	client, err := NewServingClient(d.Namespace)
	if err != nil {
		return
	}

	_, err = client.GetService(serviceName)
	if err != nil {
		if errors.IsNotFound(err) {

			// Let's create a new Service
			if d.Verbose {
				fmt.Printf("Creating Knative Service: %v\n", serviceName)
			}
			err := client.CreateService(generateNewService(serviceName, f.Image, f.Runtime != "quarkus"))
			if err != nil {
				err = fmt.Errorf("knative deployer failed to deploy the service: %v", err)
				return err
			}

			if d.Verbose {
				fmt.Println("Waiting for Knative Service to become ready")
			}
			err, _ = client.WaitForService(serviceName, DefaultWaitingTimeout, wait.NoopMessageCallback())
			if err != nil {
				err = fmt.Errorf("knative deployer failed to wait for the service to become ready: %v", err)
				return err
			}

			route, err := client.GetRoute(serviceName)
			if err != nil {
				err = fmt.Errorf("knative deployer failed to get the route: %v", err)
				return err
			}

			fmt.Println("Function deployed at URL: " + route.Status.URL.String())

		} else {
			err = fmt.Errorf("knative deployer failed to get the service: %v", err)
			return err
		}
	} else {
		// Update the existing Service
		if d.Verbose {
			fmt.Printf("Updating existing Knative Service: %v\n", serviceName)
		}
		err = client.UpdateServiceWithRetry(serviceName, updateEnvVars(f.EnvVars), 3)
		if err != nil {
			err = fmt.Errorf("knative deployer failed to update the service: %v", err)
			return err
		}
	}

	return nil
}

func probeFor(url string) *corev1.Probe {
	return &corev1.Probe{
		Handler: corev1.Handler{
			HTTPGet: &corev1.HTTPGetAction{
				Path: url,
			},
		},
	}
}

func generateNewService(name, image string, healthChecks bool) *servingv1.Service {
	containers := []corev1.Container{
		{
			Image: image,
			Env: []corev1.EnvVar{
				{Name: "VERBOSE", Value: "true"},
			},
		},
	}

	if healthChecks {
		containers[0].LivenessProbe = probeFor("/health/liveness")
		containers[0].ReadinessProbe = probeFor("/health/readiness")
	}

	return &v1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
			Labels: map[string]string{
{'fraction_non_alphanumeric': 0.12519734764761603, 'fraction_numerical': 0.008051784022734449, 'mean_word_length': 3.5740072202166067, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7444206', 'n_tokens_mistral': 2472, 'n_tokens_neox': 2223, 'n_words': 575}