mirror of https://github.com/portainer/portainer
commit
02362defde
|
@ -1,5 +1,42 @@
|
||||||
---
|
version: "2"
|
||||||
engines:
|
checks:
|
||||||
|
argument-count:
|
||||||
|
enabled: true
|
||||||
|
config:
|
||||||
|
threshold: 4
|
||||||
|
complex-logic:
|
||||||
|
enabled: true
|
||||||
|
config:
|
||||||
|
threshold: 4
|
||||||
|
file-lines:
|
||||||
|
enabled: true
|
||||||
|
config:
|
||||||
|
threshold: 300
|
||||||
|
method-complexity:
|
||||||
|
enabled: false
|
||||||
|
method-count:
|
||||||
|
enabled: true
|
||||||
|
config:
|
||||||
|
threshold: 20
|
||||||
|
method-lines:
|
||||||
|
enabled: true
|
||||||
|
config:
|
||||||
|
threshold: 50
|
||||||
|
nested-control-flow:
|
||||||
|
enabled: true
|
||||||
|
config:
|
||||||
|
threshold: 4
|
||||||
|
return-statements:
|
||||||
|
enabled: false
|
||||||
|
similar-code:
|
||||||
|
enabled: true
|
||||||
|
config:
|
||||||
|
threshold: #language-specific defaults. overrides affect all languages.
|
||||||
|
identical-code:
|
||||||
|
enabled: true
|
||||||
|
config:
|
||||||
|
threshold: #language-specific defaults. overrides affect all languages.
|
||||||
|
plugins:
|
||||||
gofmt:
|
gofmt:
|
||||||
enabled: true
|
enabled: true
|
||||||
golint:
|
golint:
|
||||||
|
@ -20,10 +57,5 @@ engines:
|
||||||
config: .eslintrc.yml
|
config: .eslintrc.yml
|
||||||
fixme:
|
fixme:
|
||||||
enabled: true
|
enabled: true
|
||||||
ratings:
|
exclude_patterns:
|
||||||
paths:
|
|
||||||
- "**.css"
|
|
||||||
- "**.js"
|
|
||||||
- "**.go"
|
|
||||||
exclude_paths:
|
|
||||||
- test/
|
- test/
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
version: '1.0'
|
|
||||||
steps:
|
|
||||||
|
|
||||||
build_backend:
|
|
||||||
image: portainer/golang-builder:ci
|
|
||||||
working_directory: ${{main_clone}}
|
|
||||||
commands:
|
|
||||||
- mkdir -p /go/src/github.com/${{CF_REPO_OWNER}}
|
|
||||||
- ln -s /codefresh/volume/${{CF_REPO_NAME}}/api /go/src/github.com/${{CF_REPO_OWNER}}/${{CF_REPO_NAME}}
|
|
||||||
- /build.sh api/cmd/portainer
|
|
||||||
|
|
||||||
build_frontend:
|
|
||||||
image: portainer/angular-builder:latest
|
|
||||||
working_directory: ${{build_backend}}
|
|
||||||
commands:
|
|
||||||
- yarn
|
|
||||||
- yarn grunt build-webapp
|
|
||||||
- mv api/cmd/portainer/portainer dist/
|
|
||||||
|
|
||||||
get_docker_version:
|
|
||||||
image: alpine:3.7
|
|
||||||
working_directory: ${{build_frontend}}
|
|
||||||
commands:
|
|
||||||
- cf_export DOCKER_VERSION=`cat gruntfile.js | grep -m 1 'shippedDockerVersion' | cut -d\' -f2`
|
|
||||||
|
|
||||||
download_docker_binary:
|
|
||||||
image: busybox
|
|
||||||
working_directory: ${{build_frontend}}
|
|
||||||
commands:
|
|
||||||
- echo ${{DOCKER_VERSION}}
|
|
||||||
- wget -O /tmp/docker-binaries.tgz https://download.docker.com/linux/static/stable/x86_64/docker-${{DOCKER_VERSION}}.tgz
|
|
||||||
- tar -xf /tmp/docker-binaries.tgz -C /tmp
|
|
||||||
- mv /tmp/docker/docker dist/
|
|
||||||
|
|
||||||
build_image:
|
|
||||||
type: build
|
|
||||||
working_directory: ${{download_docker_binary}}
|
|
||||||
dockerfile: ./build/linux/Dockerfile
|
|
||||||
image_name: portainer/portainer
|
|
||||||
tag: ${{CF_BRANCH}}
|
|
||||||
|
|
||||||
push_image:
|
|
||||||
type: push
|
|
||||||
candidate: '${{build_image}}'
|
|
||||||
tag: '${{CF_BRANCH}}'
|
|
||||||
registry: dockerhub
|
|
|
@ -1,46 +0,0 @@
|
||||||
version: '1.0'
|
|
||||||
steps:
|
|
||||||
|
|
||||||
build_backend:
|
|
||||||
image: portainer/golang-builder:ci
|
|
||||||
working_directory: ${{main_clone}}
|
|
||||||
commands:
|
|
||||||
- mkdir -p /go/src/github.com/${{CF_REPO_OWNER}}
|
|
||||||
- ln -s /codefresh/volume/${{CF_REPO_NAME}}/api /go/src/github.com/${{CF_REPO_OWNER}}/${{CF_REPO_NAME}}
|
|
||||||
- /build.sh api/cmd/portainer
|
|
||||||
|
|
||||||
build_frontend:
|
|
||||||
image: portainer/angular-builder:latest
|
|
||||||
working_directory: ${{build_backend}}
|
|
||||||
commands:
|
|
||||||
- yarn
|
|
||||||
- yarn grunt build-webapp
|
|
||||||
- mv api/cmd/portainer/portainer dist/
|
|
||||||
|
|
||||||
get_docker_version:
|
|
||||||
image: alpine:3.7
|
|
||||||
working_directory: ${{build_frontend}}
|
|
||||||
commands:
|
|
||||||
- cf_export DOCKER_VERSION=`cat gruntfile.js | grep -m 1 'shippedDockerVersion' | cut -d\' -f2`
|
|
||||||
|
|
||||||
download_docker_binary:
|
|
||||||
image: busybox
|
|
||||||
working_directory: ${{build_frontend}}
|
|
||||||
commands:
|
|
||||||
- echo ${{DOCKER_VERSION}}
|
|
||||||
- wget -O /tmp/docker-binaries.tgz https://download.docker.com/linux/static/stable/x86_64/docker-${{DOCKER_VERSION}}.tgz
|
|
||||||
- tar -xf /tmp/docker-binaries.tgz -C /tmp
|
|
||||||
- mv /tmp/docker/docker dist/
|
|
||||||
|
|
||||||
build_image:
|
|
||||||
type: build
|
|
||||||
working_directory: ${{download_docker_binary}}
|
|
||||||
dockerfile: ./build/linux/Dockerfile
|
|
||||||
image_name: portainer/portainer
|
|
||||||
tag: ${{CF_BRANCH}}
|
|
||||||
|
|
||||||
push_image:
|
|
||||||
type: push
|
|
||||||
candidate: '${{build_image}}'
|
|
||||||
tag: 'pr${{CF_PULL_REQUEST_NUMBER}}'
|
|
||||||
registry: dockerhub
|
|
|
@ -141,7 +141,10 @@ rules:
|
||||||
no-undef-init: error
|
no-undef-init: error
|
||||||
no-undef: off
|
no-undef: off
|
||||||
no-undefined: off
|
no-undefined: off
|
||||||
no-unused-vars: off
|
no-unused-vars:
|
||||||
|
- warn
|
||||||
|
-
|
||||||
|
vars: local
|
||||||
no-use-before-define: off
|
no-use-before-define: off
|
||||||
|
|
||||||
# Node.js and CommonJS
|
# Node.js and CommonJS
|
||||||
|
|
|
@ -4,3 +4,4 @@ dist
|
||||||
portainer-checksum.txt
|
portainer-checksum.txt
|
||||||
api/cmd/portainer/portainer*
|
api/cmd/portainer/portainer*
|
||||||
.tmp
|
.tmp
|
||||||
|
.vscode
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
Some basic conventions for contributing to this project.
|
Some basic conventions for contributing to this project.
|
||||||
|
|
||||||
### General
|
## General
|
||||||
|
|
||||||
Please make sure that there aren't existing pull requests attempting to address the issue mentioned. Likewise, please check for issues related to update, as someone else may be working on the issue in a branch or fork.
|
Please make sure that there aren't existing pull requests attempting to address the issue mentioned. Likewise, please check for issues related to update, as someone else may be working on the issue in a branch or fork.
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ When creating a new branch, prefix it with the *type* of the change (see section
|
||||||
|
|
||||||
For example, if you work on a bugfix for the issue #361, you could name the branch `fix361-template-selection`.
|
For example, if you work on a bugfix for the issue #361, you could name the branch `fix361-template-selection`.
|
||||||
|
|
||||||
### Issues open to contribution
|
## Issues open to contribution
|
||||||
|
|
||||||
Want to contribute but don't know where to start?
|
Want to contribute but don't know where to start?
|
||||||
|
|
||||||
|
@ -24,14 +24,14 @@ Some of the open issues are labeled with prefix `exp/`, this is used to mark the
|
||||||
either AngularJS or Golang
|
either AngularJS or Golang
|
||||||
* **advanced**: a task that require a deep understanding of the project codebase
|
* **advanced**: a task that require a deep understanding of the project codebase
|
||||||
|
|
||||||
You can have a use Github filters to list these issues:
|
You can use Github filters to list these issues:
|
||||||
|
|
||||||
* beginner labeled issues: https://github.com/portainer/portainer/labels/exp%2Fbeginner
|
* beginner labeled issues: https://github.com/portainer/portainer/labels/exp%2Fbeginner
|
||||||
* intermediate labeled issues: https://github.com/portainer/portainer/labels/exp%2Fintermediate
|
* intermediate labeled issues: https://github.com/portainer/portainer/labels/exp%2Fintermediate
|
||||||
* advanced labeled issues: https://github.com/portainer/portainer/labels/exp%2Fadvanced
|
* advanced labeled issues: https://github.com/portainer/portainer/labels/exp%2Fadvanced
|
||||||
|
|
||||||
|
|
||||||
### Commit Message Format
|
## Commit Message Format
|
||||||
|
|
||||||
Each commit message should include a **type**, a **scope** and a **subject**:
|
Each commit message should include a **type**, a **scope** and a **subject**:
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ Lines should not exceed 100 characters. This allows the message to be easier to
|
||||||
#269 style(dashboard): update dashboard with new layout
|
#269 style(dashboard): update dashboard with new layout
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Type
|
### Type
|
||||||
|
|
||||||
Must be one of the following:
|
Must be one of the following:
|
||||||
|
|
||||||
|
@ -61,16 +61,30 @@ Must be one of the following:
|
||||||
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
|
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
|
||||||
generation
|
generation
|
||||||
|
|
||||||
#### Scope
|
### Scope
|
||||||
|
|
||||||
The scope could be anything specifying place of the commit change. For example `networks`,
|
The scope could be anything specifying place of the commit change. For example `networks`,
|
||||||
`containers`, `images` etc...
|
`containers`, `images` etc...
|
||||||
You can use the **area** label tag associated on the issue here (for `area/containers` use `containers` as a scope...)
|
You can use the **area** label tag associated on the issue here (for `area/containers` use `containers` as a scope...)
|
||||||
|
|
||||||
#### Subject
|
### Subject
|
||||||
|
|
||||||
The subject contains succinct description of the change:
|
The subject contains succinct description of the change:
|
||||||
|
|
||||||
* use the imperative, present tense: "change" not "changed" nor "changes"
|
* use the imperative, present tense: "change" not "changed" nor "changes"
|
||||||
* don't capitalize first letter
|
* don't capitalize first letter
|
||||||
* no dot (.) at the end
|
* no dot (.) at the end
|
||||||
|
|
||||||
|
## Contribution process
|
||||||
|
|
||||||
|
Our contribution process is described below. Some of the steps can be visualized inside Github via specific `contrib/` labels, such as `contrib/func-review-in-progress` or `contrib/tech-review-approved`.
|
||||||
|
|
||||||
|
### Bug report
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Feature request
|
||||||
|
|
||||||
|
The feature request process is similar to the bug report process but has an extra functional validation before the technical validation.
|
||||||
|
|
||||||
|

|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
[](https://hub.docker.com/r/portainer/portainer/)
|
[](https://hub.docker.com/r/portainer/portainer/)
|
||||||
[](http://microbadger.com/images/portainer/portainer "Image size")
|
[](http://microbadger.com/images/portainer/portainer "Image size")
|
||||||
[](http://portainer.readthedocs.io/en/stable/?badge=stable)
|
[](http://portainer.readthedocs.io/en/stable/?badge=stable)
|
||||||
[]( https://g.codefresh.io/repositories/portainer/portainer/builds?filter=trigger:build;branch:develop;service:5922a08a3a1aab000116fcc6~portainer-ci)
|
[](https://semaphoreci.com/portainer/portainer)
|
||||||
[](https://codeclimate.com/github/portainer/portainer)
|
[](https://codeclimate.com/github/portainer/portainer)
|
||||||
[](https://portainer.io/slack/)
|
[](https://portainer.io/slack/)
|
||||||
[](https://gitter.im/portainer/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
[](https://gitter.im/portainer/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/portainer/portainer/bolt/template"
|
"github.com/portainer/portainer/bolt/template"
|
||||||
"github.com/portainer/portainer/bolt/user"
|
"github.com/portainer/portainer/bolt/user"
|
||||||
"github.com/portainer/portainer/bolt/version"
|
"github.com/portainer/portainer/bolt/version"
|
||||||
|
"github.com/portainer/portainer/bolt/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -47,6 +48,7 @@ type Store struct {
|
||||||
TemplateService *template.Service
|
TemplateService *template.Service
|
||||||
UserService *user.Service
|
UserService *user.Service
|
||||||
VersionService *version.Service
|
VersionService *version.Service
|
||||||
|
WebhookService *webhook.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStore initializes a new Store and the associated services
|
// NewStore initializes a new Store and the associated services
|
||||||
|
@ -232,5 +234,11 @@ func (store *Store) initServices() error {
|
||||||
}
|
}
|
||||||
store.VersionService = versionService
|
store.VersionService = versionService
|
||||||
|
|
||||||
|
webhookService, err := webhook.NewService(store.db)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
store.WebhookService = webhookService
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package migrator
|
||||||
|
|
||||||
|
func (m *Migrator) updateResourceControlsToDBVersion14() error {
|
||||||
|
resourceControls, err := m.resourceControlService.ResourceControls()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, resourceControl := range resourceControls {
|
||||||
|
if resourceControl.AdministratorsOnly == true {
|
||||||
|
err = m.resourceControlService.DeleteResourceControl(resourceControl.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -178,5 +178,13 @@ func (m *Migrator) Migrate() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Portainer 1.19.2
|
||||||
|
if m.currentDBVersion < 14 {
|
||||||
|
err := m.updateResourceControlsToDBVersion14()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return m.versionService.StoreDBVersion(portainer.DBVersion)
|
return m.versionService.StoreDBVersion(portainer.DBVersion)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
package webhook
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/portainer/portainer"
|
||||||
|
"github.com/portainer/portainer/bolt/internal"
|
||||||
|
|
||||||
|
"github.com/boltdb/bolt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// BucketName represents the name of the bucket where this service stores data.
|
||||||
|
BucketName = "webhooks"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service represents a service for managing webhook data.
|
||||||
|
type Service struct {
|
||||||
|
db *bolt.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewService creates a new instance of a service.
|
||||||
|
func NewService(db *bolt.DB) (*Service, error) {
|
||||||
|
err := internal.CreateBucket(db, BucketName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Service{
|
||||||
|
db: db,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//Webhooks returns an array of all webhooks
|
||||||
|
func (service *Service) Webhooks() ([]portainer.Webhook, error) {
|
||||||
|
var webhooks = make([]portainer.Webhook, 0)
|
||||||
|
|
||||||
|
err := service.db.View(func(tx *bolt.Tx) error {
|
||||||
|
bucket := tx.Bucket([]byte(BucketName))
|
||||||
|
|
||||||
|
cursor := bucket.Cursor()
|
||||||
|
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||||
|
var webhook portainer.Webhook
|
||||||
|
err := internal.UnmarshalObject(v, &webhook)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
webhooks = append(webhooks, webhook)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return webhooks, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Webhook returns a webhook by ID.
|
||||||
|
func (service *Service) Webhook(ID portainer.WebhookID) (*portainer.Webhook, error) {
|
||||||
|
var webhook portainer.Webhook
|
||||||
|
identifier := internal.Itob(int(ID))
|
||||||
|
|
||||||
|
err := internal.GetObject(service.db, BucketName, identifier, &webhook)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &webhook, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebhookByResourceID returns a webhook by the ResourceID it is associated with.
|
||||||
|
func (service *Service) WebhookByResourceID(ID string) (*portainer.Webhook, error) {
|
||||||
|
var webhook *portainer.Webhook
|
||||||
|
|
||||||
|
err := service.db.View(func(tx *bolt.Tx) error {
|
||||||
|
bucket := tx.Bucket([]byte(BucketName))
|
||||||
|
cursor := bucket.Cursor()
|
||||||
|
|
||||||
|
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||||
|
var w portainer.Webhook
|
||||||
|
err := internal.UnmarshalObject(v, &w)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.ResourceID == ID {
|
||||||
|
webhook = &w
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if webhook == nil {
|
||||||
|
return portainer.ErrObjectNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return webhook, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebhookByToken returns a webhook by the random token it is associated with.
|
||||||
|
func (service *Service) WebhookByToken(token string) (*portainer.Webhook, error) {
|
||||||
|
var webhook *portainer.Webhook
|
||||||
|
|
||||||
|
err := service.db.View(func(tx *bolt.Tx) error {
|
||||||
|
bucket := tx.Bucket([]byte(BucketName))
|
||||||
|
cursor := bucket.Cursor()
|
||||||
|
|
||||||
|
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
|
||||||
|
var w portainer.Webhook
|
||||||
|
err := internal.UnmarshalObject(v, &w)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.Token == token {
|
||||||
|
webhook = &w
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if webhook == nil {
|
||||||
|
return portainer.ErrObjectNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return webhook, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteWebhook deletes a webhook.
|
||||||
|
func (service *Service) DeleteWebhook(ID portainer.WebhookID) error {
|
||||||
|
identifier := internal.Itob(int(ID))
|
||||||
|
return internal.DeleteObject(service.db, BucketName, identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateWebhook assign an ID to a new webhook and saves it.
|
||||||
|
func (service *Service) CreateWebhook(webhook *portainer.Webhook) error {
|
||||||
|
return service.db.Update(func(tx *bolt.Tx) error {
|
||||||
|
bucket := tx.Bucket([]byte(BucketName))
|
||||||
|
|
||||||
|
id, _ := bucket.NextSequence()
|
||||||
|
webhook.ID = portainer.WebhookID(id)
|
||||||
|
|
||||||
|
data, err := internal.MarshalObject(webhook)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bucket.Put(internal.Itob(int(webhook.ID)), data)
|
||||||
|
})
|
||||||
|
}
|
|
@ -178,6 +178,10 @@ func initSettings(settingsService portainer.SettingsService, flags *portainer.CL
|
||||||
SnapshotInterval: *flags.SnapshotInterval,
|
SnapshotInterval: *flags.SnapshotInterval,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *flags.Templates != "" {
|
||||||
|
settings.TemplatesURL = *flags.Templates
|
||||||
|
}
|
||||||
|
|
||||||
if *flags.Labels != nil {
|
if *flags.Labels != nil {
|
||||||
settings.BlackListedLabels = *flags.Labels
|
settings.BlackListedLabels = *flags.Labels
|
||||||
} else {
|
} else {
|
||||||
|
@ -193,6 +197,10 @@ func initSettings(settingsService portainer.SettingsService, flags *portainer.CL
|
||||||
}
|
}
|
||||||
|
|
||||||
func initTemplates(templateService portainer.TemplateService, fileService portainer.FileService, templateURL, templateFile string) error {
|
func initTemplates(templateService portainer.TemplateService, fileService portainer.FileService, templateURL, templateFile string) error {
|
||||||
|
if templateURL != "" {
|
||||||
|
log.Printf("Portainer started with the --templates flag. Using external templates, template management will be disabled.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
existingTemplates, err := templateService.Templates()
|
existingTemplates, err := templateService.Templates()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -204,32 +212,14 @@ func initTemplates(templateService portainer.TemplateService, fileService portai
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var templatesJSON []byte
|
|
||||||
if templateURL == "" {
|
|
||||||
return loadTemplatesFromFile(fileService, templateService, templateFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
templatesJSON, err = client.Get(templateURL)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Unable to retrieve templates via HTTP")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return unmarshalAndPersistTemplates(templateService, templatesJSON)
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadTemplatesFromFile(fileService portainer.FileService, templateService portainer.TemplateService, templateFile string) error {
|
|
||||||
templatesJSON, err := fileService.GetFileContent(templateFile)
|
templatesJSON, err := fileService.GetFileContent(templateFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Unable to retrieve template via filesystem")
|
log.Println("Unable to retrieve template definitions via filesystem")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return unmarshalAndPersistTemplates(templateService, templatesJSON)
|
|
||||||
}
|
|
||||||
|
|
||||||
func unmarshalAndPersistTemplates(templateService portainer.TemplateService, templateData []byte) error {
|
|
||||||
var templates []portainer.Template
|
var templates []portainer.Template
|
||||||
err := json.Unmarshal(templateData, &templates)
|
err = json.Unmarshal(templatesJSON, &templates)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Unable to parse templates file. Please review your template definition file.")
|
log.Println("Unable to parse templates file. Please review your template definition file.")
|
||||||
return err
|
return err
|
||||||
|
@ -241,6 +231,7 @@ func unmarshalAndPersistTemplates(templateService portainer.TemplateService, tem
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,6 +505,7 @@ func main() {
|
||||||
StackService: store.StackService,
|
StackService: store.StackService,
|
||||||
TagService: store.TagService,
|
TagService: store.TagService,
|
||||||
TemplateService: store.TemplateService,
|
TemplateService: store.TemplateService,
|
||||||
|
WebhookService: store.WebhookService,
|
||||||
SwarmStackManager: swarmStackManager,
|
SwarmStackManager: swarmStackManager,
|
||||||
ComposeStackManager: composeStackManager,
|
ComposeStackManager: composeStackManager,
|
||||||
CryptoService: cryptoService,
|
CryptoService: cryptoService,
|
||||||
|
@ -527,6 +519,7 @@ func main() {
|
||||||
SSL: *flags.SSL,
|
SSL: *flags.SSL,
|
||||||
SSLCert: *flags.SSLCert,
|
SSLCert: *flags.SSLCert,
|
||||||
SSLKey: *flags.SSLKey,
|
SSLKey: *flags.SSLKey,
|
||||||
|
DockerClientFactory: clientFactory,
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Starting Portainer %s on %s", portainer.APIVersion, *flags.Addr)
|
log.Printf("Starting Portainer %s on %s", portainer.APIVersion, *flags.Addr)
|
||||||
|
|
|
@ -3,7 +3,6 @@ package crypto
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/md5"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
@ -97,9 +96,7 @@ func (service *ECDSAService) GenerateKeyPair() ([]byte, []byte, error) {
|
||||||
// that hash.
|
// that hash.
|
||||||
// It then encodes the generated signature in base64.
|
// It then encodes the generated signature in base64.
|
||||||
func (service *ECDSAService) Sign(message string) (string, error) {
|
func (service *ECDSAService) Sign(message string) (string, error) {
|
||||||
digest := md5.New()
|
hash := HashFromBytes([]byte(message))
|
||||||
digest.Write([]byte(message))
|
|
||||||
hash := digest.Sum(nil)
|
|
||||||
|
|
||||||
r := big.NewInt(0)
|
r := big.NewInt(0)
|
||||||
s := big.NewInt(0)
|
s := big.NewInt(0)
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import "crypto/md5"
|
||||||
|
|
||||||
|
// HashFromBytes returns the hash of the specified data
|
||||||
|
func HashFromBytes(data []byte) []byte {
|
||||||
|
digest := md5.New()
|
||||||
|
digest.Write(data)
|
||||||
|
return digest.Sum(nil)
|
||||||
|
}
|
|
@ -30,6 +30,11 @@ func snapshot(cli *client.Client) (*portainer.Snapshot, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = snapshotNodes(snapshot, cli)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snapshotContainers(snapshot, cli)
|
err = snapshotContainers(snapshot, cli)
|
||||||
|
@ -64,6 +69,22 @@ func snapshotInfo(snapshot *portainer.Snapshot, cli *client.Client) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func snapshotNodes(snapshot *portainer.Snapshot, cli *client.Client) error {
|
||||||
|
nodes, err := cli.NodeList(context.Background(), types.NodeListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var nanoCpus int64
|
||||||
|
var totalMem int64
|
||||||
|
for _, node := range nodes {
|
||||||
|
nanoCpus += node.Description.Resources.NanoCPUs
|
||||||
|
totalMem += node.Description.Resources.MemoryBytes
|
||||||
|
}
|
||||||
|
snapshot.TotalCPU = int(nanoCpus / 1e9)
|
||||||
|
snapshot.TotalMemory = totalMem
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func snapshotSwarmServices(snapshot *portainer.Snapshot, cli *client.Client) error {
|
func snapshotSwarmServices(snapshot *portainer.Snapshot, cli *client.Client) error {
|
||||||
stacks := make(map[string]struct{})
|
stacks := make(map[string]struct{})
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ func (snapshotter *Snapshotter) CreateSnapshot(endpoint *portainer.Endpoint) (*p
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
defer cli.Close()
|
||||||
|
|
||||||
return snapshot(cli)
|
return snapshot(cli)
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,3 +93,9 @@ type Error string
|
||||||
|
|
||||||
// Error returns the error message.
|
// Error returns the error message.
|
||||||
func (e Error) Error() string { return string(e) }
|
func (e Error) Error() string { return string(e) }
|
||||||
|
|
||||||
|
// Webhook errors
|
||||||
|
const (
|
||||||
|
ErrWebhookAlreadyExists = Error("A webhook for this resource already exists")
|
||||||
|
ErrUnsupportedWebhookType = Error("Webhooks for this resource are not currently supported")
|
||||||
|
)
|
||||||
|
|
|
@ -13,6 +13,10 @@ import (
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
errInvalidResponseStatus = portainer.Error("Invalid response status (expecting 200)")
|
||||||
|
)
|
||||||
|
|
||||||
// HTTPClient represents a client to send HTTP requests.
|
// HTTPClient represents a client to send HTTP requests.
|
||||||
type HTTPClient struct {
|
type HTTPClient struct {
|
||||||
*http.Client
|
*http.Client
|
||||||
|
@ -75,6 +79,10 @@ func Get(url string) ([]byte, error) {
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
if response.StatusCode != http.StatusOK {
|
||||||
|
return nil, errInvalidResponseStatus
|
||||||
|
}
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(response.Body)
|
body, err := ioutil.ReadAll(response.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
package error
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// LoggerHandler defines a HTTP handler that includes a HandlerError return pointer
|
|
||||||
LoggerHandler func(http.ResponseWriter, *http.Request) *HandlerError
|
|
||||||
// HandlerError represents an error raised inside a HTTP handler
|
|
||||||
HandlerError struct {
|
|
||||||
StatusCode int
|
|
||||||
Message string
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
errorResponse struct {
|
|
||||||
Err string `json:"err,omitempty"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (handler LoggerHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
|
||||||
err := handler(rw, r)
|
|
||||||
if err != nil {
|
|
||||||
writeErrorResponse(rw, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeErrorResponse(rw http.ResponseWriter, err *HandlerError) {
|
|
||||||
log.Printf("http error: %s (err=%s) (code=%d)\n", err.Message, err.Err, err.StatusCode)
|
|
||||||
rw.Header().Set("Content-Type", "application/json")
|
|
||||||
rw.WriteHeader(err.StatusCode)
|
|
||||||
json.NewEncoder(rw).Encode(&errorResponse{Err: err.Message})
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteError is a convenience function that creates a new HandlerError before calling writeErrorResponse.
|
|
||||||
// For use outside of the standard http handlers.
|
|
||||||
func WriteError(rw http.ResponseWriter, code int, message string, err error) {
|
|
||||||
writeErrorResponse(rw, &HandlerError{code, message, err})
|
|
||||||
}
|
|
|
@ -6,10 +6,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type authenticatePayload struct {
|
type authenticatePayload struct {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ package dockerhub
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer/http/response"
|
"github.com/portainer/libhttp/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET request on /api/dockerhub
|
// GET request on /api/dockerhub
|
||||||
|
|
|
@ -4,10 +4,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type dockerhubUpdatePayload struct {
|
type dockerhubUpdatePayload struct {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type endpointGroupCreatePayload struct {
|
type endpointGroupCreatePayload struct {
|
||||||
|
|
|
@ -3,10 +3,10 @@ package endpointgroups
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DELETE request on /api/endpoint_groups/:id
|
// DELETE request on /api/endpoint_groups/:id
|
||||||
|
|
|
@ -3,10 +3,10 @@ package endpointgroups
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET request on /api/endpoint_groups/:id
|
// GET request on /api/endpoint_groups/:id
|
||||||
|
|
|
@ -3,8 +3,8 @@ package endpointgroups
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer/http/response"
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,10 @@ package endpointgroups
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type endpointGroupUpdatePayload struct {
|
type endpointGroupUpdatePayload struct {
|
||||||
|
|
|
@ -3,10 +3,10 @@ package endpointgroups
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type endpointGroupUpdateAccessPayload struct {
|
type endpointGroupUpdateAccessPayload struct {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ package endpointproxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/proxy"
|
"github.com/portainer/portainer/http/proxy"
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,9 +3,9 @@ package endpointproxy
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,9 +3,9 @@ package endpointproxy
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,9 +3,9 @@ package endpointproxy
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,12 +6,12 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
"github.com/portainer/portainer/crypto"
|
"github.com/portainer/portainer/crypto"
|
||||||
"github.com/portainer/portainer/http/client"
|
"github.com/portainer/portainer/http/client"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type endpointCreatePayload struct {
|
type endpointCreatePayload struct {
|
||||||
|
@ -35,7 +35,7 @@ type endpointCreatePayload struct {
|
||||||
func (payload *endpointCreatePayload) Validate(r *http.Request) error {
|
func (payload *endpointCreatePayload) Validate(r *http.Request) error {
|
||||||
name, err := request.RetrieveMultiPartFormValue(r, "Name", false)
|
name, err := request.RetrieveMultiPartFormValue(r, "Name", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return portainer.Error("Invalid stack name")
|
return portainer.Error("Invalid endpoint name")
|
||||||
}
|
}
|
||||||
payload.Name = name
|
payload.Name = name
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ func (payload *endpointCreatePayload) Validate(r *http.Request) error {
|
||||||
payload.TLSSkipClientVerify = skipTLSClientVerification
|
payload.TLSSkipClientVerify = skipTLSClientVerification
|
||||||
|
|
||||||
if !payload.TLSSkipVerify {
|
if !payload.TLSSkipVerify {
|
||||||
caCert, err := request.RetrieveMultiPartFormFile(r, "TLSCACertFile")
|
caCert, _, err := request.RetrieveMultiPartFormFile(r, "TLSCACertFile")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return portainer.Error("Invalid CA certificate file. Ensure that the file is uploaded correctly")
|
return portainer.Error("Invalid CA certificate file. Ensure that the file is uploaded correctly")
|
||||||
}
|
}
|
||||||
|
@ -79,13 +79,13 @@ func (payload *endpointCreatePayload) Validate(r *http.Request) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !payload.TLSSkipClientVerify {
|
if !payload.TLSSkipClientVerify {
|
||||||
cert, err := request.RetrieveMultiPartFormFile(r, "TLSCertFile")
|
cert, _, err := request.RetrieveMultiPartFormFile(r, "TLSCertFile")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return portainer.Error("Invalid certificate file. Ensure that the file is uploaded correctly")
|
return portainer.Error("Invalid certificate file. Ensure that the file is uploaded correctly")
|
||||||
}
|
}
|
||||||
payload.TLSCertFile = cert
|
payload.TLSCertFile = cert
|
||||||
|
|
||||||
key, err := request.RetrieveMultiPartFormFile(r, "TLSKeyFile")
|
key, _, err := request.RetrieveMultiPartFormFile(r, "TLSKeyFile")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return portainer.Error("Invalid key file. Ensure that the file is uploaded correctly")
|
return portainer.Error("Invalid key file. Ensure that the file is uploaded correctly")
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ func (handler *Handler) createAzureEndpoint(payload *endpointCreatePayload) (*po
|
||||||
endpoint := &portainer.Endpoint{
|
endpoint := &portainer.Endpoint{
|
||||||
ID: portainer.EndpointID(endpointID),
|
ID: portainer.EndpointID(endpointID),
|
||||||
Name: payload.Name,
|
Name: payload.Name,
|
||||||
URL: payload.URL,
|
URL: "https://management.azure.com",
|
||||||
Type: portainer.AzureEnvironment,
|
Type: portainer.AzureEnvironment,
|
||||||
GroupID: portainer.EndpointGroupID(payload.GroupID),
|
GroupID: portainer.EndpointGroupID(payload.GroupID),
|
||||||
PublicURL: payload.PublicURL,
|
PublicURL: payload.PublicURL,
|
||||||
|
|
|
@ -4,10 +4,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DELETE request on /api/endpoints/:id
|
// DELETE request on /api/endpoints/:id
|
||||||
|
|
|
@ -4,10 +4,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type endpointExtensionAddPayload struct {
|
type endpointExtensionAddPayload struct {
|
||||||
|
|
|
@ -3,10 +3,10 @@ package endpoints
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DELETE request on /api/endpoints/:id/extensions/:extensionType
|
// DELETE request on /api/endpoints/:id/extensions/:extensionType
|
||||||
|
|
|
@ -3,10 +3,10 @@ package endpoints
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET request on /api/endpoints/:id
|
// GET request on /api/endpoints/:id
|
||||||
|
|
|
@ -3,8 +3,8 @@ package endpoints
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer/http/response"
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,8 +27,9 @@ func (handler *Handler) endpointList(w http.ResponseWriter, r *http.Request) *ht
|
||||||
|
|
||||||
filteredEndpoints := security.FilterEndpoints(endpoints, endpointGroups, securityContext)
|
filteredEndpoints := security.FilterEndpoints(endpoints, endpointGroups, securityContext)
|
||||||
|
|
||||||
for _, endpoint := range filteredEndpoints {
|
for idx := range filteredEndpoints {
|
||||||
hideFields(&endpoint)
|
hideFields(&filteredEndpoints[idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.JSON(w, filteredEndpoints)
|
return response.JSON(w, filteredEndpoints)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// POST request on /api/endpoints/snapshot
|
// POST request on /api/endpoints/snapshot
|
||||||
|
|
|
@ -4,11 +4,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
"github.com/portainer/portainer/http/client"
|
"github.com/portainer/portainer/http/client"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type endpointUpdatePayload struct {
|
type endpointUpdatePayload struct {
|
||||||
|
|
|
@ -3,10 +3,10 @@ package endpoints
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type endpointUpdateAccessPayload struct {
|
type endpointUpdateAccessPayload struct {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package endpoints
|
package endpoints
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/proxy"
|
"github.com/portainer/portainer/http/proxy"
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
|
|
||||||
|
|
|
@ -33,5 +33,9 @@ func (handler *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
} else {
|
} else {
|
||||||
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Add("X-Frame-Options", "DENY")
|
||||||
|
w.Header().Add("X-XSS-Protection", "1; mode=block")
|
||||||
|
w.Header().Add("X-Content-Type-Options", "nosniff")
|
||||||
handler.Handler.ServeHTTP(w, r)
|
handler.Handler.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/portainer/portainer/http/handler/endpointproxy"
|
"github.com/portainer/portainer/http/handler/endpointproxy"
|
||||||
"github.com/portainer/portainer/http/handler/endpoints"
|
"github.com/portainer/portainer/http/handler/endpoints"
|
||||||
"github.com/portainer/portainer/http/handler/file"
|
"github.com/portainer/portainer/http/handler/file"
|
||||||
|
"github.com/portainer/portainer/http/handler/motd"
|
||||||
"github.com/portainer/portainer/http/handler/registries"
|
"github.com/portainer/portainer/http/handler/registries"
|
||||||
"github.com/portainer/portainer/http/handler/resourcecontrols"
|
"github.com/portainer/portainer/http/handler/resourcecontrols"
|
||||||
"github.com/portainer/portainer/http/handler/settings"
|
"github.com/portainer/portainer/http/handler/settings"
|
||||||
|
@ -21,6 +22,7 @@ import (
|
||||||
"github.com/portainer/portainer/http/handler/templates"
|
"github.com/portainer/portainer/http/handler/templates"
|
||||||
"github.com/portainer/portainer/http/handler/upload"
|
"github.com/portainer/portainer/http/handler/upload"
|
||||||
"github.com/portainer/portainer/http/handler/users"
|
"github.com/portainer/portainer/http/handler/users"
|
||||||
|
"github.com/portainer/portainer/http/handler/webhooks"
|
||||||
"github.com/portainer/portainer/http/handler/websocket"
|
"github.com/portainer/portainer/http/handler/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -33,6 +35,7 @@ type Handler struct {
|
||||||
EndpointHandler *endpoints.Handler
|
EndpointHandler *endpoints.Handler
|
||||||
EndpointProxyHandler *endpointproxy.Handler
|
EndpointProxyHandler *endpointproxy.Handler
|
||||||
FileHandler *file.Handler
|
FileHandler *file.Handler
|
||||||
|
MOTDHandler *motd.Handler
|
||||||
RegistryHandler *registries.Handler
|
RegistryHandler *registries.Handler
|
||||||
ResourceControlHandler *resourcecontrols.Handler
|
ResourceControlHandler *resourcecontrols.Handler
|
||||||
SettingsHandler *settings.Handler
|
SettingsHandler *settings.Handler
|
||||||
|
@ -45,6 +48,7 @@ type Handler struct {
|
||||||
UploadHandler *upload.Handler
|
UploadHandler *upload.Handler
|
||||||
UserHandler *users.Handler
|
UserHandler *users.Handler
|
||||||
WebSocketHandler *websocket.Handler
|
WebSocketHandler *websocket.Handler
|
||||||
|
WebhookHandler *webhooks.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeHTTP delegates a request to the appropriate subhandler.
|
// ServeHTTP delegates a request to the appropriate subhandler.
|
||||||
|
@ -67,6 +71,8 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
default:
|
default:
|
||||||
http.StripPrefix("/api", h.EndpointHandler).ServeHTTP(w, r)
|
http.StripPrefix("/api", h.EndpointHandler).ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
case strings.HasPrefix(r.URL.Path, "/api/motd"):
|
||||||
|
http.StripPrefix("/api", h.MOTDHandler).ServeHTTP(w, r)
|
||||||
case strings.HasPrefix(r.URL.Path, "/api/registries"):
|
case strings.HasPrefix(r.URL.Path, "/api/registries"):
|
||||||
http.StripPrefix("/api", h.RegistryHandler).ServeHTTP(w, r)
|
http.StripPrefix("/api", h.RegistryHandler).ServeHTTP(w, r)
|
||||||
case strings.HasPrefix(r.URL.Path, "/api/resource_controls"):
|
case strings.HasPrefix(r.URL.Path, "/api/resource_controls"):
|
||||||
|
@ -91,6 +97,8 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
http.StripPrefix("/api", h.TeamMembershipHandler).ServeHTTP(w, r)
|
http.StripPrefix("/api", h.TeamMembershipHandler).ServeHTTP(w, r)
|
||||||
case strings.HasPrefix(r.URL.Path, "/api/websocket"):
|
case strings.HasPrefix(r.URL.Path, "/api/websocket"):
|
||||||
http.StripPrefix("/api", h.WebSocketHandler).ServeHTTP(w, r)
|
http.StripPrefix("/api", h.WebSocketHandler).ServeHTTP(w, r)
|
||||||
|
case strings.HasPrefix(r.URL.Path, "/api/webhooks"):
|
||||||
|
http.StripPrefix("/api", h.WebhookHandler).ServeHTTP(w, r)
|
||||||
case strings.HasPrefix(r.URL.Path, "/"):
|
case strings.HasPrefix(r.URL.Path, "/"):
|
||||||
h.FileHandler.ServeHTTP(w, r)
|
h.FileHandler.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package motd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/portainer/portainer/http/security"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handler is the HTTP handler used to handle MOTD operations.
|
||||||
|
type Handler struct {
|
||||||
|
*mux.Router
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHandler returns a new Handler
|
||||||
|
func NewHandler(bouncer *security.RequestBouncer) *Handler {
|
||||||
|
h := &Handler{
|
||||||
|
Router: mux.NewRouter(),
|
||||||
|
}
|
||||||
|
h.Handle("/motd",
|
||||||
|
bouncer.AuthenticatedAccess(http.HandlerFunc(h.motd))).Methods(http.MethodGet)
|
||||||
|
|
||||||
|
return h
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package motd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
|
"github.com/portainer/portainer"
|
||||||
|
"github.com/portainer/portainer/crypto"
|
||||||
|
"github.com/portainer/portainer/http/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
type motdResponse struct {
|
||||||
|
Message string `json:"Message"`
|
||||||
|
Hash []byte `json:"Hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (handler *Handler) motd(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
motd, err := client.Get(portainer.MessageOfTheDayURL)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hash := crypto.HashFromBytes(motd)
|
||||||
|
response.JSON(w, &motdResponse{Message: string(motd), Hash: hash})
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package registries
|
package registries
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
|
@ -4,10 +4,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type registryCreatePayload struct {
|
type registryCreatePayload struct {
|
||||||
|
|
|
@ -3,10 +3,10 @@ package registries
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DELETE request on /api/registries/:id
|
// DELETE request on /api/registries/:id
|
||||||
|
|
|
@ -3,10 +3,10 @@ package registries
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET request on /api/registries/:id
|
// GET request on /api/registries/:id
|
||||||
|
|
|
@ -3,8 +3,8 @@ package registries
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer/http/response"
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,8 +22,9 @@ func (handler *Handler) registryList(w http.ResponseWriter, r *http.Request) *ht
|
||||||
|
|
||||||
filteredRegistries := security.FilterRegistries(registries, securityContext)
|
filteredRegistries := security.FilterRegistries(registries, securityContext)
|
||||||
|
|
||||||
for _, registry := range filteredRegistries {
|
for idx := range filteredRegistries {
|
||||||
hideFields(®istry)
|
hideFields(&filteredRegistries[idx])
|
||||||
}
|
}
|
||||||
return response.JSON(w, registries)
|
|
||||||
|
return response.JSON(w, filteredRegistries)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type registryUpdatePayload struct {
|
type registryUpdatePayload struct {
|
||||||
|
|
|
@ -3,10 +3,10 @@ package registries
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type registryUpdateAccessPayload struct {
|
type registryUpdateAccessPayload struct {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,20 +4,20 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
type resourceControlCreatePayload struct {
|
type resourceControlCreatePayload struct {
|
||||||
ResourceID string
|
ResourceID string
|
||||||
Type string
|
Type string
|
||||||
AdministratorsOnly bool
|
Public bool
|
||||||
Users []int
|
Users []int
|
||||||
Teams []int
|
Teams []int
|
||||||
SubResourceIDs []string
|
SubResourceIDs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (payload *resourceControlCreatePayload) Validate(r *http.Request) error {
|
func (payload *resourceControlCreatePayload) Validate(r *http.Request) error {
|
||||||
|
@ -29,8 +29,8 @@ func (payload *resourceControlCreatePayload) Validate(r *http.Request) error {
|
||||||
return portainer.Error("Invalid type")
|
return portainer.Error("Invalid type")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(payload.Users) == 0 && len(payload.Teams) == 0 && !payload.AdministratorsOnly {
|
if len(payload.Users) == 0 && len(payload.Teams) == 0 && !payload.Public {
|
||||||
return portainer.Error("Invalid resource control declaration. Must specify Users, Teams or AdministratorOnly")
|
return portainer.Error("Invalid resource control declaration. Must specify Users, Teams or Public")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -90,12 +90,12 @@ func (handler *Handler) resourceControlCreate(w http.ResponseWriter, r *http.Req
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceControl := portainer.ResourceControl{
|
resourceControl := portainer.ResourceControl{
|
||||||
ResourceID: payload.ResourceID,
|
ResourceID: payload.ResourceID,
|
||||||
SubResourceIDs: payload.SubResourceIDs,
|
SubResourceIDs: payload.SubResourceIDs,
|
||||||
Type: resourceControlType,
|
Type: resourceControlType,
|
||||||
AdministratorsOnly: payload.AdministratorsOnly,
|
Public: payload.Public,
|
||||||
UserAccesses: userAccesses,
|
UserAccesses: userAccesses,
|
||||||
TeamAccesses: teamAccesses,
|
TeamAccesses: teamAccesses,
|
||||||
}
|
}
|
||||||
|
|
||||||
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
||||||
|
|
|
@ -3,10 +3,10 @@ package resourcecontrols
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,22 +3,22 @@ package resourcecontrols
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
type resourceControlUpdatePayload struct {
|
type resourceControlUpdatePayload struct {
|
||||||
AdministratorsOnly bool
|
Public bool
|
||||||
Users []int
|
Users []int
|
||||||
Teams []int
|
Teams []int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (payload *resourceControlUpdatePayload) Validate(r *http.Request) error {
|
func (payload *resourceControlUpdatePayload) Validate(r *http.Request) error {
|
||||||
if len(payload.Users) == 0 && len(payload.Teams) == 0 && !payload.AdministratorsOnly {
|
if len(payload.Users) == 0 && len(payload.Teams) == 0 && !payload.Public {
|
||||||
return portainer.Error("Invalid resource control declaration. Must specify Users, Teams or AdministratorOnly")
|
return portainer.Error("Invalid resource control declaration. Must specify Users, Teams or Public")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ func (handler *Handler) resourceControlUpdate(w http.ResponseWriter, r *http.Req
|
||||||
return &httperror.HandlerError{http.StatusForbidden, "Permission denied to update the resource control", portainer.ErrResourceAccessDenied}
|
return &httperror.HandlerError{http.StatusForbidden, "Permission denied to update the resource control", portainer.ErrResourceAccessDenied}
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceControl.AdministratorsOnly = payload.AdministratorsOnly
|
resourceControl.Public = payload.Public
|
||||||
|
|
||||||
var userAccesses = make([]portainer.UserResourceAccess, 0)
|
var userAccesses = make([]portainer.UserResourceAccess, 0)
|
||||||
for _, v := range payload.Users {
|
for _, v := range payload.Users {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ package settings
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer/http/response"
|
"github.com/portainer/libhttp/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET request on /api/settings
|
// GET request on /api/settings
|
||||||
|
|
|
@ -3,11 +3,11 @@ package settings
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
"github.com/portainer/portainer/filesystem"
|
"github.com/portainer/portainer/filesystem"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type settingsLDAPCheckPayload struct {
|
type settingsLDAPCheckPayload struct {
|
||||||
|
|
|
@ -3,9 +3,9 @@ package settings
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type publicSettingsResponse struct {
|
type publicSettingsResponse struct {
|
||||||
|
@ -13,6 +13,7 @@ type publicSettingsResponse struct {
|
||||||
AuthenticationMethod portainer.AuthenticationMethod `json:"AuthenticationMethod"`
|
AuthenticationMethod portainer.AuthenticationMethod `json:"AuthenticationMethod"`
|
||||||
AllowBindMountsForRegularUsers bool `json:"AllowBindMountsForRegularUsers"`
|
AllowBindMountsForRegularUsers bool `json:"AllowBindMountsForRegularUsers"`
|
||||||
AllowPrivilegedModeForRegularUsers bool `json:"AllowPrivilegedModeForRegularUsers"`
|
AllowPrivilegedModeForRegularUsers bool `json:"AllowPrivilegedModeForRegularUsers"`
|
||||||
|
ExternalTemplates bool `json:"ExternalTemplates"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET request on /api/settings/public
|
// GET request on /api/settings/public
|
||||||
|
@ -27,6 +28,11 @@ func (handler *Handler) settingsPublic(w http.ResponseWriter, r *http.Request) *
|
||||||
AuthenticationMethod: settings.AuthenticationMethod,
|
AuthenticationMethod: settings.AuthenticationMethod,
|
||||||
AllowBindMountsForRegularUsers: settings.AllowBindMountsForRegularUsers,
|
AllowBindMountsForRegularUsers: settings.AllowBindMountsForRegularUsers,
|
||||||
AllowPrivilegedModeForRegularUsers: settings.AllowPrivilegedModeForRegularUsers,
|
AllowPrivilegedModeForRegularUsers: settings.AllowPrivilegedModeForRegularUsers,
|
||||||
|
ExternalTemplates: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.TemplatesURL != "" {
|
||||||
|
publicSettings.ExternalTemplates = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.JSON(w, publicSettings)
|
return response.JSON(w, publicSettings)
|
||||||
|
|
|
@ -4,11 +4,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
"github.com/portainer/portainer/filesystem"
|
"github.com/portainer/portainer/filesystem"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type settingsUpdatePayload struct {
|
type settingsUpdatePayload struct {
|
||||||
|
@ -19,6 +19,7 @@ type settingsUpdatePayload struct {
|
||||||
AllowBindMountsForRegularUsers *bool
|
AllowBindMountsForRegularUsers *bool
|
||||||
AllowPrivilegedModeForRegularUsers *bool
|
AllowPrivilegedModeForRegularUsers *bool
|
||||||
SnapshotInterval *string
|
SnapshotInterval *string
|
||||||
|
TemplatesURL *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (payload *settingsUpdatePayload) Validate(r *http.Request) error {
|
func (payload *settingsUpdatePayload) Validate(r *http.Request) error {
|
||||||
|
@ -28,6 +29,9 @@ func (payload *settingsUpdatePayload) Validate(r *http.Request) error {
|
||||||
if payload.LogoURL != nil && *payload.LogoURL != "" && !govalidator.IsURL(*payload.LogoURL) {
|
if payload.LogoURL != nil && *payload.LogoURL != "" && !govalidator.IsURL(*payload.LogoURL) {
|
||||||
return portainer.Error("Invalid logo URL. Must correspond to a valid URL format")
|
return portainer.Error("Invalid logo URL. Must correspond to a valid URL format")
|
||||||
}
|
}
|
||||||
|
if payload.TemplatesURL != nil && *payload.TemplatesURL != "" && !govalidator.IsURL(*payload.TemplatesURL) {
|
||||||
|
return portainer.Error("Invalid external templates URL. Must correspond to a valid URL format")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +56,10 @@ func (handler *Handler) settingsUpdate(w http.ResponseWriter, r *http.Request) *
|
||||||
settings.LogoURL = *payload.LogoURL
|
settings.LogoURL = *payload.LogoURL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if payload.TemplatesURL != nil {
|
||||||
|
settings.TemplatesURL = *payload.TemplatesURL
|
||||||
|
}
|
||||||
|
|
||||||
if payload.BlackListedLabels != nil {
|
if payload.BlackListedLabels != nil {
|
||||||
settings.BlackListedLabels = payload.BlackListedLabels
|
settings.BlackListedLabels = payload.BlackListedLabels
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
"github.com/portainer/portainer/filesystem"
|
"github.com/portainer/portainer/filesystem"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ func (payload *composeStackFromFileUploadPayload) Validate(r *http.Request) erro
|
||||||
}
|
}
|
||||||
payload.Name = name
|
payload.Name = name
|
||||||
|
|
||||||
composeFileContent, err := request.RetrieveMultiPartFormFile(r, "file")
|
composeFileContent, _, err := request.RetrieveMultiPartFormFile(r, "file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return portainer.Error("Invalid Compose file. Ensure that the Compose file is uploaded correctly")
|
return portainer.Error("Invalid Compose file. Ensure that the Compose file is uploaded correctly")
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
"github.com/portainer/portainer/filesystem"
|
"github.com/portainer/portainer/filesystem"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ func (payload *swarmStackFromFileUploadPayload) Validate(r *http.Request) error
|
||||||
}
|
}
|
||||||
payload.SwarmID = swarmID
|
payload.SwarmID = swarmID
|
||||||
|
|
||||||
composeFileContent, err := request.RetrieveMultiPartFormFile(r, "file")
|
composeFileContent, _, err := request.RetrieveMultiPartFormFile(r, "file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return portainer.Error("Invalid Compose file. Ensure that the Compose file is uploaded correctly")
|
return portainer.Error("Invalid Compose file. Ensure that the Compose file is uploaded correctly")
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package stacks
|
package stacks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (handler *Handler) cleanUp(stack *portainer.Stack, doCleanUp *bool) error {
|
func (handler *Handler) cleanUp(stack *portainer.Stack, doCleanUp *bool) error {
|
||||||
|
@ -57,7 +58,7 @@ func (handler *Handler) stackCreate(w http.ResponseWriter, r *http.Request) *htt
|
||||||
return handler.createComposeStack(w, r, method, endpoint)
|
return handler.createComposeStack(w, r, method, endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &httperror.HandlerError{http.StatusBadRequest, "Invalid value for query parameter: type. Value must be one of: 1 (Swarm stack) or 2 (Compose stack)", request.ErrInvalidQueryParameter}
|
return &httperror.HandlerError{http.StatusBadRequest, "Invalid value for query parameter: type. Value must be one of: 1 (Swarm stack) or 2 (Compose stack)", errors.New(request.ErrInvalidQueryParameter)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler *Handler) createComposeStack(w http.ResponseWriter, r *http.Request, method string, endpoint *portainer.Endpoint) *httperror.HandlerError {
|
func (handler *Handler) createComposeStack(w http.ResponseWriter, r *http.Request, method string, endpoint *portainer.Endpoint) *httperror.HandlerError {
|
||||||
|
@ -71,7 +72,7 @@ func (handler *Handler) createComposeStack(w http.ResponseWriter, r *http.Reques
|
||||||
return handler.createComposeStackFromFileUpload(w, r, endpoint)
|
return handler.createComposeStackFromFileUpload(w, r, endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &httperror.HandlerError{http.StatusBadRequest, "Invalid value for query parameter: method. Value must be one of: string, repository or file", request.ErrInvalidQueryParameter}
|
return &httperror.HandlerError{http.StatusBadRequest, "Invalid value for query parameter: method. Value must be one of: string, repository or file", errors.New(request.ErrInvalidQueryParameter)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler *Handler) createSwarmStack(w http.ResponseWriter, r *http.Request, method string, endpoint *portainer.Endpoint) *httperror.HandlerError {
|
func (handler *Handler) createSwarmStack(w http.ResponseWriter, r *http.Request, method string, endpoint *portainer.Endpoint) *httperror.HandlerError {
|
||||||
|
@ -84,5 +85,5 @@ func (handler *Handler) createSwarmStack(w http.ResponseWriter, r *http.Request,
|
||||||
return handler.createSwarmStackFromFileUpload(w, r, endpoint)
|
return handler.createSwarmStackFromFileUpload(w, r, endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &httperror.HandlerError{http.StatusBadRequest, "Invalid value for query parameter: method. Value must be one of: string, repository or file", request.ErrInvalidQueryParameter}
|
return &httperror.HandlerError{http.StatusBadRequest, "Invalid value for query parameter: method. Value must be one of: string, repository or file", errors.New(request.ErrInvalidQueryParameter)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/proxy"
|
"github.com/portainer/portainer/http/proxy"
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,8 +48,8 @@ func (handler *Handler) stackDelete(w http.ResponseWriter, r *http.Request) *htt
|
||||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err}
|
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err}
|
||||||
}
|
}
|
||||||
|
|
||||||
if resourceControl != nil {
|
if !securityContext.IsAdmin {
|
||||||
if !securityContext.IsAdmin && !proxy.CanAccessStack(stack, resourceControl, securityContext.UserID, securityContext.UserMemberships) {
|
if !proxy.CanAccessStack(stack, resourceControl, securityContext.UserID, securityContext.UserMemberships) {
|
||||||
return &httperror.HandlerError{http.StatusForbidden, "Access denied to resource", portainer.ErrResourceAccessDenied}
|
return &httperror.HandlerError{http.StatusForbidden, "Access denied to resource", portainer.ErrResourceAccessDenied}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/proxy"
|
"github.com/portainer/portainer/http/proxy"
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -41,6 +41,10 @@ func (handler *Handler) stackFile(w http.ResponseWriter, r *http.Request) *httpe
|
||||||
}
|
}
|
||||||
|
|
||||||
extendedStack := proxy.ExtendedStack{*stack, portainer.ResourceControl{}}
|
extendedStack := proxy.ExtendedStack{*stack, portainer.ResourceControl{}}
|
||||||
|
if !securityContext.IsAdmin && resourceControl == nil {
|
||||||
|
return &httperror.HandlerError{http.StatusForbidden, "Access denied to resource", portainer.ErrResourceAccessDenied}
|
||||||
|
}
|
||||||
|
|
||||||
if resourceControl != nil {
|
if resourceControl != nil {
|
||||||
if securityContext.IsAdmin || proxy.CanAccessStack(stack, resourceControl, securityContext.UserID, securityContext.UserMemberships) {
|
if securityContext.IsAdmin || proxy.CanAccessStack(stack, resourceControl, securityContext.UserID, securityContext.UserMemberships) {
|
||||||
extendedStack.ResourceControl = *resourceControl
|
extendedStack.ResourceControl = *resourceControl
|
||||||
|
|
|
@ -3,11 +3,11 @@ package stacks
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/proxy"
|
"github.com/portainer/portainer/http/proxy"
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -36,6 +36,10 @@ func (handler *Handler) stackInspect(w http.ResponseWriter, r *http.Request) *ht
|
||||||
}
|
}
|
||||||
|
|
||||||
extendedStack := proxy.ExtendedStack{*stack, portainer.ResourceControl{}}
|
extendedStack := proxy.ExtendedStack{*stack, portainer.ResourceControl{}}
|
||||||
|
if !securityContext.IsAdmin && resourceControl == nil {
|
||||||
|
return &httperror.HandlerError{http.StatusForbidden, "Access denied to resource", portainer.ErrResourceAccessDenied}
|
||||||
|
}
|
||||||
|
|
||||||
if resourceControl != nil {
|
if resourceControl != nil {
|
||||||
if securityContext.IsAdmin || proxy.CanAccessStack(stack, resourceControl, securityContext.UserID, securityContext.UserMemberships) {
|
if securityContext.IsAdmin || proxy.CanAccessStack(stack, resourceControl, securityContext.UserID, securityContext.UserMemberships) {
|
||||||
extendedStack.ResourceControl = *resourceControl
|
extendedStack.ResourceControl = *resourceControl
|
||||||
|
|
|
@ -3,11 +3,11 @@ package stacks
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/proxy"
|
"github.com/portainer/portainer/http/proxy"
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,11 @@ package stacks
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/proxy"
|
"github.com/portainer/portainer/http/proxy"
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -53,8 +53,8 @@ func (handler *Handler) stackMigrate(w http.ResponseWriter, r *http.Request) *ht
|
||||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err}
|
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err}
|
||||||
}
|
}
|
||||||
|
|
||||||
if resourceControl != nil {
|
if !securityContext.IsAdmin {
|
||||||
if !securityContext.IsAdmin && !proxy.CanAccessStack(stack, resourceControl, securityContext.UserID, securityContext.UserMemberships) {
|
if !proxy.CanAccessStack(stack, resourceControl, securityContext.UserID, securityContext.UserMemberships) {
|
||||||
return &httperror.HandlerError{http.StatusForbidden, "Access denied to resource", portainer.ErrResourceAccessDenied}
|
return &httperror.HandlerError{http.StatusForbidden, "Access denied to resource", portainer.ErrResourceAccessDenied}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,11 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/proxy"
|
"github.com/portainer/portainer/http/proxy"
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -62,8 +62,8 @@ func (handler *Handler) stackUpdate(w http.ResponseWriter, r *http.Request) *htt
|
||||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err}
|
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err}
|
||||||
}
|
}
|
||||||
|
|
||||||
if resourceControl != nil {
|
if !securityContext.IsAdmin {
|
||||||
if !securityContext.IsAdmin && !proxy.CanAccessStack(stack, resourceControl, securityContext.UserID, securityContext.UserMemberships) {
|
if !proxy.CanAccessStack(stack, resourceControl, securityContext.UserID, securityContext.UserMemberships) {
|
||||||
return &httperror.HandlerError{http.StatusForbidden, "Access denied to resource", portainer.ErrResourceAccessDenied}
|
return &httperror.HandlerError{http.StatusForbidden, "Access denied to resource", portainer.ErrResourceAccessDenied}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ package status
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer/http/response"
|
"github.com/portainer/libhttp/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET request on /api/status
|
// GET request on /api/status
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type tagCreatePayload struct {
|
type tagCreatePayload struct {
|
||||||
|
|
|
@ -3,10 +3,10 @@ package tags
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DELETE request on /api/tags/:id
|
// DELETE request on /api/tags/:id
|
||||||
|
|
|
@ -3,8 +3,8 @@ package tags
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer/http/response"
|
"github.com/portainer/libhttp/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET request on /api/tags
|
// GET request on /api/tags
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package teammemberships
|
package teammemberships
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
|
@ -3,10 +3,10 @@ package teammemberships
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,10 @@ package teammemberships
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@ package teammemberships
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,10 @@ package teammemberships
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type teamCreatePayload struct {
|
type teamCreatePayload struct {
|
||||||
|
|
|
@ -3,10 +3,10 @@ package teams
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DELETE request on /api/teams/:id
|
// DELETE request on /api/teams/:id
|
||||||
|
|
|
@ -3,10 +3,10 @@ package teams
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ package teams
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer/http/response"
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,10 @@ package teams
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,10 @@ package teams
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type teamUpdatePayload struct {
|
type teamUpdatePayload struct {
|
||||||
|
|
|
@ -4,15 +4,20 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
errTemplateManagementDisabled = portainer.Error("Template management is disabled")
|
||||||
|
)
|
||||||
|
|
||||||
// Handler represents an HTTP API handler for managing templates.
|
// Handler represents an HTTP API handler for managing templates.
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
*mux.Router
|
*mux.Router
|
||||||
TemplateService portainer.TemplateService
|
TemplateService portainer.TemplateService
|
||||||
|
SettingsService portainer.SettingsService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHandler returns a new instance of Handler.
|
// NewHandler returns a new instance of Handler.
|
||||||
|
@ -20,15 +25,32 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
|
||||||
h := &Handler{
|
h := &Handler{
|
||||||
Router: mux.NewRouter(),
|
Router: mux.NewRouter(),
|
||||||
}
|
}
|
||||||
|
|
||||||
h.Handle("/templates",
|
h.Handle("/templates",
|
||||||
bouncer.RestrictedAccess(httperror.LoggerHandler(h.templateList))).Methods(http.MethodGet)
|
bouncer.RestrictedAccess(httperror.LoggerHandler(h.templateList))).Methods(http.MethodGet)
|
||||||
h.Handle("/templates",
|
h.Handle("/templates",
|
||||||
bouncer.AdministratorAccess(httperror.LoggerHandler(h.templateCreate))).Methods(http.MethodPost)
|
bouncer.AdministratorAccess(h.templateManagementCheck(httperror.LoggerHandler(h.templateCreate)))).Methods(http.MethodPost)
|
||||||
h.Handle("/templates/{id}",
|
h.Handle("/templates/{id}",
|
||||||
bouncer.AdministratorAccess(httperror.LoggerHandler(h.templateInspect))).Methods(http.MethodGet)
|
bouncer.AdministratorAccess(h.templateManagementCheck(httperror.LoggerHandler(h.templateInspect)))).Methods(http.MethodGet)
|
||||||
h.Handle("/templates/{id}",
|
h.Handle("/templates/{id}",
|
||||||
bouncer.AdministratorAccess(httperror.LoggerHandler(h.templateUpdate))).Methods(http.MethodPut)
|
bouncer.AdministratorAccess(h.templateManagementCheck(httperror.LoggerHandler(h.templateUpdate)))).Methods(http.MethodPut)
|
||||||
h.Handle("/templates/{id}",
|
h.Handle("/templates/{id}",
|
||||||
bouncer.AdministratorAccess(httperror.LoggerHandler(h.templateDelete))).Methods(http.MethodDelete)
|
bouncer.AdministratorAccess(h.templateManagementCheck(httperror.LoggerHandler(h.templateDelete)))).Methods(http.MethodDelete)
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (handler *Handler) templateManagementCheck(next http.Handler) http.Handler {
|
||||||
|
return httperror.LoggerHandler(func(rw http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||||
|
settings, err := handler.SettingsService.Settings()
|
||||||
|
if err != nil {
|
||||||
|
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve settings from the database", err}
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.TemplatesURL != "" {
|
||||||
|
return &httperror.HandlerError{http.StatusServiceUnavailable, "Portainer is configured to use external templates, template management is disabled", errTemplateManagementDisabled}
|
||||||
|
}
|
||||||
|
|
||||||
|
next.ServeHTTP(rw, r)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
"github.com/portainer/portainer/filesystem"
|
"github.com/portainer/portainer/filesystem"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type templateCreatePayload struct {
|
type templateCreatePayload struct {
|
||||||
|
|
|
@ -3,10 +3,10 @@ package templates
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DELETE request on /api/templates/:id
|
// DELETE request on /api/templates/:id
|
||||||
|
|
|
@ -3,10 +3,10 @@ package templates
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET request on /api/templates/:id
|
// GET request on /api/templates/:id
|
||||||
|
|
|
@ -1,18 +1,40 @@
|
||||||
package templates
|
package templates
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer/http/response"
|
"github.com/portainer/libhttp/response"
|
||||||
|
"github.com/portainer/portainer"
|
||||||
|
"github.com/portainer/portainer/http/client"
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET request on /api/templates
|
// GET request on /api/templates
|
||||||
func (handler *Handler) templateList(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
func (handler *Handler) templateList(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||||
templates, err := handler.TemplateService.Templates()
|
settings, err := handler.SettingsService.Settings()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve templates from the database", err}
|
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve settings from the database", err}
|
||||||
|
}
|
||||||
|
|
||||||
|
var templates []portainer.Template
|
||||||
|
if settings.TemplatesURL == "" {
|
||||||
|
templates, err = handler.TemplateService.Templates()
|
||||||
|
if err != nil {
|
||||||
|
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve templates from the database", err}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var templateData []byte
|
||||||
|
templateData, err = client.Get(settings.TemplatesURL)
|
||||||
|
if err != nil {
|
||||||
|
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve external templates", err}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(templateData, &templates)
|
||||||
|
if err != nil {
|
||||||
|
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to parse external templates", err}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
securityContext, err := security.RetrieveRestrictedRequestContext(r)
|
||||||
|
@ -21,6 +43,5 @@ func (handler *Handler) templateList(w http.ResponseWriter, r *http.Request) *ht
|
||||||
}
|
}
|
||||||
|
|
||||||
filteredTemplates := security.FilterTemplates(templates, securityContext)
|
filteredTemplates := security.FilterTemplates(templates, securityContext)
|
||||||
|
|
||||||
return response.JSON(w, filteredTemplates)
|
return response.JSON(w, filteredTemplates)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@ package templates
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
|
"github.com/portainer/libhttp/request"
|
||||||
|
"github.com/portainer/libhttp/response"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/request"
|
|
||||||
"github.com/portainer/portainer/http/response"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type templateUpdatePayload struct {
|
type templateUpdatePayload struct {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package upload
|
package upload
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
httperror "github.com/portainer/libhttp/error"
|
||||||
"github.com/portainer/portainer"
|
"github.com/portainer/portainer"
|
||||||
httperror "github.com/portainer/portainer/http/error"
|
|
||||||
"github.com/portainer/portainer/http/security"
|
"github.com/portainer/portainer/http/security"
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue