swagger: "2.0"
info:
  title: NodeMaster API
  description: |
    API for managing a node, its services, and a cluster of remote nodes.
  version: 1.0.0
  contact:
    email: yves.cerezal@irt-saintexupery.com
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
basePath: /v1
paths:
  /node/:
    get:
      tags:
      - node
      description: |-
        get current node info including runtime config_file path
        <br>
      operationId: NodeController.GetNode
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.NodeInfo'
    put:
      tags:
      - node
      description: |-
        update current node hostname, description, or restic_password (the repository password used to encrypt/decrypt all restic backup targets on this node)
        <br>
      operationId: NodeController.UpdateNode
      parameters:
      - in: body
        name: body
        description: fields to update
        required: true
        schema:
          $ref: '#/definitions/models.NodeInfo'
      responses:
        "200":
          description: '{string} update success'
        "400":
          description: invalid body
  /node/backup:
    get:
      tags:
      - node
      description: |-
        get node backup configuration
        <br>
      operationId: NodeController.GetBackup
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.BackupConfig'
    put:
      tags:
      - node
      description: |-
        update node backup configuration
        <br>
      operationId: NodeController.UpdateBackup
      parameters:
      - in: body
        name: body
        description: backup config
        required: true
        schema:
          $ref: '#/definitions/models.BackupConfig'
      responses:
        "200":
          description: '{string} update success'
        "400":
          description: invalid body
  /node/backup/progress:
    get:
      tags:
      - node
      description: |-
        get the current/last run state for every node backup target
        <br>
      operationId: NodeController.GetBackupProgress
      responses:
        "200":
          description: ""
          schema:
            type: array
            items:
              $ref: '#/definitions/models.RunState'
  /node/backup/run:
    post:
      tags:
      - node
      description: |-
        trigger an immediate node backup across all targets (asynchronous)
        <br>
      operationId: NodeController.RunBackup
      responses:
        "202":
          description: '{string} backup started'
        "400":
          description: no targets configured
  /node/backup/targets:
    get:
      tags:
      - node
      description: |-
        list node backup target definitions
        <br>
      operationId: NodeController.GetBackupTargets
      responses:
        "200":
          description: ""
          schema:
            type: array
            items:
              $ref: '#/definitions/models.BackupTarget'
    post:
      tags:
      - node
      description: |-
        define a new node backup target
        <br>
      operationId: NodeController.AddBackupTarget
      parameters:
      - in: body
        name: body
        description: backup target definition
        required: true
        schema:
          $ref: '#/definitions/models.BackupTarget'
      responses:
        "201":
          description: ""
          schema:
            $ref: '#/definitions/models.BackupTarget'
        "400":
          description: invalid body
  /node/backup/targets/{tid}:
    get:
      tags:
      - node
      description: |-
        get a node backup target by id
        <br>
      operationId: NodeController.GetBackupTarget
      parameters:
      - in: path
        name: tid
        description: backup target id
        required: true
        type: string
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.BackupTarget'
        "404":
          description: not found
    put:
      tags:
      - node
      description: |-
        update a node backup target definition
        <br>
      operationId: NodeController.PutBackupTarget
      parameters:
      - in: path
        name: tid
        description: backup target id
        required: true
        type: string
      - in: body
        name: body
        description: updated backup target
        required: true
        schema:
          $ref: '#/definitions/models.BackupTarget'
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.BackupTarget'
        "400":
          description: invalid body
        "404":
          description: not found
    delete:
      tags:
      - node
      description: |-
        delete a node backup target definition
        <br>
      operationId: NodeController.DeleteBackupTarget
      parameters:
      - in: path
        name: tid
        description: backup target id
        required: true
        type: string
      responses:
        "200":
          description: '{string} delete success'
        "404":
          description: not found
  /node/backup/targets/{tid}/progress:
    get:
      tags:
      - node
      description: |-
        get the current/last run state for a node backup target
        <br>
      operationId: NodeController.GetBackupTargetProgress
      parameters:
      - in: path
        name: tid
        description: backup target id
        required: true
        type: string
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.RunState'
        "404":
          description: not found
  /node/backup/targets/{tid}/run:
    post:
      tags:
      - node
      description: |-
        trigger an immediate backup for a single node target (asynchronous)
        <br>
      operationId: NodeController.RunBackupTarget
      parameters:
      - in: path
        name: tid
        description: backup target id
        required: true
        type: string
      responses:
        "202":
          description: '{string} backup started'
        "404":
          description: not found
  /node/scan:
    post:
      tags:
      - node
      description: |-
        scan compose folders and index discovered services; accepts optional {"folder":"/path"} body
        <br>
      operationId: NodeController.Scan
      parameters:
      - in: body
        name: body
        description: optional folder override
        schema:
          $ref: '#/definitions/object'
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.ScanResult'
  /node/updates:
    get:
      tags:
      - node
      description: |-
        list update history
        <br>
      operationId: NodeController.GetUpdates
      responses:
        "200":
          description: ""
          schema:
            type: array
            items:
              $ref: '#/definitions/models.UpdateRecord'
    post:
      tags:
      - node
      description: |-
        record a new update entry
        <br>
      operationId: NodeController.AddUpdate
      parameters:
      - in: body
        name: body
        description: update record
        required: true
        schema:
          $ref: '#/definitions/models.UpdateRecord'
      responses:
        "201":
          description: ""
          schema:
            $ref: '#/definitions/models.UpdateRecord'
        "400":
          description: invalid body
  /node/updates/{id}:
    get:
      tags:
      - node
      description: |-
        get a single update record
        <br>
      operationId: NodeController.GetUpdate
      parameters:
      - in: path
        name: id
        description: update record id
        required: true
        type: string
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.UpdateRecord'
        "404":
          description: not found
    delete:
      tags:
      - node
      description: |-
        delete an update record
        <br>
      operationId: NodeController.DeleteUpdate
      parameters:
      - in: path
        name: id
        description: update record id
        required: true
        type: string
      responses:
        "200":
          description: '{string} delete success'
        "404":
          description: not found
  /nodes/:
    get:
      tags:
      - nodes
      description: |-
        list all registered remote nodes
        <br>
      operationId: NodesController.GetAllNodes
      responses:
        "200":
          description: ""
          schema:
            type: array
            items:
              $ref: '#/definitions/models.RemoteNode'
    post:
      tags:
      - nodes
      description: |-
        register a remote node
        <br>
      operationId: NodesController.AddNode
      parameters:
      - in: body
        name: body
        description: node to register
        required: true
        schema:
          $ref: '#/definitions/models.RemoteNode'
      responses:
        "201":
          description: ""
          schema:
            $ref: '#/definitions/models.RemoteNode'
        "400":
          description: invalid body
  /nodes/{id}:
    get:
      tags:
      - nodes
      description: |-
        get a remote node by id
        <br>
      operationId: NodesController.GetNode
      parameters:
      - in: path
        name: id
        description: node id
        required: true
        type: string
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.RemoteNode'
        "404":
          description: not found
    put:
      tags:
      - nodes
      description: |-
        update a remote node
        <br>
      operationId: NodesController.UpdateNode
      parameters:
      - in: path
        name: id
        description: node id
        required: true
        type: string
      - in: body
        name: body
        description: updated node data
        required: true
        schema:
          $ref: '#/definitions/models.RemoteNode'
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.RemoteNode'
        "400":
          description: invalid body
        "404":
          description: not found
    delete:
      tags:
      - nodes
      description: |-
        delete a remote node
        <br>
      operationId: NodesController.DeleteNode
      parameters:
      - in: path
        name: id
        description: node id
        required: true
        type: string
      responses:
        "200":
          description: '{string} delete success'
        "404":
          description: not found
  /nodes/aggregated:
    get:
      tags:
      - nodes
      description: |-
        query all registered nodes for their services and return an aggregated view
        <br>
      operationId: NodesController.GetAggregated
      responses:
        "200":
          description: ""
          schema:
            type: array
            items:
              $ref: '#/definitions/nodeServices'
  /services/:
    get:
      tags:
      - services
      description: |-
        list all services
        <br>
      operationId: ServicesController.GetAllServices
      responses:
        "200":
          description: ""
          schema:
            type: array
            items:
              $ref: '#/definitions/models.Service'
    post:
      tags:
      - services
      description: |-
        register a new service
        <br>
      operationId: ServicesController.AddService
      parameters:
      - in: body
        name: body
        description: service definition
        required: true
        schema:
          $ref: '#/definitions/models.Service'
      responses:
        "201":
          description: ""
          schema:
            $ref: '#/definitions/models.Service'
        "400":
          description: invalid body
  /services/{id}:
    get:
      tags:
      - services
      description: |-
        get a service by id
        <br>
      operationId: ServicesController.GetService
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.Service'
        "404":
          description: not found
    put:
      tags:
      - services
      description: |-
        update a service definition
        <br>
      operationId: ServicesController.UpdateService
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      - in: body
        name: body
        description: updated service data
        required: true
        schema:
          $ref: '#/definitions/models.Service'
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.Service'
        "400":
          description: invalid body
        "404":
          description: not found
    delete:
      tags:
      - services
      description: |-
        delete a service
        <br>
      operationId: ServicesController.DeleteService
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      responses:
        "200":
          description: '{string} delete success'
        "404":
          description: not found
  /services/{id}/backup:
    post:
      tags:
      - services
      description: |-
        trigger an immediate backup for a service across all targets (asynchronous)
        <br>
      operationId: ServicesController.BackupService
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      responses:
        "202":
          description: '{string} backup started'
        "400":
          description: no backup configured
        "404":
          description: not found
  /services/{id}/backup/progress:
    get:
      tags:
      - services
      description: |-
        get the current/last run state for every backup target of a service
        <br>
      operationId: ServicesController.GetServiceBackupProgress
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      responses:
        "200":
          description: ""
          schema:
            type: array
            items:
              $ref: '#/definitions/models.RunState'
        "404":
          description: not found
  /services/{id}/backup/targets:
    get:
      tags:
      - services
      description: |-
        list a service's backup target definitions
        <br>
      operationId: ServicesController.GetServiceBackupTargets
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      responses:
        "200":
          description: ""
          schema:
            type: array
            items:
              $ref: '#/definitions/models.BackupTarget'
        "404":
          description: not found
    post:
      tags:
      - services
      description: |-
        define a new backup target for a service
        <br>
      operationId: ServicesController.AddServiceBackupTarget
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      - in: body
        name: body
        description: backup target definition
        required: true
        schema:
          $ref: '#/definitions/models.BackupTarget'
      responses:
        "201":
          description: ""
          schema:
            $ref: '#/definitions/models.BackupTarget'
        "400":
          description: invalid body
        "404":
          description: not found
  /services/{id}/backup/targets/{tid}:
    get:
      tags:
      - services
      description: |-
        get a service backup target by id
        <br>
      operationId: ServicesController.GetServiceBackupTarget
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      - in: path
        name: tid
        description: backup target id
        required: true
        type: string
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.BackupTarget'
        "404":
          description: not found
    put:
      tags:
      - services
      description: |-
        update a service backup target definition
        <br>
      operationId: ServicesController.PutServiceBackupTarget
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      - in: path
        name: tid
        description: backup target id
        required: true
        type: string
      - in: body
        name: body
        description: updated backup target
        required: true
        schema:
          $ref: '#/definitions/models.BackupTarget'
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.BackupTarget'
        "400":
          description: invalid body
        "404":
          description: not found
    delete:
      tags:
      - services
      description: |-
        delete a service backup target definition
        <br>
      operationId: ServicesController.DeleteServiceBackupTarget
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      - in: path
        name: tid
        description: backup target id
        required: true
        type: string
      responses:
        "200":
          description: '{string} delete success'
        "404":
          description: not found
  /services/{id}/backup/targets/{tid}/progress:
    get:
      tags:
      - services
      description: |-
        get the current/last run state for a service backup target
        <br>
      operationId: ServicesController.GetServiceBackupTargetProgress
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      - in: path
        name: tid
        description: backup target id
        required: true
        type: string
      responses:
        "200":
          description: ""
          schema:
            $ref: '#/definitions/models.RunState'
        "404":
          description: not found
  /services/{id}/backup/targets/{tid}/run:
    post:
      tags:
      - services
      description: |-
        trigger an immediate backup for a single service target (asynchronous)
        <br>
      operationId: ServicesController.RunServiceBackupTarget
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      - in: path
        name: tid
        description: backup target id
        required: true
        type: string
      responses:
        "202":
          description: '{string} backup started'
        "404":
          description: not found
  /services/{id}/start:
    post:
      tags:
      - services
      description: |-
        start a service via its compose file
        <br>
      operationId: ServicesController.StartService
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      responses:
        "200":
          description: '{string} started'
        "404":
          description: not found
  /services/{id}/stop:
    post:
      tags:
      - services
      description: |-
        stop a service via its compose file
        <br>
      operationId: ServicesController.StopService
      parameters:
      - in: path
        name: id
        description: service id
        required: true
        type: string
      responses:
        "200":
          description: '{string} stopped'
        "404":
          description: not found
