Skip to content

Commit

Permalink
move snapshot scheduler to go api (#1014)
Browse files Browse the repository at this point in the history
* move snapshot scheduler to go api
  • Loading branch information
sgalsaleh committed Aug 26, 2020
1 parent 5f3c07e commit 0b6efeb
Show file tree
Hide file tree
Showing 11 changed files with 287 additions and 165 deletions.
5 changes: 0 additions & 5 deletions kotsadm/api/src/server/server.ts
Expand Up @@ -32,8 +32,6 @@ import { KurlStore } from "../kurl/kurl_store";
import { ReplicatedError } from "./errors";
import { MetricStore } from "../monitoring/metric_store";
import { ParamsStore } from "../params/params_store";
import { ensureBucket } from "../util/s3";
import { SnapshotScheduler } from "../snapshots/schedule";

let mount = {
"/": "${rootDir}/../controllers/{*.*s,!(ship)/*.*s}"
Expand Down Expand Up @@ -128,9 +126,6 @@ export class Server extends ServerLoader {
await stores.userStore.createAdminConsolePassword(process.env["SHARED_PASSWORD_BCRYPT"]!);
}

const scheduler = new SnapshotScheduler(stores, pool);
scheduler.run();

const setContext = async (req: Request, res: Response, next: NextFunction) => {
let token = req.get("Authorization") || "";

Expand Down
121 changes: 0 additions & 121 deletions kotsadm/api/src/snapshots/schedule.ts

This file was deleted.

5 changes: 5 additions & 0 deletions kotsadm/pkg/apiserver/server.go
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/replicatedhq/kots/kotsadm/pkg/automation"
"github.com/replicatedhq/kots/kotsadm/pkg/handlers"
"github.com/replicatedhq/kots/kotsadm/pkg/informers"
"github.com/replicatedhq/kots/kotsadm/pkg/snapshotscheduler"
"github.com/replicatedhq/kots/kotsadm/pkg/socketservice"
"github.com/replicatedhq/kots/kotsadm/pkg/store"
"github.com/replicatedhq/kots/kotsadm/pkg/updatechecker"
Expand All @@ -41,6 +42,10 @@ func Start() {
log.Println("Failed to start update checker", err)
}

if err := snapshotscheduler.Start(); err != nil {
log.Println("Failed to start snapshot scheduler", err)
}

if err := automation.AutomateInstall(); err != nil {
log.Println("Failed to run automated installs", err)
}
Expand Down
2 changes: 1 addition & 1 deletion kotsadm/pkg/handlers/backup.go
Expand Up @@ -52,7 +52,7 @@ func CreateBackup(w http.ResponseWriter, r *http.Request) {
return
}

err = snapshot.CreateBackup(foundApp)
_, err = snapshot.CreateBackup(foundApp, false)
if err != nil {
logger.Error(err)
createBackupResponse.Error = "failed to create backup"
Expand Down
79 changes: 54 additions & 25 deletions kotsadm/pkg/snapshot/backup.go
Expand Up @@ -26,32 +26,36 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/config"
)

func CreateBackup(a *apptypes.App) error {
if err := createApplicationBackup(context.TODO(), a); err != nil {
return errors.Wrap(err, "failed to create application backup")
func CreateBackup(a *apptypes.App, isScheduled bool) (*velerov1.Backup, error) {
backup, err := createApplicationBackup(context.TODO(), a, isScheduled)
if err != nil {
return nil, errors.Wrap(err, "failed to create application backup")
}

// uncomment to create disaster recovery snapshots
// if err := createAdminConsoleBackup(context.TODO()); err != nil {
// return errors.Wrap(err, "failed to create admin console backup")
// if err := createAdminConsoleBackup(context.TODO(), isScheduled); err != nil {
// return nil, errors.Wrap(err, "failed to create admin console backup")
// }

return nil
return backup, nil
}

func createApplicationBackup(ctx context.Context, a *apptypes.App) error {
func createApplicationBackup(ctx context.Context, a *apptypes.App, isScheduled bool) (*velerov1.Backup, error) {
downstreams, err := store.GetStore().ListDownstreamsForApp(a.ID)
if err != nil {
return errors.Wrap(err, "failed to list downstreams for app")
return nil, errors.Wrap(err, "failed to list downstreams for app")
}

if len(downstreams) == 0 {
return errors.New("no downstreams found for app")
return nil, errors.New("no downstreams found for app")
}

parentSequence, err := downstream.GetCurrentParentSequence(a.ID, downstreams[0].ClusterID)
if err != nil {
return errors.Wrap(err, "failed to get current downstream parent sequence")
return nil, errors.Wrap(err, "failed to get current downstream parent sequence")
}
if parentSequence == -1 {
return nil, errors.New("app does not have a deployed version")
}

logger.Debug("creating backup",
Expand All @@ -60,36 +64,36 @@ func createApplicationBackup(ctx context.Context, a *apptypes.App) error {

archiveDir, err := store.GetStore().GetAppVersionArchive(a.ID, parentSequence)
if err != nil {
return errors.Wrap(err, "failed to get app version archive")
return nil, errors.Wrap(err, "failed to get app version archive")
}

kotsadmVeleroBackendStorageLocation, err := FindBackupStoreLocation()
if err != nil {
return errors.Wrap(err, "failed to find backupstoragelocations")
return nil, errors.Wrap(err, "failed to find backupstoragelocations")
}

kotsKinds, err := kotsutil.LoadKotsKindsFromPath(archiveDir)
if err != nil {
return errors.Wrap(err, "failed to load kots kinds from path")
return nil, errors.Wrap(err, "failed to load kots kinds from path")
}

registrySettings, err := store.GetStore().GetRegistryDetailsForApp(a.ID)
if err != nil {
return errors.Wrap(err, "failed to get registry settings for app")
return nil, errors.Wrap(err, "failed to get registry settings for app")
}

backupSpec, err := kotsKinds.Marshal("velero.io", "v1", "Backup")
if err != nil {
return errors.Wrap(err, "failed to get backup spec from kotskinds")
return nil, errors.Wrap(err, "failed to get backup spec from kotskinds")
}

renderedBackup, err := render.RenderFile(kotsKinds, registrySettings, []byte(backupSpec))
if err != nil {
return errors.Wrap(err, "failed to render backup")
return nil, errors.Wrap(err, "failed to render backup")
}
veleroBackup, err := kotsutil.LoadBackupFromContents(renderedBackup)
if err != nil {
return errors.Wrap(err, "failed to load backup from contents")
return nil, errors.Wrap(err, "failed to load backup from contents")
}

appNamespace := os.Getenv("POD_NAMESPACE")
Expand All @@ -100,12 +104,17 @@ func createApplicationBackup(ctx context.Context, a *apptypes.App) error {
includedNamespaces := []string{appNamespace}
includedNamespaces = append(includedNamespaces, kotsKinds.KotsApplication.Spec.AdditionalNamespaces...)

snapshotTrigger := "manual"
if isScheduled {
snapshotTrigger = "schedule"
}

veleroBackup.Name = ""
veleroBackup.GenerateName = a.Slug + "-"

veleroBackup.Namespace = kotsadmVeleroBackendStorageLocation.Namespace
veleroBackup.Annotations = map[string]string{
"kots.io/snapshot-trigger": "manual",
"kots.io/snapshot-trigger": snapshotTrigger,
"kots.io/app-id": a.ID,
"kots.io/app-sequence": strconv.FormatInt(parentSequence, 10),
"kots.io/snapshot-requested": time.Now().UTC().Format(time.RFC3339),
Expand All @@ -125,37 +134,42 @@ func createApplicationBackup(ctx context.Context, a *apptypes.App) error {

cfg, err := config.GetConfig()
if err != nil {
return errors.Wrap(err, "failed to get cluster config")
return nil, errors.Wrap(err, "failed to get cluster config")
}

veleroClient, err := veleroclientv1.NewForConfig(cfg)
if err != nil {
return errors.Wrap(err, "failed to create clientset")
return nil, errors.Wrap(err, "failed to create clientset")
}

_, err = veleroClient.Backups(kotsadmVeleroBackendStorageLocation.Namespace).Create(ctx, veleroBackup, metav1.CreateOptions{})
backup, err := veleroClient.Backups(kotsadmVeleroBackendStorageLocation.Namespace).Create(ctx, veleroBackup, metav1.CreateOptions{})
if err != nil {
return errors.Wrap(err, "failed to create velero backup")
return nil, errors.Wrap(err, "failed to create velero backup")
}

return nil
return backup, nil
}

func createAdminConsoleBackup(ctx context.Context) error {
func createAdminConsoleBackup(ctx context.Context, isScheduled bool) error {
logger.Debug("creating admin console backup")

kotsadmVeleroBackendStorageLocation, err := FindBackupStoreLocation()
if err != nil {
return errors.Wrap(err, "failed to find backupstoragelocations")
}

snapshotTrigger := "manual"
if isScheduled {
snapshotTrigger = "schedule"
}

veleroBackup := &velerov1.Backup{
ObjectMeta: metav1.ObjectMeta{
Name: "",
GenerateName: "kotsadm-",
Namespace: kotsadmVeleroBackendStorageLocation.Namespace,
Annotations: map[string]string{
"kots.io/snapshot-trigger": "manual",
"kots.io/snapshot-trigger": snapshotTrigger,
"kots.io/snapshot-requested": time.Now().UTC().Format(time.RFC3339),
kotstypes.VeleroKey: kotstypes.VeleroLabelConsoleValue,
},
Expand Down Expand Up @@ -520,6 +534,21 @@ func DeleteBackup(snapshotName string) error {
return nil
}

func HasUnfinishedBackup(appID string) (bool, error) {
backups, err := ListBackupsForApp(appID)
if err != nil {
return false, errors.Wrap(err, "failed to list backups")
}

for _, backup := range backups {
if backup.Status == "New" || backup.Status == "InProgress" {
return true, nil
}
}

return false, nil
}

func GetKotsadmBackupDetail(ctx context.Context, backupName string) (*types.BackupDetail, error) {
cfg, err := config.GetConfig()
if err != nil {
Expand Down
8 changes: 8 additions & 0 deletions kotsadm/pkg/snapshot/types/types.go
Expand Up @@ -152,3 +152,11 @@ type ParsedTTL struct {
Quantity int64 `json:"quantity"`
Unit string `json:"unit"`
}

type ScheduledSnapshot struct {
ID string `json:"id"`
AppID string `json:"appId"`
ScheduledTimestamp time.Time `json:"scheduledTimestamp"`
// name of Backup CR will be set once scheduled
BackupName string `json:"backupName,omitempty"`
}

0 comments on commit 0b6efeb

Please sign in to comment.