Skip to content

Commit

Permalink
Add docs for commands (#90)
Browse files Browse the repository at this point in the history
  • Loading branch information
tamalsaha committed Jun 27, 2017
0 parents commit 1de064d
Show file tree
Hide file tree
Showing 4 changed files with 286 additions and 0 deletions.
28 changes: 28 additions & 0 deletions root.go
@@ -0,0 +1,28 @@
package cmds

import (
"flag"
"log"

v "github.com/appscode/go/version"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

func NewCmdStash(version string) *cobra.Command {
var rootCmd = &cobra.Command{
Use: "stash",
Short: `Stash by AppsCode - Backup your Kubernetes Volumes`,
PersistentPreRun: func(c *cobra.Command, args []string) {
c.Flags().VisitAll(func(flag *pflag.Flag) {
log.Printf("FLAG: --%s=%q", flag.Name, flag.Value)
})
},
}
rootCmd.PersistentFlags().AddGoFlagSet(flag.CommandLine)

rootCmd.AddCommand(v.NewCmdVersion())
rootCmd.AddCommand(NewCmdRun(version))
rootCmd.AddCommand(NewCmdSchedule(version))
return rootCmd
}
89 changes: 89 additions & 0 deletions run.go
@@ -0,0 +1,89 @@
package cmds

import (
"fmt"
"net/http"

stringz "github.com/appscode/go/strings"
"github.com/appscode/log"
"github.com/appscode/pat"
sapi "github.com/appscode/stash/api"
scs "github.com/appscode/stash/client/clientset"
"github.com/appscode/stash/pkg/analytics"
"github.com/appscode/stash/pkg/controller"
"github.com/appscode/stash/pkg/docker"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spf13/cobra"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)

var (
kubeClient clientset.Interface
stashClient scs.ExtensionInterface

scratchDir string = "/tmp"
)

func NewCmdRun(version string) *cobra.Command {
var (
masterURL string
kubeconfigPath string
tag string = stringz.Val(version, "canary")
address string = ":56790"
enableAnalytics bool = true
)

cmd := &cobra.Command{
Use: "run",
Short: "Run Stash operator",
PreRun: func(cmd *cobra.Command, args []string) {
if enableAnalytics {
analytics.Enable()
}
analytics.SendEvent("operator", "started", version)
},
PostRun: func(cmd *cobra.Command, args []string) {
analytics.SendEvent("operator", "stopped", version)
},
Run: func(cmd *cobra.Command, args []string) {
if err := docker.CheckDockerImageVersion(docker.ImageOperator, tag); err != nil {
log.Fatalf(`Image %v:%v not found.`, docker.ImageOperator, tag)
}

config, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfigPath)
if err != nil {
log.Fatalln(err)
}
kubeClient = clientset.NewForConfigOrDie(config)
stashClient = scs.NewForConfigOrDie(config)

ctrl := controller.New(kubeClient, stashClient, tag)
err = ctrl.Setup()
if err != nil {
log.Fatalln(err)
}

log.Infoln("Starting operator...")
ctrl.Run()

m := pat.New()
m.Get("/metrics", promhttp.Handler())

pattern := fmt.Sprintf("/%s/v1beta1/namespaces/%s/restics/%s/metrics", sapi.GroupName, PathParamNamespace, PathParamName)
log.Infof("URL pattern: %s", pattern)
m.Get(pattern, http.HandlerFunc(ExportSnapshots))

http.Handle("/", m)
log.Infoln("Listening on", address)
log.Fatal(http.ListenAndServe(address, nil))
},
}
cmd.Flags().StringVar(&masterURL, "master", masterURL, "The address of the Kubernetes API server (overrides any value in kubeconfig)")
cmd.Flags().StringVar(&kubeconfigPath, "kubeconfig", kubeconfigPath, "Path to kubeconfig file with authorization information (the master location is set by the master flag).")
cmd.Flags().StringVar(&address, "address", address, "Address to listen on for web interface and telemetry.")
cmd.Flags().StringVar(&scratchDir, "scratch-dir", scratchDir, "Directory used to store temporary files. Use an `emptyDir` in Kubernetes.")
cmd.Flags().BoolVar(&enableAnalytics, "analytics", enableAnalytics, "Send analytical event to Google Analytics")

return cmd
}
86 changes: 86 additions & 0 deletions schedule.go
@@ -0,0 +1,86 @@
package cmds

import (
"io/ioutil"
"os"
"strings"

"github.com/appscode/log"
rcs "github.com/appscode/stash/client/clientset"
"github.com/appscode/stash/pkg/analytics"
"github.com/appscode/stash/pkg/scheduler"
"github.com/spf13/cobra"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)

func NewCmdSchedule(version string) *cobra.Command {
var (
masterURL string
kubeconfigPath string
opt scheduler.Options = scheduler.Options{
ResourceNamespace: "",
ResourceName: "",
PrefixHostname: true,
ScratchDir: "/tmp",
PushgatewayURL: "http://stash-operator.kube-system.svc:56789",
PodLabelsPath: "/etc/labels",
}
enableAnalytics bool = true
)

cmd := &cobra.Command{
Use: "schedule",
Short: "Run Stash cron daemon",
PreRun: func(cmd *cobra.Command, args []string) {
if enableAnalytics {
analytics.Enable()
}
analytics.SendEvent("scheduler", "started", version)
},
PostRun: func(cmd *cobra.Command, args []string) {
analytics.SendEvent("scheduler", "stopped", version)
},
Run: func(cmd *cobra.Command, args []string) {
config, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfigPath)
if err != nil {
log.Fatalf("Could not get Kubernetes config: %s", err)
}
kubeClient = clientset.NewForConfigOrDie(config)
stashClient = rcs.NewForConfigOrDie(config)

opt.ScratchDir = strings.TrimSuffix(opt.ScratchDir, "/")
err = os.MkdirAll(opt.ScratchDir, 0755)
if err != nil {
log.Fatalf("Failed to create scratch dir: %s", err)
}
err = ioutil.WriteFile(opt.ScratchDir+"/.stash", []byte("test"), 644)
if err != nil {
log.Fatalf("No write access in scratch dir: %s", err)
}

ctrl, err := scheduler.New(kubeClient, stashClient, opt)
if err != nil {
log.Fatalf("Failed to create scheduler: %s", err)
}
err = ctrl.Setup()
if err != nil {
log.Fatalf("Failed to setup scheduler: %s", err)
}
ctrl.RunAndHold()
},
}
cmd.Flags().StringVar(&masterURL, "master", masterURL, "The address of the Kubernetes API server (overrides any value in kubeconfig)")
cmd.Flags().StringVar(&kubeconfigPath, "kubeconfig", kubeconfigPath, "Path to kubeconfig file with authorization information (the master location is set by the master flag).")
cmd.Flags().StringVar(&opt.App, "app", opt.App, "Name of app where sidecar pod is added")
cmd.Flags().StringVar(&opt.ResourceNamespace, "namespace", opt.ResourceNamespace, "The address of the Kubernetes API server (overrides any value in kubeconfig)")
cmd.Flags().StringVar(&opt.ResourceName, "name", opt.ResourceName, "Path to kubeconfig file with authorization information (the master location is set by the master flag).")
cmd.Flags().BoolVar(&opt.PrefixHostname, "prefix-hostname", opt.PrefixHostname, "If set, adds Hostname as prefix to repository. This should be true for StatefulSets & DaemonSets. This should be false in all other cases.")
cmd.Flags().StringVar(&opt.ScratchDir, "scratch-dir", opt.ScratchDir, "Directory used to store temporary files. Use an `emptyDir` in Kubernetes.")
cmd.Flags().StringVar(&opt.PushgatewayURL, "pushgateway-url", opt.PushgatewayURL, "URL of Prometheus pushgateway used to cache backup metrics")
cmd.Flags().StringVar(&opt.PodLabelsPath, "pod-labels-path", opt.PodLabelsPath, "Path to pod labels file mounted via Kubernetes Downward api")

// Analytics flags
cmd.Flags().BoolVar(&enableAnalytics, "analytics", enableAnalytics, "Send analytical event to Google Analytics")
return cmd
}
83 changes: 83 additions & 0 deletions snapshot_handler.go
@@ -0,0 +1,83 @@
package cmds

import (
"encoding/json"
"net/http"
_ "net/http/pprof"

"github.com/appscode/pat"
sapi "github.com/appscode/stash/api"
"github.com/appscode/stash/pkg/cli"
kerr "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
apiv1 "k8s.io/client-go/pkg/api/v1"
)

const (
PathParamNamespace = ":namespace"
PathParamName = ":name"
QueryParamHostname = "hostname"
)

func ExportSnapshots(w http.ResponseWriter, r *http.Request) {
params, found := pat.FromContext(r.Context())
if !found {
http.Error(w, "Missing parameters", http.StatusBadRequest)
return
}
namespace := params.Get(PathParamNamespace)
if namespace == "" {
http.Error(w, "Missing parameter:"+PathParamNamespace, http.StatusBadRequest)
return
}
name := params.Get(PathParamName)
if name == "" {
http.Error(w, "Missing parameter:"+PathParamName, http.StatusBadRequest)
return
}
hostname := r.URL.Query().Get(QueryParamHostname)
resticCLI := cli.New(scratchDir, hostname)

var resource *sapi.Restic
resource, err := stashClient.Restics(namespace).Get(name)
if kerr.IsNotFound(err) {
http.Error(w, err.Error(), http.StatusNotFound)
return
} else if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

if resource.Spec.Backend.RepositorySecretName == "" {
http.Error(w, "Missing repository secret name", http.StatusBadRequest)
return
}
var secret *apiv1.Secret
secret, err = kubeClient.CoreV1().Secrets(resource.Namespace).Get(resource.Spec.Backend.RepositorySecretName, metav1.GetOptions{})
if kerr.IsNotFound(err) {
http.Error(w, err.Error(), http.StatusNotFound)
return
} else if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
err = resticCLI.SetupEnv(resource, secret)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

snapshots, err := resticCLI.ListSnapshots()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
js, err := json.Marshal(snapshots)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "application/json")
w.Write(js)
}

0 comments on commit 1de064d

Please sign in to comment.