definitions:
  models.BackupConfig:
    title: BackupConfig
    type: object
    properties:
      history:
        type: array
        items:
          $ref: '#/definitions/models.BackupExecution'
      last_run:
        description: 'aggregate: latest LastRun across Targets'
        type: string
        format: datetime
      next_run:
        description: 'aggregate: earliest NextRun across Targets'
        type: string
        format: datetime
      source_path:
        type: string
      targets:
        type: array
        items:
          $ref: '#/definitions/models.BackupTarget'
  models.BackupExecution:
    title: BackupExecution
    type: object
    properties:
      duration_seconds:
        type: integer
        format: int64
      id:
        type: string
      message:
        type: string
      success:
        type: boolean
      target_id:
        type: string
      timestamp:
        type: string
        format: datetime
  models.BackupMethod:
    title: BackupMethod
    type: string
    enum:
    - MethodRsync = "rsync"
    - MethodRestic = "restic"
    - MethodExternal = "external"
    example: rsync
  models.BackupTarget:
    title: BackupTarget
    type: object
    properties:
      id:
        type: string
      last_run:
        type: string
        format: datetime
      method:
        $ref: '#/definitions/models.BackupMethod'
      name:
        type: string
      next_run:
        type: string
        format: datetime
      params:
        additionalProperties:
          type: string
      remote:
        description: 'destination: rsync target path (e.g. "user@host:/path") or restic
          repository string (e.g. "/mnt/backup/repo", "s3:s3.amazonaws.com/bucket/path",
          "sftp:user@host:/path")'
        type: string
      schedule:
        description: cron expression (5-field, standard). Empty = manual-only.
        type: string
  models.NodeInfo:
    title: NodeInfo
    type: object
    properties:
      backup:
        $ref: '#/definitions/models.BackupConfig'
      description:
        type: string
      hostname:
        type: string
      restic_password:
        description: repository password used to encrypt/decrypt all restic backup
          targets on this node
        type: string
      update_history:
        type: array
        items:
          $ref: '#/definitions/models.UpdateRecord'
  models.RemoteNode:
    title: RemoteNode
    type: object
    properties:
      description:
        type: string
      id:
        type: string
      last_seen:
        type: string
        format: datetime
      name:
        type: string
      status:
        type: string
      tags:
        type: array
        items:
          type: string
      url:
        type: string
  models.RunState:
    title: RunState
    type: object
    properties:
      eta:
        type: string
      message:
        type: string
      method:
        $ref: '#/definitions/models.BackupMethod'
      percent:
        type: number
        format: double
      running:
        type: boolean
      started_at:
        type: string
        format: datetime
      target_id:
        type: string
  models.ScanResult:
    title: ScanResult
    type: object
    properties:
      created:
        type: array
        items:
          $ref: '#/definitions/models.ServiceScanInfo'
      errors:
        type: array
        items:
          type: string
      found:
        type: integer
        format: int64
      scanned_paths:
        type: array
        items:
          type: string
      updated:
        type: array
        items:
          $ref: '#/definitions/models.ServiceScanInfo'
  models.Service:
    title: Service
    type: object
    properties:
      backup:
        $ref: '#/definitions/models.BackupConfig'
      backup_folder:
        type: string
      compose_file:
        type: string
      compose_type:
        type: string
      external_backup_start_minutes:
        type: integer
        format: int64
      external_backup_stop_minutes:
        type: integer
        format: int64
      id:
        type: string
      name:
        type: string
      status:
        description: '"up", "down", "unknown"'
        type: string
      stop_on_backup:
        type: boolean
  models.ServiceScanInfo:
    title: ServiceScanInfo
    type: object
    properties:
      backup_folder:
        type: string
      compose_file:
        type: string
      name:
        type: string
      status:
        type: string
  models.UpdateRecord:
    title: UpdateRecord
    type: object
    properties:
      id:
        type: string
      message:
        type: string
      packages:
        type: array
        items:
          type: string
      success:
        type: boolean
      timestamp:
        type: string
        format: datetime
  nodeServices:
    title: nodeServices
    type: object
  object:
    title: object
    type: object
tags:
- name: node
  description: |
    NodeController manages the current host node.
- name: nodes
  description: |
    NodesController manages the registry of remote nodes.
- name: services
  description: |
    ServicesController manages services on this host.
