Skip to content

Commit

Permalink
Merge pull request #1748 from samerbahri98/backup_restore
Browse files Browse the repository at this point in the history
Backup and Restore Projects
  • Loading branch information
fiftin authored Feb 10, 2024
2 parents dd38199 + d173577 commit 540669a
Show file tree
Hide file tree
Showing 23 changed files with 1,216 additions and 12 deletions.
9 changes: 7 additions & 2 deletions .dredd/hooks/main.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package main

import (
"github.com/snikch/goodman/hooks"
trans "github.com/snikch/goodman/transaction"
"strconv"
"strings"

"github.com/snikch/goodman/hooks"
trans "github.com/snikch/goodman/transaction"
)

const (
Expand Down Expand Up @@ -115,6 +116,10 @@ func main() {
h.Before("project > /api/project/{project_id}/views/{view_id} > Updates view > 204 > application/json", capabilityWrapper("view"))
h.Before("project > /api/project/{project_id}/views/{view_id} > Removes view > 204 > application/json", capabilityWrapper("view"))

h.Before("project > /api/project/{project_id}/backup > Get backup > 200 > application/json", func(t *trans.Transaction) {
addCapabilities([]string{"repository", "inventory", "environment", "view", "template"})
})

//Add these last as they normalize the requests and path values after hook processing
h.BeforeAll(func(transactions []*trans.Transaction) {
for _, t := range transactions {
Expand Down
170 changes: 170 additions & 0 deletions api-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,146 @@ definitions:
username:
type: string

ProjectBackup:
type: object
example: {"meta":{"name":"homelab","alert":true,"alert_chat":"Test","max_parallel_tasks":0},"templates":[{"inventory":"Build","repository":"Demo","environment":"Empty","name":"Build","playbook":"build.yml","arguments":"[]","allow_override_args_in_task":false,"description":"Build Job","vault_key":null,"type":"build","start_version":"1.0.0","build_template":null,"view":"Build","autorun":false,"survey_vars":"null","suppress_success_alerts":false,"cron":"* * * * *"}],"repositories":[{"name":"Demo","git_url":"https://github.com/semaphoreui/demo-project.git","git_branch":"main","ssh_key":"None"}],"keys":[{"name":"None","type":"none"},{"name":"Vault Password","type":"login_password"}],"views":[{"name":"Build","position":0}],"inventories":[{"name":"Build","inventory":"","ssh_key":"None","become_key":"None","type":"static"},{"name":"Dev","inventory":"","ssh_key":"None","become_key":"None","type":"file"},{"name":"Prod","inventory":"","ssh_key":"None","become_key":"None","type":"file"}],"environments":[{"name":"Empty","password":null,"json":"{}","env":null}]}
properties:
meta:
type: object
properties:
name:
type: string
alert:
type: boolean
alert_chat:
type:
- string
- 'null'
max_parallel_tasks:
type: integer
minimum: 0
templates:
type: array
items:
type: object
properties:
inventory:
type: string
repository:
type: string
environment:
type: string
view:
type: string
name:
type: string
playbook:
type: string
arguments:
type:
- string
- 'null'
description:
type: string
allow_override_args_in_task:
type: boolean
suppress_success_alerts:
type: boolean
cron:
type:
- string
- 'null'
build_template:
type:
- string
- 'null'
autorun:
type: boolean
survey_vars:
type:
- string
- 'null'
start_version:
type:
- string
- 'null'
type:
type: string
vault_key:
type:
- string
- 'null'
repositories:
type: array
items:
type: object
properties:
name:
type: string
git_url:
type: string
git_branch:
type: string
ssh_key:
type: string
keys:
type: array
items:
type: object
properties:
name:
type: string
type:
type: string
enum: [ssh, login_password, none]
views:
type: array
items:
type: object
properties:
name:
type: string
position:
type: integer
minimum: 0
inventories:
type: array
items:
type: object
properties:
name:
type: string
inventory:
type: string
ssh_key:
type:
- string
- 'null'
become_key:
type:
- string
- 'null'
type:
type: string
enum: [static, static-yaml, file]
environments:
type: array
items:
type: object
properties:
name:
type: string
password:
type:
- string
- 'null'
json:
type: string
env:
type:
- string
- 'null'

APIToken:
type: object
properties:
Expand Down Expand Up @@ -953,6 +1093,24 @@ paths:
responses:
201:
description: Created project
/projects/restore:
post:
tags:
- projects
summary: Restore Project
consumes:
- application/json
parameters:
- name: Backup
in: body
required: true
schema:
$ref: '#/definitions/ProjectBackup'
responses:
200:
description: Created project
schema:
$ref: "#/definitions/Project"

/events:
get:
Expand Down Expand Up @@ -1011,6 +1169,18 @@ paths:
204:
description: Project deleted

/project/{project_id}/backup:
parameters:
- $ref: "#/parameters/project_id"
get:
tags:
- project
summary: Backup A Project
responses:
200:
description: Backup
schema:
$ref: '#/definitions/ProjectBackup'

/project/{project_id}/role:
parameters:
Expand Down
48 changes: 48 additions & 0 deletions api/projects/backupRestore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package projects

import (
"net/http"

log "github.com/Sirupsen/logrus"
"github.com/ansible-semaphore/semaphore/api/helpers"
"github.com/ansible-semaphore/semaphore/db"
projectService "github.com/ansible-semaphore/semaphore/services/project"
"github.com/gorilla/context"
)

func GetBackup(w http.ResponseWriter, r *http.Request) {
project := context.Get(r, "project").(db.Project)

store := helpers.Store(r)

backup, err := projectService.GetBackup(project.ID, store)

if err != nil {
helpers.WriteError(w, err)
return
}
helpers.WriteJSON(w, http.StatusOK, backup)
}

func Restore(w http.ResponseWriter, r *http.Request) {
var backup projectService.BackupFormat
var p *db.Project
var err error

if !helpers.Bind(w, r, &backup) {
helpers.WriteJSON(w, http.StatusBadRequest, backup)
return
}
store := helpers.Store(r)
if err = backup.Verify(); err != nil {
log.Error(err)
helpers.WriteError(w, (err))
return
}
if p, err = backup.Restore(store); err != nil {
log.Error(err)
helpers.WriteError(w, (err))
return
}
helpers.WriteJSON(w, http.StatusOK, p)
}
5 changes: 4 additions & 1 deletion api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package api

import (
"fmt"
"github.com/ansible-semaphore/semaphore/api/runners"
"net/http"
"os"
"strings"

"github.com/ansible-semaphore/semaphore/api/helpers"
"github.com/ansible-semaphore/semaphore/api/projects"
"github.com/ansible-semaphore/semaphore/api/runners"
"github.com/ansible-semaphore/semaphore/api/sockets"
"github.com/ansible-semaphore/semaphore/db"
"github.com/ansible-semaphore/semaphore/util"
Expand Down Expand Up @@ -106,6 +106,7 @@ func Route() *mux.Router {

authenticatedAPI.Path("/projects").HandlerFunc(projects.GetProjects).Methods("GET", "HEAD")
authenticatedAPI.Path("/projects").HandlerFunc(projects.AddProject).Methods("POST")
authenticatedAPI.Path("/projects/restore").HandlerFunc(projects.Restore).Methods("POST")
authenticatedAPI.Path("/events").HandlerFunc(getAllEvents).Methods("GET", "HEAD")
authenticatedAPI.HandleFunc("/events/last", getLastEvents).Methods("GET", "HEAD")

Expand Down Expand Up @@ -180,6 +181,8 @@ func Route() *mux.Router {
projectUserAPI.Path("/views").HandlerFunc(projects.AddView).Methods("POST")
projectUserAPI.Path("/views/positions").HandlerFunc(projects.SetViewPositions).Methods("POST")

projectUserAPI.Path("/backup").HandlerFunc(projects.GetBackup).Methods("GET", "HEAD")

//
// Updating and deleting project
projectAdminAPI := authenticatedAPI.Path("/project/{project_id}").Subrouter()
Expand Down
54 changes: 54 additions & 0 deletions db/BackupEntity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package db

type BackupEntity interface {
GetID() int
GetName() string
}

func (e View) GetID() int {
return e.ID
}

func (e View) GetName() string {
return e.Title
}

func (e Template) GetID() int {
return e.ID
}

func (e Template) GetName() string {
return e.Name
}

func (e Inventory) GetID() int {
return e.ID
}

func (e Inventory) GetName() string {
return e.Name
}

func (e AccessKey) GetID() int {
return e.ID
}

func (e AccessKey) GetName() string {
return e.Name
}

func (e Repository) GetID() int {
return e.ID
}

func (e Repository) GetName() string {
return e.Name
}

func (e Environment) GetID() int {
return e.ID
}

func (e Environment) GetName() string {
return e.Name
}
4 changes: 4 additions & 0 deletions db/sql/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package sql

import (
"database/sql"

"github.com/ansible-semaphore/semaphore/db"
"github.com/masterminds/squirrel"
)
Expand Down Expand Up @@ -114,8 +115,11 @@ func (d *SqlDb) GetTemplates(projectID int, filter db.TemplateFilter, params db.
"pt.arguments",
"pt.allow_override_args_in_task",
"pt.vault_key_id",
"pt.build_template_id",
"pt.start_version",
"pt.view_id",
"pt.`app`",
"pt.survey_vars",
"pt.start_version",
"pt.`type`").
From("project__template pt")
Expand Down
Loading

0 comments on commit 540669a

Please sign in to comment.