func/cmd/func-util/main.go

191 lines
4.1 KiB
Go

//go:build exclude_graphdriver_btrfs || !cgo
// +build exclude_graphdriver_btrfs !cgo
package main
import (
"context"
"flag"
"fmt"
"os"
"os/signal"
"path/filepath"
"slices"
"syscall"
"golang.org/x/sys/unix"
"github.com/openshift/source-to-image/pkg/cmd/cli"
"k8s.io/klog/v2"
"knative.dev/func/pkg/builders/s2i"
fn "knative.dev/func/pkg/functions"
"knative.dev/func/pkg/k8s"
"knative.dev/func/pkg/knative"
"knative.dev/func/pkg/scaffolding"
"knative.dev/func/pkg/tar"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigs
cancel()
<-sigs // second sigint/sigterm is treated as sigkill
os.Exit(137)
}()
var cmd func(context.Context) error = unknown
switch filepath.Base(os.Args[0]) {
case "deploy":
cmd = deploy
case "scaffold":
cmd = scaffold
case "s2i":
cmd = s2iCmd
case "socat":
cmd = socat
case "sh":
cmd = sh
}
err := cmd(ctx)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
os.Exit(1)
}
}
func unknown(_ context.Context) error {
return fmt.Errorf("unknown command: %q", os.Args[0])
}
func socat(ctx context.Context) error {
cmd := newSocatCmd()
cmd.SetContext(ctx)
return cmd.Execute()
}
func scaffold(ctx context.Context) error {
if len(os.Args) != 2 {
return fmt.Errorf("expected exactly one positional argument (function project path)")
}
path := os.Args[1]
f, err := fn.NewFunction(path)
if err != nil {
return fmt.Errorf("cannot load func project: %w", err)
}
if f.Runtime != "go" {
// Scaffolding is for now supported/needed only for Go.
return nil
}
embeddedRepo, err := fn.NewRepository("", "")
if err != nil {
return fmt.Errorf("cannot initialize repository: %w", err)
}
appRoot := filepath.Join(f.Root, ".s2i", "builds", "last")
_ = os.RemoveAll(appRoot)
err = scaffolding.Write(appRoot, f.Root, f.Runtime, f.Invoke, embeddedRepo.FS())
if err != nil {
return fmt.Errorf("cannot write the scaffolding: %w", err)
}
if err := os.MkdirAll(filepath.Join(f.Root, ".s2i", "bin"), 0755); err != nil {
return fmt.Errorf("unable to create .s2i bin dir. %w", err)
}
if err := os.WriteFile(filepath.Join(f.Root, ".s2i", "bin", "assemble"), []byte(s2i.GoAssembler), 0755); err != nil {
return fmt.Errorf("unable to write go assembler. %w", err)
}
return nil
}
func s2iCmd(ctx context.Context) error {
klog.InitFlags(flag.CommandLine)
cmd := cli.CommandFor()
cmd.SetContext(ctx)
return cmd.Execute()
}
func deploy(ctx context.Context) error {
var err error
deployer := knative.NewDeployer(
knative.WithDeployerVerbose(true),
knative.WithDeployerDecorator(deployDecorator{}))
var root string
if len(os.Args) > 1 {
root = os.Args[1]
} else {
root, err = os.Getwd()
if err != nil {
return fmt.Errorf("cannot determine working directory: %w", err)
}
}
f, err := fn.NewFunction(root)
if err != nil {
return fmt.Errorf("cannot load function: %w", err)
}
if len(os.Args) > 2 {
f.Deploy.Image = os.Args[2]
}
if f.Deploy.Image == "" {
f.Deploy.Image = f.Image
}
res, err := deployer.Deploy(ctx, f)
if err != nil {
return fmt.Errorf("cannont deploy the function: %w", err)
}
fmt.Printf("function has been deployed\n%+v\n", res)
return nil
}
type deployDecorator struct {
oshDec k8s.OpenshiftMetadataDecorator
}
func (d deployDecorator) UpdateAnnotations(function fn.Function, annotations map[string]string) map[string]string {
if k8s.IsOpenShift() {
return d.oshDec.UpdateAnnotations(function, annotations)
}
return annotations
}
func (d deployDecorator) UpdateLabels(function fn.Function, labels map[string]string) map[string]string {
if k8s.IsOpenShift() {
return d.oshDec.UpdateLabels(function, labels)
}
return labels
}
func sh(ctx context.Context) error {
if !slices.Equal(os.Args[1:], []string{"-c", "umask 0000 && exec tar -xmf -"}) {
return fmt.Errorf("this is a fake sh (only for backward compatiblility purposes)")
}
wd, err := os.Getwd()
if err != nil {
return fmt.Errorf("cannot get working directory: %w", err)
}
unix.Umask(0)
return tar.Extract(os.Stdin, wd)
}