Compare commits

..

119 Commits

Author SHA1 Message Date
Platforms Team
c0ee5b67d8 Merge branch 'ado-release' 2022-02-08 20:12:28 +00:00
Chaim Lev-Ari
029e41ee46 fix(services): show task actions (#6534) 2022-02-09 09:03:47 +13:00
Platforms Team
c8deeade84 Merge branch 'ado-release' 2022-02-03 01:11:15 +00:00
andres-portainer
3c356275b3 fix(fdo): change 'http' to 'https' in the placeholder text EE-2479 (#6515) 2022-02-02 20:35:49 -03:00
yi-portainer
d0cdbc2d1e Merge branch 'release/2.11' 2022-02-02 13:42:19 +13:00
testA113
a79b89bcf3 fix font weight (#6513)
Co-authored-by: testA113 <42307911+aliharriss@users.noreply.github.com>
2022-02-02 12:32:33 +13:00
andres-portainer
41d2e7f502 fix(fdo): add suffix to the device name supplied to /fdo/configure EE-2469 (#6506) 2022-02-01 19:38:59 -03:00
testA113
774c268e8e match old tooltip styling (#6510) 2022-02-02 08:42:34 +13:00
andres-portainer
26bbdfc536 fix(db): handle decryption error EE-2466 (#6501) 2022-02-01 11:48:18 -03:00
Marcelo Rydel
08358ade26 fix(ssl): default httpEnabled to false [EE-2465] (#6496) 2022-02-01 09:14:40 -03:00
Chaim Lev-Ari
d23b374d69 fix(agent): add agent header [EE-2433] (#6485)
* fix(agent): add agent header [EE-2433]

fix [EE-2433]

* fix(containers): reload current endpoint id
2022-02-01 09:37:14 +02:00
andres-portainer
8a438e5ae6 fix(edge): change the edge menu to work in dark mode EE-2462 (#6489) 2022-01-31 19:22:22 -03:00
Marcelo Rydel
a90cfb32f1 chore(import): remove duplicated logrus import (#6497) 2022-01-28 12:02:28 -03:00
andres-portainer
4c90b9f336 fix(fdo): change the owner service connection message EE-2457 (#6491) 2022-01-28 10:06:07 -03:00
Marcelo Rydel
bb63b424a1 fix(settings): updateSettingsFromFlags only if dataStore is new [EE-2397] (#6477) 2022-01-28 09:28:29 -03:00
Prabhat Khera
3ec6c6a49d fix base url in axios (#6459) 2022-01-28 08:59:54 +13:00
Chaim Lev-Ari
6f9683b77a fix(k8s/app): populate ingress details [EE-2445] (#6464)
* fix(k8s/app): populate ingress details [EE-2445]

fix [EE-2445]

* fix(k8s/app): check if there are ingresses
2022-01-27 08:37:41 +02:00
Matt Hook
5aeaafd223 fix(restore): restore the database file correctly EE-2435 (#6448)
* prevent restoring db to the wrong name or potentially having two dbs

* fix for case where we started encrypted and restore unencrypted.  We don't want to have two databases
2022-01-27 09:04:09 +13:00
andres-portainer
31d973dab4 fix(fdo): generate an edgeID when the 'Enforce environment ID' setting is disabled EE-2446 (#6466) 2022-01-25 15:25:12 -03:00
andres-portainer
51dbdaa848 fix(fdo): cancel the action in progress on error EE-2447 (#6470) 2022-01-25 11:45:44 -03:00
Marcelo Rydel
0dbb6af646 fix(images): fix registryModal [EE-2426] (#6443) 2022-01-25 09:13:47 -03:00
Richard Wei
53865e1d0f fix input text color (#6467) 2022-01-25 15:56:30 +13:00
cong meng
a74238bf33 fix(db) EE-2425 http-disabled flag does not work (#6446)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2022-01-25 09:32:24 +13:00
Richard Wei
234b6fb369 fix(ui): fix unreadable components in dark mode EE-2417 (#6435)
* fix unreadable in dark mode
2022-01-25 08:49:19 +13:00
Chaim Lev-Ari
7650143f69 fix(app): skip authorizations in CE [EE-2423] (#6437)
* feat(app): check auth on ee only

* refactor(features): load edition from env var

* fix(containers): show empty message if no containers
2022-01-24 08:02:19 +02:00
Marcelo Rydel
1f2817b174 feat(intel): Enable OpenAMT and FDO capabilities (RELEASE) (#6452)
* feat(openamt): Configuration of the OpenAMT capability [INT-6] (#6071)

Co-authored-by: Sven Dowideit <sven.dowideit@portainer.io>

* fix(openamt): fix IsFeatureFlagEnabled, rename MPS Url to MPS Server [INT-6] (#6172)

* feat(docker): allow docker container resource settings without restart EE-1942 (#6065)

Co-authored-by: sam <sam@allofword>
Co-authored-by: sam@gemibook <huapox@126.com>
Co-authored-by: Prabhat Khera <prabhat.khera@gmail.com>

* fix(registry): fix order of registries in drop down menu EE-1939 (#5960)


Co-authored-by: Prabhat Khera <prabhat.khera@portainer.io>

* fix(docker-event-display): EE-1968: support (event_name)[:extra info] for all event Actions, and append it to the output details (#6092)

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* feat(api-key/backend): introducing support for api-key based auth EE-978 (#6079)

* feat(access-token): Multi-auth middleware support EE-1891 (#5936)

* AnyAuth middleware initial implementation with tests

* using mux.MiddlewareFunc instead of custom definition

* removed redundant comments

* - ExtractBearerToken bouncer func made private
- changed helm token handling functionality to use jwt service to convert token to jwt string
- updated tests
- fixed helm list broken test due to missing token in request context

* rename mwCheckAuthentication -> mwCheckJWTAuthentication

* - introduce initial api-key auth support using X-API-KEY header
- added tests to validate x-api-key request header presence

* updated core mwAuthenticatedUser middleware to support multiple auth paradigms

* - simplified anyAuth middleware
- enforcing authmiddleware to implement verificationFunc interface
- created tests for middleware

* simplify bouncer

Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>

* feat(api-key): user-access-token generation endpoint EE-1889 EE-1888 EE-1895 (#6012)

* user-access-token generation endpoint

* fix comment

* - introduction of apikey service
- seperation of repository from service logic - called in handler

* fixed tests

* - fixed api key prefix
- added tests

* added another test for digest matching

* updated swagger spec for access token creation

* api key response returns raw key and struct - easing testability

* test for api key prefix length

* added another TODO to middleware

* - api-key prefix rune -> string (rune does not auto-encode when response sent back to client)
- digest -> pointer as we want to allow nil values and omit digest in responses (when nil)

* - updated apikey struct
- updated apikey service to support all common operations
- updated apikey repo
- integration of apikey service into bouncer
- added test for all apikey service functions
- boilerplate code for apikey service integration

* - user access token generation tests
- apiKeyLookup updated to support query params
- added api-key tests for query params
- added api-key tests for apiKeyLookup

* get and remove access token handlers

* get and remove access token handler tests

* - delete user deletes all associated api keys
- tests for this functionality

* removed redundant []byte cast

* automatic api-key eviction set within cache for 1 hour

* fixed bug with loop var using final value

* fixed service comment

* ignore bolt error responses

* case-insensitive query param check

* simplified query var assignment

* - added GetAPIKey func to get by unique id
- updated DeleteAPIKey func to not require user ID
- updated tests

* GenerateRandomKey helper func from github.com/gorilla/securecookie moved to codebase

* json response casing for api-keys fixed

* updating api-key will update the cache

* updated golang LRU cache

* using hashicorps golang-LRU cache for api keys

* simplified jwt check in create user access token

* fixed api-key update logic on cache miss

* Prefix generated api-keys with `ptr_` (#6067)

* prefix api-keys with 'ptr_'

* updated apikey description

* refactor

Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>

* helm list test refactor

* fixed user delete test

* reduce test nil pointer errors

* using correct http 201 created status code for token creation; updated tests

* fixed swagger doc user id path param for user access token based endpoints

* added api-key security openapi spec to existing jwt secured endpoints (#6091)

* fixed flaky test

* apikey datecreated and lastused attrs converted to unix timestamp

* feat(user): added access token datatable. (#6124)

* feat(user): added access token datatable.

* feat(tokens): only display lastUsed time when it is not the default date

* Update app/portainer/views/account/accountController.js

Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>

* Update app/portainer/views/account/accountController.js

Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>

* Update app/portainer/views/account/accountController.js

Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>

* Update app/portainer/components/datatables/access-tokens-datatable/accessTokensDatatableController.js

Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>

* Update app/portainer/services/api/userService.js

Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>

* feat(improvements): proposed datatable improvements to speed up dev time (#6138)

* modal code update

* updated datatable filenames, updated controller to be default class export

* fix(access-token): code improvement.

Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>

* feat(apikeys): create access token view initial implementation EE-1886 (#6129)

* CopyButton implementation

* Code component implementation

* ToolTip component migration to another folder

* TextTip component implementation - continued

* form Heading component

* Button component updated to be more dynamic

* copybutton - small size

* form control pass tip error

* texttip small text

* CreateAccessToken react feature initial implementation

* create user access token angularjs view implementation

* registration of CreateAccessToken component in AngularJS

* user token generation API request moved to angular service, method passed down instead

* consistent naming of access token operations; clustered similar code together

* any user can add access token

* create access token page routing

* moved code component to the correct location

* removed isadmin check as all functionality applicable to all users

* create access token angular view moved up a level

* fixed PR issues, updated PR

* addressed PR issues/improvements

* explicit hr for horizontal line

* fixed merge conflict storybook build breaking

* - apikey test
- cache test

* addressed testing issues:
- description validations
- remove token description link on table

* fix(api-keys): user role change evicts user keys in cache EE-2113 (#6168)

* user role change evicts user api keys in cache

* EvictUserKeyCache -> InvalidateUserKeyCache

* godoc for InvalidateUserKeyCache func

* additional test line

* disable add access token button after adding token to prevent spam

Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>
Co-authored-by: fhanportainer <79428273+fhanportainer@users.noreply.github.com>

* fix(k8s/ingress): ensure new ports are only added to ingress only if app is published via ingress (#6153)

* fix(k8s/ingress): ensure new ports are only added to ingress only if app is published via ingress

* refactor(k8s/ingress): removed deleted ports of ingress in a single pass

* Update endpointItem.html (#6142)

feat(home): show cpu and ram for non local endpoints EE-2077

* fix(react): use ctrl directive in WidgetTitle component [EE-2118] (#6181)

* Revert "fix(openamt): fix IsFeatureFlagEnabled, rename MPS Url to MPS Server [INT-6] (#6172)" (#6182)

This reverts commit c267355759.

* fix(openamt): fix IsFeatureFlagEnabled, rename MPS Url to MPS Server (#6185)

Co-authored-by: cheloRydel <marcelorydel26@gmail.com>

* feat(registry) EE-806 add support for AWS ECR (#6165)

* feat(ecr) EE-806 add support for aws ecr

* feat(ecr) EE-806 fix wrong doc for Ecr Region

Co-authored-by: Simon Meng <simon.meng@portainer.io>

* verify repositry URL from template json when coping (#6036) (#6111)

* fix(environments): show kubeconfig env list in dark mode (#6156)

* fix(container): prevent user from editing the portainer container it self EE-917 (#6093)

* fix(container): prevent from editing portainer container

* fix(container): prevent from editing portainer container

* Missing kill operation

* fix(container): enhance creating stack from template

* fix(docker): prevent user from editing the portainer container itself EE-917

* fix(docker): enhance code style

* fix(container): fix issues from code review

* fix(container): enhance creating stack from template

* fix(container): some code review issues

* fix(container): disable leave network when the container is portainer

* fix(container): disable leave network when the container is portainer

* Fix(stack)/update StackUpdateGit swagger info to POST EE-2019 (#6176)

* fix/EE-2019/Fix-stackgitupdate-swagger

Co-authored-by: sunportainer <ericsun@SG1.local>

* feat(config): add base url support EE-506 (#5999)

* feat(openamt): add AMT Devices information in Environments view [INT-8] (#6169)

* feat(openamt): add AMT Devices Ouf of Band Managamenet actions  [INT-9] (#6171)

* feat(openamt): add AMT Devices KVM Connection [INT-10] (#6179)

* feat(openamt): Enhance the Environments MX to activate OpenAMT on compatible environments [INT-7] (#6196)

* fallback to depracted copy text if clipboard api not available (#6200) (#6218)

* - standard user cannot delete another users api-keys (#6208) (#6217)

- added new method to get api key by ID
- added tests

* fix app templates symbol (#6221)

* feat(webhook) EE-2125 send registry auth haeder when update swarms service via webhook (#6220)

* feat(webhook) EE-2125 add some helpers to registry utils

* feat(webhook) EE-2125 persist registryID when creating a webhook

* feat(webhook) EE-2125 send registry auth header when executing a webhook

* feat(webhook) EE-2125 send registryID to backend when creating a service with webhook

* feat(webhook) EE-2125 use the initial registry ID to create webhook on editing service screen

* feat(webhook) EE-2125 update webhook when update registry

* feat(webhook) EE-2125 add endpoint of update webhook

* feat(webhook) EE-2125 code cleanup

* feat(webhook) EE-2125 fix a typo

* feat(webhook) EE-2125 fix circle import issue with unit test

Co-authored-by: Simon Meng <simon.meng@portainer.io>

* fix(kubeconfig): show kubeconfig download button for non admin users [EE-2123] (#6204)

Co-authored-by: Simon Meng <simon.meng@portainer.io>

* fix data-cy for k8s cluster menu (#6226)

LGTM

* feat(stack): make stack created from app template editable EE-1941 (#6104)

feat(stack): make stack from app template editable

* feat(openamt): Enable KVM by default [INT-25] (#6228)

* fix(container):disable Duplicate/Edit button when the container is portainer (#6223)

* fix/ee-1909/show-pull-image-error (#6195)

Co-authored-by: sunportainer <ericsun@SG1.local>

* feat(fdo): implement the FDO configuration settings INT-19 (#6238)

feat(fdo): implement the FDO configuration settings INT-19

* feat(fdo): implement Owner client INT-17 (#6231)

feat(fdo): implement Owner client INT-17

* feat(cy): add data-cy to helm install button (#6241)

* feat(cy): add data-cy to add registry button (#6242)

* refactor(app): convert root folder files to es6 (#4159)

* refactor(app): duplicate constants as es6 exports (#4158)

* fix(docker): provide workaround to save network name variable  (#6080)

* fix/EE-1862/unable-to-stop-or-remove-stack workaround for var without default value in yaml file

* fix/EE-1862/unable-to-stop-or-remove-stack check yaml file

* fixed func and var names

* wrapper error and used bool for stringset

* UT case for createNetworkEnvFile

* UT case for %s=%s

* powerful StringSet

* wrapper error for extract network name

* wrapper all the return err

* store more env

* put to env file

* make default value None

* feat(openamt): hide wireless config in OpenAMT form (#6250)

* feat(openamt): Increase OpenAMT timeouts [INT-30] (#6253)

* feat(openamt): Disable the ability to use KVM and OOB actions on a MPS disconnected device [INT-36] (#6254)

* feat: gzip static resources (#6258)

* fix(ssl)//handle --sslcert and --sslkey ee-2106 (#6203)

* fix/ee-2106/handle-sslcert-sslkey

Co-authored-by: sunportainer <ericsun@SG1.local>

* fix(server):support disable https only ee-2068 (#6232)

* fix/ee-2068/disable-forcely-https

* refactor(endpoints): remove endpointProvider from views [EE-1136] (#5359)

[EE-1136]

* feat(app): introduce component library in react [EE-1816] (#6236)

* refactor(app): replace notification with es6 service (#6015) [EE-1897]

chore(app): format

* refactor(containers): remove the dependency on angular modal service (#6017) [EE-1898]

* refactor(app): remove angular from http-request [EE-1899] (#6016)

* feat(app): add axios [EE-2035](#6077)

* refactor(feature): remove angular dependency from feature service [EE-2034] (#6078)

* refactor(app): replace box-selector with react component (#6046)

fix: rename angular2react

refactor(app): make box-selector type generic

feat(app): add story for box-selector

feat(app): test box-selector

feat(app): add stories for box selector item

fix(app): remove unneccesary element

refactor(app): remove assign

* feat(feature): add be-indicator in react [EE-2005] (#6106)

* refactor(app): add react components for headers [EE-1949] (#6023)

* feat(auth): provide user context

* feat(app): added base header component [EE-1949]

style(app): reformat

refactor(app/header): use same api as angular

* feat(app): add breadcrumbs component [EE-2024]

* feat(app): remove u element from user links

* fix(users): handle axios errors

Co-authored-by: Chaim Lev-Ari <chiptus@gmail.com>

* refactor(app): convert switch component to react [EE-2005] (#6025)

Co-authored-by: Marcelo Rydel <marcelorydel26@gmail.com>

* feat(fdo): add import device UI [INT-20] (#6240)

feat(fdo): add import device UI INT-20

* release 2.11

* chore(store) EE-1981: Refactor/store/error checking, and other refactoring (#6173)

* use the Store interface IsErrObjectNotFound() to avoid revealing internal errors

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* what happens when you extract the datastore interfaces into their own package

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* Start renaming Storage methods

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* extract the boltdb specific code from the Portainer storage code (example, the others need the same)

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* more extract bolt.Tx from datastore code

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* minimise imports by putting moving the struct definition into the file that needs the Service imports

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* more extraction of boltdb.Tx

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* extract the use of bucket.SetSequence

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* almost done - just endpoint.Synchonise :/

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* so, endpoint.Synchonize looks hard, but i can't find where we use it, so 'delete first refactoring'

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* fix test compile errors

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* test compile fixes after rebase

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* fix a mis-remembering I had wrt deserialisation - last time i used AnyData - jsoniter's bindTo looks interesting for the same reason

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* set us up to make the connection an interface

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* make the db connection a datastore interface, and separate out our datastore services from the bolt ones

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* rename methods to something less oltdb internals specific

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* these errors are not boltdb secific

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* start using the db-backend factory method too

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* export boltdb raw in case we can't export from the service layer

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* add a raw export from boltdb to yaml for broken db's, and an export services to yaml in backup

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* add the version info by hand for now

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* actually, the export from services can be fully typed - its the import that needs to do more work

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* redo raw export, and make import capable of using it

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* add DockerHub

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* migration from anything older than v1.21.0 has been broken for quite a while, deleting the un-tested code

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* fix go test ./... again

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* my goland wasn't setup to gofmt

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* move the two extremely dubious migration tests down into store, so they can use the test store code

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* the migrator is now free of boltdb

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* reverse goland overzealous replcement of internal with boltdb

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* more undo over-zealous goland internal->boltdb

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* yay, now bolt is only mentioned inside the api/database/ dir

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* and this might be the last of the boltdb references?

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* add todo

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* extract the store code into a separate module too

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* don't need the fileService in boltdb anymore

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* use IsErrObjectNotFound()

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* use a string to select what database backend we use

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* make isNew store an ephemeral bool that doesn't stay true after we've initialised it

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* move the import.json wip to a separate file so its more obvious - we'll be using it for testing, emergency fixups, and in the next part of the store work, when we improve migrations and data model lifecycles

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* undo vscode formatting html

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* fix app templates symbol (#6221)

* feat(webhook) EE-2125 send registry auth haeder when update swarms service via webhook (#6220)

* feat(webhook) EE-2125 add some helpers to registry utils

* feat(webhook) EE-2125 persist registryID when creating a webhook

* feat(webhook) EE-2125 send registry auth header when executing a webhook

* feat(webhook) EE-2125 send registryID to backend when creating a service with webhook

* feat(webhook) EE-2125 use the initial registry ID to create webhook on editing service screen

* feat(webhook) EE-2125 update webhook when update registry

* feat(webhook) EE-2125 add endpoint of update webhook

* feat(webhook) EE-2125 code cleanup

* feat(webhook) EE-2125 fix a typo

* feat(webhook) EE-2125 fix circle import issue with unit test

Co-authored-by: Simon Meng <simon.meng@portainer.io>

* fix(kubeconfig): show kubeconfig download button for non admin users [EE-2123] (#6204)

Co-authored-by: Simon Meng <simon.meng@portainer.io>

* fix data-cy for k8s cluster menu (#6226)

LGTM

* feat(stack): make stack created from app template editable EE-1941 (#6104)

feat(stack): make stack from app template editable

* fix(container):disable Duplicate/Edit button when the container is portainer (#6223)

* fix/ee-1909/show-pull-image-error (#6195)

Co-authored-by: sunportainer <ericsun@SG1.local>

* feat(cy): add data-cy to helm install button (#6241)

* feat(cy): add data-cy to add registry button (#6242)

* refactor(app): convert root folder files to es6 (#4159)

* refactor(app): duplicate constants as es6 exports (#4158)

* fix(docker): provide workaround to save network name variable  (#6080)

* fix/EE-1862/unable-to-stop-or-remove-stack workaround for var without default value in yaml file

* fix/EE-1862/unable-to-stop-or-remove-stack check yaml file

* fixed func and var names

* wrapper error and used bool for stringset

* UT case for createNetworkEnvFile

* UT case for %s=%s

* powerful StringSet

* wrapper error for extract network name

* wrapper all the return err

* store more env

* put to env file

* make default value None

* feat: gzip static resources (#6258)

* fix(ssl)//handle --sslcert and --sslkey ee-2106 (#6203)

* fix/ee-2106/handle-sslcert-sslkey

Co-authored-by: sunportainer <ericsun@SG1.local>

* fix(server):support disable https only ee-2068 (#6232)

* fix/ee-2068/disable-forcely-https

* feat(store): implement store tests EE-2112 (#6224)

* add store tests

* add some more tests

* Update missing helm user repo methods

* remove redundant comments

* add webhook export

* update webhooks

* use the Store interface IsErrObjectNotFound() to avoid revealing internal errors

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* what happens when you extract the datastore interfaces into their own package

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* Start renaming Storage methods

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* extract the boltdb specific code from the Portainer storage code (example, the others need the same)

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* more extract bolt.Tx from datastore code

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* minimise imports by putting moving the struct definition into the file that needs the Service imports

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* more extraction of boltdb.Tx

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* extract the use of bucket.SetSequence

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* almost done - just endpoint.Synchonise :/

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* so, endpoint.Synchonize looks hard, but i can't find where we use it, so 'delete first refactoring'

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* fix test compile errors

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* test compile fixes after rebase

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* fix a mis-remembering I had wrt deserialisation - last time i used AnyData - jsoniter's bindTo looks interesting for the same reason

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* set us up to make the connection an interface

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* make the db connection a datastore interface, and separate out our datastore services from the bolt ones

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* rename methods to something less oltdb internals specific

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* these errors are not boltdb secific

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* start using the db-backend factory method too

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* export boltdb raw in case we can't export from the service layer

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* add a raw export from boltdb to yaml for broken db's, and an export services to yaml in backup

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* add the version info by hand for now

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* actually, the export from services can be fully typed - its the import that needs to do more work

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* redo raw export, and make import capable of using it

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* add DockerHub

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* migration from anything older than v1.21.0 has been broken for quite a while, deleting the un-tested code

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* fix go test ./... again

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* my goland wasn't setup to gofmt

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* move the two extremely dubious migration tests down into store, so they can use the test store code

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* the migrator is now free of boltdb

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* reverse goland overzealous replcement of internal with boltdb

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* more undo over-zealous goland internal->boltdb

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* yay, now bolt is only mentioned inside the api/database/ dir

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* and this might be the last of the boltdb references?

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* add todo

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* extract the store code into a separate module too

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* don't need the fileService in boltdb anymore

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* use IsErrObjectNotFound()

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* use a string to select what database backend we use

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* make isNew store an ephemeral bool that doesn't stay true after we've initialised it

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* move the import.json wip to a separate file so its more obvious - we'll be using it for testing, emergency fixups, and in the next part of the store work, when we improve migrations and data model lifecycles

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* undo vscode formatting html

Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>

* Update missing helm user repo methods

* feat(store): implement store tests EE-2112 (#6224)

* add store tests

* add some more tests

* remove redundant comments

* add webhook export

* update webhooks

* fix build issues after rebasing

* move migratorparams

* remove unneeded integer type conversions

* disable the db import/export for now

Co-authored-by: Richard Wei <54336863+WaysonWei@users.noreply.github.com>
Co-authored-by: cong meng <mcpacino@gmail.com>
Co-authored-by: Simon Meng <simon.meng@portainer.io>
Co-authored-by: Marcelo Rydel <marcelorydel26@gmail.com>
Co-authored-by: Hao Zhang <hao.zhang@portainer.io>
Co-authored-by: sunportainer <93502624+sunportainer@users.noreply.github.com>
Co-authored-by: sunportainer <ericsun@SG1.local>
Co-authored-by: wheresolivia <78844659+wheresolivia@users.noreply.github.com>
Co-authored-by: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Co-authored-by: Chao Geng <93526589+chaogeng77977@users.noreply.github.com>
Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>
Co-authored-by: Matt Hook <hookenz@gmail.com>

* add switch for react query devtools based on .env (#6280)

* refactor(fdo): fix develop merge issues

* feat(openamt): Do not fetch OpenAMT details for an unassociated Edge endpoint (#6273)

* fix(intel): Fix switches params (#6282)

* feat(cy): add data-cy to add kube volume views (#6285)

* fix(intel): fix switches params [EE-2166] (#6284)

* fix(intel): fix switches params

* feat(settings): prevent openamt panel to render

* feat(openamt): preload existing AMT settings (#6283)

* feat(frontend): upgrade frontend dependencies DTD-11 (#6244)

* upgrade webpack, eslint, storybook and other dependencies

* feat(openamt): Better UI/UX for AMT activation loading [INT-39] (#6290)

* feat(openamt): Remove wireless config related code [INT-41] (#6291)

* fix(db): fix marshalling code so that we're compatible with the existing db (#6286)

* special handling for non-json types

* added tests for json MarshalObject

* another attempt

* Fix marshal/unmarshal code for VERSION bucket

* use short form

* don't discard err

* fix the json_test.go

* remove duplicate string

* added uuid tests

* updated case for strings

Co-authored-by: zees-dev <dev.786zshan@gmail.com>

* feat(service): rebase and recommit (#6245)

* feat(service): duplication validation for configs and secrets EE-1974 (#6266)

feat(service): check if configs or secrets are duplicated

* yarn install

* feat(openamt): change kvm redirection for pop up, always enable features [INT-37] (#6292)

* feat(openamt): change kvm redirection for pop up, always enable features [INT-37] (#6293)

* feat(app): introduce form framework [EE-1946] (#6272)

* fix(modals): upgrade jquery versions (#6303)

* support upgrading (#6256)

* fix(app): main services [EE-1896] (#6279)

[EE-1896]

* chore(build): add script to analyze webpack bundle [EE-2132] (#6259)

* chore(build): add script to analyze webpack bundle

* chore(build): use single dep (lodash,moment)

* Fix(UI): disable autofill username input EE-2140 (#6252)

* fix/ee-2140/disable-autofill-username

* fix scroolbar shown in confirmation dialogs (#6264)

* fix(home): display tags properly [EE-2153] (#6275)

fix(home): display tags properly EE-2153

* fix(teams): create more then one team [EE-2184] (#6305)

fixes [EE-2184]

* feat(openmt): use .ts services with axios for OpenAMT (#6312)

* fix(kubeconfig): fix modal inputType [EE-2325] (#6317)

* Minor code cleanup.

* refactor(app): create a composed header component [EE-2329] (#6326)

* refactor(app): create a composed header component

refactor(app): support single child breadcrumbs

fix(app): fix breadcrumbs warning

* refactor(app): import breadcrumbs

* refactor(app): support object breadcrumbs

* chore(app): write tests for header components

* fix(fdo): move the FDO client code to the hostmanagement folder INT-44 (#6345)

* feat(react): migrate analytics interface to react. (#6296) [EE-2100]

* refactor(containers): replace containers datatable with react component [EE-1815] (#6059)

* feat(react): add FileUploadField and FileUploadForm components [EE-2336] (#6350)

* refactor(intel): Add Edge Compute Settings view (#6351)

* refactor(app): create access-control-form react component [EE-2332] (#6346)

* refactor(app): create access-control-form react component [EE-2332]

fix [EE-2332]

* chore(tests): setup msw for async tests and stories

chore(sb): add msw support for storybook

* refactor(access-control): move loading into component

* fix(app): fix users and teams selector stories

* chore(access-control): write test for validation

* refactor(environments): remove angular dep from service [EE-2346] (#6360)

refactor(environments): parse axios error

* fix(ldap): show BE border correctly (#6357)

* chore(tests): update AccessControlForm snapshots [EE-2348] (#6361)

* feat(fdo): add FDO profiles INT-22 (#6363)

feat(fdo): add FDO profiles INT-22

* feat(k8s): add ingressClassName to payload EE-2129 (#6265)

* add ingressClassName to payload

* add IngressClass.Name into formValues

* feat: bump golang version to 1.17.6 (#6366)

* fix(download-plugin): Image name not available when using watchtower or similar  (#6225)

* make plugin version 1.0.22 and correct download-file name

* updated to v2.0.0-rc.2

* rollback download_docker_compose_binary.sh

* fix(edgestacks): create new stack [EE-2178] (#6311)

* fix(edgestacks): create new stack [EE-2178]

[EE-2178]

* refactor(edgestacks): id is required on create

* feat(i18n): add support for multiple languages (#6270)

feat(users): add i18n to create access token

chore(app): remove test code

* refactor: unit tests (#6367)

* fix(registries): sync code with ee [EE-2176] (#6355)

fixes [EE-2176]

* fix(fdo): fix incorrect profile URL INT-45 (#6377)

* fixed husky version

* fix go.mod with go mod tidy

* fix background color for boxselector in dark/high contrast theme (#6378)

* fix(auth): prevent login for non admin for ldap and oauth [EE-648] (#5283)

* fix(stacks): show stack containers [EE-2359] (#6375)


Co-authored-by: LP B <xAt0mZ@users.noreply.github.com>

* fix(azure): parse validation error [EE-2334] (#6341)

fixes [EE-2334]

* feat(edge): migrate OpenAMT devices views to Edge Devices [EE-2322] (#6373)

* chore(i18n): set extract output path (#6384)

* feat(intel): OpenAMT UI/UX adjustments (#6394)

* only allow edge agent as edge device

* show all edge agent environments on Edge Devices view

* fix automatic team membership toggle issue (#6382)

* feat(stack): detach git based stacks from git EE-2143 (#6307)

* feat(stack): detach git based stacks from git

* feat(fdo): add the ability to import multiple ownership vouchers at once EE-2324 (#6395)

* fix(edge): settings edge compute alert (#6402)

* EE-1958 Set default value of auth and auto-update to off in page Manifest and stacks (#6380)

* fix(oauth): change default microsoft logout url [EE-2044] (#6324)

* feat(k8s): Allow mix services for k8s app EE-1791 (#6198)

allow a mix of services for k8s in ui

* fix(docker-compose): add logic control for docker compose force recreate EE-2356

* feat(database): add encryption support EE-1983 (#6316)

* bootstrap encryption key

* secret key message change in cli and secret key file content trimmed

* Migrate encryption code to latest version

* pull in newer code

* tidying up

* working data encryption layer

* fix tests

* remove stray comment

* fix a few minor issues and improve the comments

* split out databasefilename with param to two methods to be more obvious

* DB encryption integration (#6374)

* json methods moved under DBConnection

* store encryption fixed

* cleaned

* review comments addressed

* newstore value fixed

* backup test updated

* logrus format config updated

* Fix for newStore

Co-authored-by: Matt Hook <hookenz@gmail.com>

* Minor improvements

* Improve the export code.  Add missing webhook for import

* rename HelmUserRepositorys to HelmUserRepositories

* fix logging messages

* when starting portainer with a key (first use) http is disabled by default.  But when starting fresh without a key, http is enabled?

* Fix bug for default settings on new installs

Co-authored-by: Prabhat Khera <prabhat.khera@portainer.io>
Co-authored-by: Prabhat Khera <91852476+prabhat-org@users.noreply.github.com>

* fix(app): add github action for linting and formatting [EE-2344] (#6356)

* remove pagination, add useMemo for devices result array (#6409)

* feat(edge): minor Edge Devices (AMT) UI fixes (#6410)

* chore(eslint): fix versions

* chore(app): reformat codebase

* change add edge agent modal behaviour, fix yarn.lock

* fix use pagination

* remove extractedTranslations folder

* feat(edge): add FDO Profiles Datatable [EE-2406] (#6415)

* feat(edge): add KVM workaround tooltip (#6441)

* yarn install

* fix merge conflicts

* revert .codeclimate.yml change

* gofmt

* use yarn.lock from develop

* remove unused OpenAMT files

* revert Button.tsx changes, delete helm binary

* feat(edge): Add default FDO profile (#6450)

* feat(edge): add settings to disable trust on first connect and enforce Edge ID INT-1 EE-2410 (#6429)

Co-authored-by: Sven Dowideit <sven.dowideit@portainer.io>
Co-authored-by: Prabhat Khera <91852476+prabhat-org@users.noreply.github.com>
Co-authored-by: sam <sam@allofword>
Co-authored-by: sam@gemibook <huapox@126.com>
Co-authored-by: Prabhat Khera <prabhat.khera@gmail.com>
Co-authored-by: Richard Wei <54336863+WaysonWei@users.noreply.github.com>
Co-authored-by: Prabhat Khera <prabhat.khera@portainer.io>
Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>
Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>
Co-authored-by: fhanportainer <79428273+fhanportainer@users.noreply.github.com>
Co-authored-by: LP B <xAt0mZ@users.noreply.github.com>
Co-authored-by: huib-portainer <77944876+huib-portainer@users.noreply.github.com>
Co-authored-by: Matt Hook <hookenz@gmail.com>
Co-authored-by: cong meng <mcpacino@gmail.com>
Co-authored-by: Simon Meng <simon.meng@portainer.io>
Co-authored-by: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Co-authored-by: Hao Zhang <hao.zhang@portainer.io>
Co-authored-by: sunportainer <93502624+sunportainer@users.noreply.github.com>
Co-authored-by: sunportainer <ericsun@SG1.local>
Co-authored-by: andres-portainer <91705312+andres-portainer@users.noreply.github.com>
Co-authored-by: wheresolivia <78844659+wheresolivia@users.noreply.github.com>
Co-authored-by: Chao Geng <93526589+chaogeng77977@users.noreply.github.com>
Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
Co-authored-by: zees-dev <dev.786zshan@gmail.com>
Co-authored-by: andres-portainer <andres-portainer@users.noreply.github.com>
Co-authored-by: Hui <arris_li@hotmail.com>
Co-authored-by: Chaim Lev-Ari <chiptus@gmail.com>
2022-01-24 08:47:33 +13:00
Chaim Lev-Ari
9d7cf0a940 fix(docker): delete docker resources [EE-2411] (#6439)
fixes [EE-2411]

ignore resource control object not found when deleting a docker resource
2022-01-23 09:17:28 +02:00
Chaim Lev-Ari
888a5e358f fix(stacks): migrate stack resource control [EE-2412] (#6438)
fixes [EE-2412]
2022-01-23 09:16:42 +02:00
Matt Hook
a6d3f63b7b fix(backup) use correct backup db file name EE-2413 (#6421)
* fix(backup) use correct db filename in backup EE-2413

* also add missing restore database filename

* fix test datastore, go test

* Remove the json export. Its insecure and was meant to be for dev/testing

* remove portainer.db from filesToRestore
2022-01-21 13:57:21 +13:00
Matt Hook
578106df3e Fix(db): needs encryption migration function fixed EE-2414 (#6419)
* fix(db) NeedsEncryptionMigration EE-2414

* Also detect both portainer.db and portainer.edb.  Should be fatal.  Ensure calls to Fatal return a value (for testing)

* Post tech review improvements
2022-01-21 09:51:56 +13:00
Matt Hook
f54974ae6c remove rogue helm binary that was committed by mistake 2022-01-20 14:12:26 +13:00
cong meng
36001bbe0a fix(bolt) EE-2415 return nil err when resource controller not found in db (#6423)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2022-01-20 13:46:00 +13:00
Richard Wei
70d669922b fix error mesage when edit pod application (#6417) 2022-01-20 08:20:59 +13:00
Hui
893383e615 merge 2.11.1 changes into 2.11 2022-01-18 13:10:18 +13:00
ArrisLee
6db8001349 bump version number to 2.11.1 2022-01-18 11:16:44 +13:00
yi-portainer
8a8b7db14c Merge branch 'release/2.11' 2021-12-07 18:17:22 +13:00
Marcelo Rydel
787807a51a fix(kubeconfig): show kubeconfig download button for non admin users [EE-2123] RELEASE (#6205)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-12-06 18:41:27 -03:00
cong meng
9991c78d6a feat(webhook) EE-2125 send registry auth haeder when update swarms service via webhook (#6219)
* feat(webhook) EE-2125 add some helpers to registry utils

* feat(webhook) EE-2125 persist registryID when creating a webhook

* feat(webhook) EE-2125 send registry auth header when executing a webhook

* feat(webhook) EE-2125 send registryID to backend when creating a service with webhook

* feat(webhook) EE-2125 use the initial registry ID to create webhook on editing service screen

* feat(webhook) EE-2125 update webhook when update registry

* feat(webhook) EE-2125 add endpoint of update webhook

* feat(webhook) EE-2125 code cleanup

* feat(webhook) EE-2125 fix a typo

* feat(webhook) EE-2125 fix circle import issue with unit test

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-12-07 09:11:35 +13:00
Richard Wei
859ff2375e fix app template symbol (#6222) 2021-12-06 19:15:22 +13:00
zees-dev
90049af6a7 fallback to depracted copy text if clipboard api not available (#6200) 2021-12-06 09:52:44 +13:00
zees-dev
e5d092fab3 - standard user cannot delete another users api-keys (#6208)
- added new method to get api key by ID
- added tests
2021-12-06 09:52:28 +13:00
Matt Hook
d0f562a827 fix(environments): show kubeconfig env list in dark mode (#6188)
Co-authored-by: Chaim Lev-Ari <chiptus@gmail.com>
2021-12-01 13:58:40 +13:00
Matt Hook
97cafc1f5e verify repositry URL from template json when coping (#6036) (#6187)
Co-authored-by: Prabhat Khera <91852476+prabhat-org@users.noreply.github.com>
2021-12-01 13:53:43 +13:00
Matt Hook
9a73d7802e go mod tidy 2021-12-01 13:36:09 +13:00
Matt Hook
d337fdf710 Merge branch 'release/2.11' of github.com:portainer/portainer into release/2.11 2021-12-01 13:34:42 +13:00
Matt Hook
ce2d5726c1 fix missing APIKeyService definition dropped during cherry-pick 2021-12-01 13:33:38 +13:00
cong meng
64fe6fe10d feat(registry) EE-806 add support for AWS ECR (#6186)
* feat(ecr) EE-806 add support for aws ecr

* feat(ecr) EE-806 fix wrong doc for Ecr Region

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-12-01 13:27:42 +13:00
Matt Hook
817ecfc496 release 2.11 2021-12-01 11:56:43 +13:00
Marcelo Rydel
7f8545532e fix(react): use ctrl directive in WidgetTitle component [EE-2118] (#6181) 2021-12-01 11:48:02 +13:00
huib-portainer
2a8b055285 Update endpointItem.html (#6142)
feat(home): show cpu and ram for non local endpoints EE-2077
2021-12-01 11:47:52 +13:00
LP B
4a1c40528e fix(k8s/ingress): ensure new ports are only added to ingress only if app is published via ingress (#6153)
* fix(k8s/ingress): ensure new ports are only added to ingress only if app is published via ingress

* refactor(k8s/ingress): removed deleted ports of ingress in a single pass
2021-12-01 11:47:40 +13:00
zees-dev
e6d9143a09 feat(api-key/backend): introducing support for api-key based auth EE-978 (#6079)
* feat(access-token): Multi-auth middleware support EE-1891 (#5936)

* AnyAuth middleware initial implementation with tests

* using mux.MiddlewareFunc instead of custom definition

* removed redundant comments

* - ExtractBearerToken bouncer func made private
- changed helm token handling functionality to use jwt service to convert token to jwt string
- updated tests
- fixed helm list broken test due to missing token in request context

* rename mwCheckAuthentication -> mwCheckJWTAuthentication

* - introduce initial api-key auth support using X-API-KEY header
- added tests to validate x-api-key request header presence

* updated core mwAuthenticatedUser middleware to support multiple auth paradigms

* - simplified anyAuth middleware
- enforcing authmiddleware to implement verificationFunc interface
- created tests for middleware

* simplify bouncer

Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>

* feat(api-key): user-access-token generation endpoint EE-1889 EE-1888 EE-1895 (#6012)

* user-access-token generation endpoint

* fix comment

* - introduction of apikey service
- seperation of repository from service logic - called in handler

* fixed tests

* - fixed api key prefix
- added tests

* added another test for digest matching

* updated swagger spec for access token creation

* api key response returns raw key and struct - easing testability

* test for api key prefix length

* added another TODO to middleware

* - api-key prefix rune -> string (rune does not auto-encode when response sent back to client)
- digest -> pointer as we want to allow nil values and omit digest in responses (when nil)

* - updated apikey struct
- updated apikey service to support all common operations
- updated apikey repo
- integration of apikey service into bouncer
- added test for all apikey service functions
- boilerplate code for apikey service integration

* - user access token generation tests
- apiKeyLookup updated to support query params
- added api-key tests for query params
- added api-key tests for apiKeyLookup

* get and remove access token handlers

* get and remove access token handler tests

* - delete user deletes all associated api keys
- tests for this functionality

* removed redundant []byte cast

* automatic api-key eviction set within cache for 1 hour

* fixed bug with loop var using final value

* fixed service comment

* ignore bolt error responses

* case-insensitive query param check

* simplified query var assignment

* - added GetAPIKey func to get by unique id
- updated DeleteAPIKey func to not require user ID
- updated tests

* GenerateRandomKey helper func from github.com/gorilla/securecookie moved to codebase

* json response casing for api-keys fixed

* updating api-key will update the cache

* updated golang LRU cache

* using hashicorps golang-LRU cache for api keys

* simplified jwt check in create user access token

* fixed api-key update logic on cache miss

* Prefix generated api-keys with `ptr_` (#6067)

* prefix api-keys with 'ptr_'

* updated apikey description

* refactor

Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>

* helm list test refactor

* fixed user delete test

* reduce test nil pointer errors

* using correct http 201 created status code for token creation; updated tests

* fixed swagger doc user id path param for user access token based endpoints

* added api-key security openapi spec to existing jwt secured endpoints (#6091)

* fixed flaky test

* apikey datecreated and lastused attrs converted to unix timestamp

* feat(user): added access token datatable. (#6124)

* feat(user): added access token datatable.

* feat(tokens): only display lastUsed time when it is not the default date

* Update app/portainer/views/account/accountController.js

Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>

* Update app/portainer/views/account/accountController.js

Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>

* Update app/portainer/views/account/accountController.js

Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>

* Update app/portainer/components/datatables/access-tokens-datatable/accessTokensDatatableController.js

Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>

* Update app/portainer/services/api/userService.js

Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>

* feat(improvements): proposed datatable improvements to speed up dev time (#6138)

* modal code update

* updated datatable filenames, updated controller to be default class export

* fix(access-token): code improvement.

Co-authored-by: zees-dev <63374656+zees-dev@users.noreply.github.com>

* feat(apikeys): create access token view initial implementation EE-1886 (#6129)

* CopyButton implementation

* Code component implementation

* ToolTip component migration to another folder

* TextTip component implementation - continued

* form Heading component

* Button component updated to be more dynamic

* copybutton - small size

* form control pass tip error

* texttip small text

* CreateAccessToken react feature initial implementation

* create user access token angularjs view implementation

* registration of CreateAccessToken component in AngularJS

* user token generation API request moved to angular service, method passed down instead

* consistent naming of access token operations; clustered similar code together

* any user can add access token

* create access token page routing

* moved code component to the correct location

* removed isadmin check as all functionality applicable to all users

* create access token angular view moved up a level

* fixed PR issues, updated PR

* addressed PR issues/improvements

* explicit hr for horizontal line

* fixed merge conflict storybook build breaking

* - apikey test
- cache test

* addressed testing issues:
- description validations
- remove token description link on table

* fix(api-keys): user role change evicts user keys in cache EE-2113 (#6168)

* user role change evicts user api keys in cache

* EvictUserKeyCache -> InvalidateUserKeyCache

* godoc for InvalidateUserKeyCache func

* additional test line

* disable add access token button after adding token to prevent spam

Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>
Co-authored-by: fhanportainer <79428273+fhanportainer@users.noreply.github.com>
2021-12-01 11:45:28 +13:00
Sven Dowideit
1f4ca2e255 fix(docker-event-display): EE-1968: support (event_name)[:extra info] for all event Actions, and append it to the output details (#6092)
Signed-off-by: Sven Dowideit <sven.dowideit@portainer.io>
2021-12-01 11:42:53 +13:00
Richard Wei
3feac3af50 fix(registry): fix order of registries in drop down menu EE-1939 (#5960)
Co-authored-by: Prabhat Khera <prabhat.khera@portainer.io>
2021-12-01 11:42:43 +13:00
Prabhat Khera
df14784a81 feat(docker): allow docker container resource settings without restart EE-1942 (#6065)
Co-authored-by: sam <sam@allofword>
Co-authored-by: sam@gemibook <huapox@126.com>
Co-authored-by: Prabhat Khera <prabhat.khera@gmail.com>
2021-12-01 11:42:32 +13:00
yi-portainer
4cb6bb863e Merge branch 'release/2.9' 2021-11-17 15:00:33 +13:00
Matt Hook
4d906e0d42 fix(dockerhub-migration): prevent duplicate migrated dockerhub entries EE-2042 (#6084)
* add missing changes to make updateDockerhubToDB32 idempotent

* fix(migration) make dockerhub registry migration idempotent EE-2042

* add tests for bad migrations
2021-11-17 13:20:28 +13:00
Matt Hook
05041fe7fd update version to 2.9.3 2021-11-01 13:16:15 +13:00
Matt Hook
1ea9b421e0 update version to 2.9.3 2021-11-01 13:09:10 +13:00
Matt Hook
a5a7e2c868 fix(migration): bubble up recovered panic in new error EE-1971 (#5998)
* fix(migration): bubble up recovered panic in new error EE-1971

* improve code and add comments
2021-10-30 22:33:06 +13:00
Hui
bb832d285b fix(migration): ignore volumes with no created timestamp EE-1966 2021-10-30 11:09:32 +13:00
Platforms Team
caced72ec1 Merge branch 'ado-release' 2021-10-26 03:57:28 +00:00
cong meng
0d72896b6b fix(image) EE-1955 unable to tag image (#5973)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-10-26 15:22:42 +13:00
Platforms Team
48b69852eb Merge branch 'ado-release' 2021-10-25 20:49:52 +00:00
yi-portainer
273ef6c2ed Merge branch 'release/2.9' 2021-10-11 12:39:33 +13:00
yi-portainer
bac7c89363 Merge branch 'release/2.9' 2021-10-11 08:05:14 +13:00
waysonwei
4bdf3ecf58 fix decl.moveTo is not a function error in css 2021-09-23 14:15:12 +12:00
yi-portainer
89dc83f24a * sync with release/2.9 2021-09-23 11:21:46 +12:00
yi-portainer
4af6dcea0e Merge branch 'release/2.9' 2021-09-23 10:54:30 +12:00
yi-portainer
d369a71ceb Merge branch 'release/2.6' 2021-08-27 09:40:19 +12:00
Stéphane Busso
1fb5d31f7e Bump to 2.6.3 2021-08-27 09:25:49 +12:00
LP B
9c616ffb07 feat(app/k8s): update ingress scheme from v1beta1 to v1 (#5466) 2021-08-25 18:35:03 +12:00
yi-portainer
dbae99ea87 Merge branch 'release/2.6' 2021-07-30 11:14:07 +12:00
yi-portainer
3254051647 * update version to 2.6.2 2021-07-30 10:28:09 +12:00
yi-portainer
f0d128f212 Merge branch 'release/2.6' 2021-07-29 17:37:27 +12:00
Matt Hook
a0b52fc3d7 Fixes for EE-1035 and dockerhub pro accounts. (#5343) 2021-07-27 10:41:58 +12:00
cong meng
31fdef1e60 fix(advance deploy): EE-1141 A standard user can escalate to cluster administrator privileges on Kubernetes (#5324)
* fix(advance deploy): EE-1141 A standard user can escalate to cluster administrator privileges on Kubernetes

* fix(advance deploy): EE-1141 reuse existing token cache when do deployment

* fix: EE-1141 use user's SA token to exec pod command

* fix: EE-1141 stop advanced-deploy or pod-exec if user's SA token is empty

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-07-27 09:55:09 +12:00
Hui
be30e1c453 fix(swagger): add swagger annotation for pull and redeploy stack 2021-07-22 11:39:47 +12:00
Richard Wei
5b55b890e7 fix charts x label padding (#5339) 2021-07-21 13:54:26 +12:00
Dmitry Salakhov
a5eac07b0c fix(namespace): update portainer-config when delete a namespace (#5328) 2021-07-20 14:05:40 +12:00
fhanportainer
fa80a7b7e5 fix(k8s): fixed generating kube auction summary issue (#5332) 2021-07-19 19:45:14 +12:00
yi-portainer
b14500a2d5 Merge branch 'release/2.6' 2021-07-09 16:43:09 +12:00
cong meng
278667825a EE-1110 Ingress routes and their mapping to a application name are not deleted when the application is deleted (#5291)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-07-09 10:39:14 +12:00
cong meng
65ded647b6 fix(ingress): fixed hostname field when having multiple ingresses EE-1072 (#5273) (#5285)
Co-authored-by: fhanportainer <79428273+fhanportainer@users.noreply.github.com>
2021-07-08 12:08:20 +12:00
Richard Wei
084cdcd8dc fix(app):Set resource assignment default to off EE-1043 (#5286) 2021-07-08 12:08:10 +12:00
Stéphane Busso
5b68c4365e Merge branch 'release/2.6' of github.com:portainer/portainer into release/2.6 2021-07-08 11:39:21 +12:00
Stéphane Busso
9cd64664cc fix download logs (#5243) 2021-07-08 11:37:18 +12:00
yi-portainer
e831fa4a03 * update versions to 2.6.1 2021-07-07 17:20:18 +12:00
cong meng
2a3c807978 fix(ingress): EE-1049 Ingress config is lost when deleting an application deployed with ingress (#5264)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-07-07 14:08:20 +12:00
cong meng
a8265a44d0 fix EE-1078 Too strict form validation for docker environment variables (#5278)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-07-07 12:52:37 +12:00
Hui
71ad21598b remove expiry time copy logic (#5259) 2021-06-30 16:49:48 +12:00
yi-portainer
6e017ea64e Merge branch 'release/2.6' 2021-06-25 00:03:04 +12:00
yi-portainer
d48980e85b Merge branch 'release/2.5' 2021-05-28 10:22:50 +12:00
yi-portainer
80d3fcc40b Merge branch 'release/2.5' 2021-05-28 10:17:05 +12:00
yi-portainer
2e92706ead Merge branch 'release/2.5' 2021-05-24 08:50:46 +12:00
yi-portainer
d4fa9db432 Merge branch 'release/2.5' 2021-05-17 13:59:38 +12:00
yi-portainer
a28559777f Merge branch 'release/2.1' 2021-05-17 13:43:48 +12:00
yi-portainer
f6531627d4 Squashed commit of the following:
commit 535215833d
Author: yi-portainer <yi.chen@portainer.io>
Date:   Thu Feb 4 18:04:18 2021 +1300

    * version change to 2.1.1

commit c4a1243af9
Author: Dmitry Salakhov <to@dimasalakhov.com>
Date:   Thu Feb 4 03:00:25 2021 +0000

    fix: docker-compose use custom config.json to access private images (#4820)

commit 305d0d2da0
Author: LP B <xAt0mZ@users.noreply.github.com>
Date:   Wed Feb 3 06:38:56 2021 +0100

    fix(k8s/resource-pool): unusable RP access management (#4810)

    (cherry picked from commit e401724d43)

commit e4605d990d
Author: yi-portainer <yi.chen@portainer.io>
Date:   Tue Feb 2 17:42:57 2021 +1300

    * update portainer version

commit 768697157c
Author: LP B <xAt0mZ@users.noreply.github.com>
Date:   Tue Feb 2 05:00:19 2021 +0100

    sec(app): remove unused and vulnerable dependencies (#4801)

commit d3086da139
Author: cong meng <mcpacino@gmail.com>
Date:   Tue Feb 2 15:10:06 2021 +1300

    fix(k8s) trigger port validation while changing protocol (ce#394) (#4804)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 95894e8047
Author: cong meng <mcpacino@gmail.com>
Date:   Tue Feb 2 15:03:11 2021 +1300

    fix(k8s) parse empty configuration as empty string yaml instead of {} (ce#395) (#4805)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 81de55fedd
Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
Date:   Tue Feb 2 11:12:40 2021 +1300

    * fix missing kubectl download (#4802)

commit 84827b8782
Author: Steven Kang <skan070@gmail.com>
Date:   Sun Jan 31 17:32:30 2021 +1300

    feat(build): introducing buildx for Windows (#4792)

    * feat(build): introducing buildx for Windows

    * feat(build): re-ordered USER

    * feat(build): Fixed Typo

    * feat(build): fixed typo

commit a71e71f481
Author: Dmitry Salakhov <to@dimasalakhov.com>
Date:   Mon Jan 25 19:16:53 2021 +0000

    feat(compose): add docker-compose wrapper (#4713)

    * feat(compose): add docker-compose wrapper

    ce-187

    * fix(compose): pick compose implementation upon startup

    * Add static compose build for linux

    * Fix wget

    * Fix platofrm specific docker-compose download

    * Keep amd64 architecture as download parameter

    * Add tmp folder for docker-compose

    * fix: line endings

    * add proxy server

    * logs

    * Proxy

    * Add lite transport for compose

    * Fix local deployment

    * refactor: pass proxyManager by ref

    * fix: string conversion

    * refactor: compose wrapper remove unused code

    * fix: tests

    * Add edge

    * Fix merge issue

    * refactor: remove unused code

    * Move server to proxy implementation

    * Cleanup wrapper and manager

    * feat: pass max supported compose syntax version with each endpoint

    * fix: pick compose syntax version

    * fix: store wrapper version in portainer

    * Get and show composeSyntaxMaxVersion at stack creation screen

    * Get and show composeSyntaxMaxVersion at stack editor screen

    * refactor: proxy server

    * Fix used tmp

    * Bump docker-compose to 1.28.0

    * remove message for docker compose limitation

    * fix: markup typo

    * Rollback docker compose to 1.27.4

    * * attempt to fix the windows build issue

    * * attempt to debug grunt issue

    * * use console log in grunt file

    * fix: try to fix windows build by removing indirect deps from go.mod

    * Remove tmp folder

    * Remove builder stage

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose - fixed verbose output

    * refactor: renames

    * fix(stack): get endpoint by EndpointProvider

    * fix(stack): use margin to add space between line instead of using br tag

    Co-authored-by: Stéphane Busso <stephane.busso@gmail.com>
    Co-authored-by: Simon Meng <simon.meng@portainer.io>
    Co-authored-by: yi-portainer <yi.chen@portainer.io>
    Co-authored-by: Steven Kang <skan070@gmail.com>

commit 83f4c5ec0b
Author: LP B <xAt0mZ@users.noreply.github.com>
Date:   Mon Jan 25 02:43:54 2021 +0100

    fix(k8s/app): remove advanced deployment panel from app details view (#4730)

commit 41308d570d
Author: Maxime Bajeux <max.bajeux@gmail.com>
Date:   Mon Jan 25 02:14:35 2021 +0100

    feat(configurations): Review UI/UX configurations (#4691)

    * feat(configurations): Review UI/UX configurations

    * feat(configurations): fix binary secret value

    * fix(frontend): populate data between simple and advanced modes (#4503)

    * fix(configuration): parseYaml before create configuration

    * fix(configurations): change c to C in ConfigurationOwner

    * fix(application): change configuration index to configuration key in the view

    * fix(configuration): resolve problem in application create with configuration not overriden.

    * fix(configuration): fix bad import in helper

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 46ff8a01bc
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Fri Jan 22 03:08:08 2021 +0200

    fix(kubernetes/pods): save note (#4675)

    * feat(kubernetes/pods): introduce patch api

    * feat(k8s/pods): pod converter

    * feat(kubernetes/pods): introduce patch api

    * feat(k8s/pod): add annotations only if needed

    * fix(k8s/pod): replace class with factory function

commit 2b257d2785
Author: yi-portainer <yi.chen@portainer.io>
Date:   Thu Jan 21 00:02:22 2021 +1300

    Squashed commit of the following 2.0.1 release fixes:

    commit f90d6b55d6
    Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
    Date:   Wed Jan 13 00:56:19 2021 +0200

        feat(service): clear source volume when change type (#4627)

        * feat(service): clear source volume when change type

        * feat(service): init volume source to the correct value

    commit 1b82b450d7
    Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
    Date:   Thu Jan 7 14:47:32 2021 +1300

        * bump the APIVersion to 2.0.1 (#4688)

    commit b78d804881
    Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
    Date:   Wed Dec 30 23:03:43 2020 +1300

        Revert "chore(build): bump Kompose version (#4475)" (#4676)

        This reverts commit 380f106571.

        Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

    commit 51b72c12f9
    Author: Anthony Lapenna <anthony.lapenna@portainer.io>
    Date:   Wed Dec 23 14:45:32 2020 +1300

        fix(docker/stack-details): do not display editor tab for external stack (#4650)

    commit 58c04bdbe3
    Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
    Date:   Tue Dec 22 13:47:11 2020 +1300

        + silently continue when downloading artifacts in windows (#4637)

    commit a6320d5222
    Author: cong meng <mcpacino@gmail.com>
    Date:   Tue Dec 22 13:38:54 2020 +1300

        fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180) (#4618)

        * fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180)

        * fix(frontend) rephrase comments (#4629)

        Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

        Co-authored-by: Simon Meng <simon.meng@portainer.io>
        Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

commit da41dbb79a
Author: cong meng <mcpacino@gmail.com>
Date:   Wed Jan 20 15:19:35 2021 +1300

    fix(stack): stacks created via API are incorrectly marked as private with no owner (#3721) (#4725)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 68d42617f2
Author: Maxime Bajeux <max.bajeux@gmail.com>
Date:   Wed Jan 20 01:02:18 2021 +0100

    feat(placement): Add a warning notification under the placement tab when an application cannot be scheduled on any node in the cluster (#4525)

    * feat(placement): Add a warning notification under the placement tab when an application cannot be scheduled on any node in the cluster

    * fix(applications): if there is at least one node the application can schedule on, then do not show the warning

commit 8323e22309
Author: Anthony McMahon <75223906+Anthony-Portainer@users.noreply.github.com>
Date:   Wed Jan 20 12:06:25 2021 +1300

    Update issue templates

    Adding auto labelling to Bug Report (kind/bug, bug/unconfirmed) and Question (kind/question)

commit 20d4341170
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Tue Jan 19 00:10:08 2021 +0200

    fix(state): check validity of state (#4609)

commit 832cafc933
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Mon Jan 18 02:59:57 2021 +0200

    fix(registries): update password only when not empty (#4669)

commit f3c537ac2c
Author: cong meng <mcpacino@gmail.com>
Date:   Mon Jan 18 13:02:16 2021 +1300

    chore(build): bump Kompose version (#4473) (#4724)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 958baf6283
Author: Anthony McMahon <75223906+Anthony-Portainer@users.noreply.github.com>
Date:   Mon Jan 18 09:30:17 2021 +1300

    Update README.md

commit 08e392378e
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Sun Jan 17 09:28:09 2021 +0200

    chore(app): fail on angular components missing nginject (#4224)

commit a2d9734b8b
Author: Alice Groux <alice.grx@gmail.com>
Date:   Sun Jan 17 04:50:22 2021 +0100

    fix(k8s/datatables): reduce size of collapse/expand column for stacks datatable and storage datatable (#4511)

    * fix(k8s/datatables): reduce size of collapse/expand column for stacks datatable and storage datatable

    * fix(k8s/datatables): reduce size of expand/collapse column

commit 15aed9fc6f
Author: DarkAEther <30438425+DarkAEther@users.noreply.github.com>
Date:   Sun Jan 17 06:23:32 2021 +0530

    feat(area/kubernetes): show shared access policy in volume details (#4707)

commit 121d33538d
Author: Alice Groux <alice.grx@gmail.com>
Date:   Fri Jan 15 02:51:36 2021 +0100

    fix(k8s/application): validate load balancer ports inputs (#4426)

    * fix(k8s/application): validate load balancer ports inputs

    * fix(k8s/application): allow user to only change the protocol on the first port mapping

commit 7a03351df8
Author: Olli Janatuinen <olljanat@users.noreply.github.com>
Date:   Thu Jan 14 23:05:33 2021 +0200

    dep(api): Support Docker Stack 3.8 (#4333)

    - Linux: Update Docker binary to version 19.03.13
    - Windows: Update Docker binary to version 19.03.12

commit 0c2987893d
Author: Alice Groux <alice.grx@gmail.com>
Date:   Thu Jan 14 03:04:44 2021 +0100

    feat(app/images): in advanced mode, remove tooltip and add an information message (#4528)

commit d1eddaa188
Author: Alice Groux <alice.grx@gmail.com>
Date:   Thu Jan 14 00:24:56 2021 +0100

    feat(app/network): rename restrict external acces to the network label and add a tooltip (#4514)

commit d336ada3c2
Author: Anthony Lapenna <anthony.lapenna@portainer.io>
Date:   Wed Jan 13 16:13:27 2021 +1300

    feat(k8s/application): review application creation warning style (#4613)

commit 839198fbff
Author: Avadhut Tanugade <30384908+mrwhoknows55@users.noreply.github.com>
Date:   Wed Jan 13 04:49:18 2021 +0530

commit 486ffa5bbd
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Tue Jan 12 23:40:09 2021 +0200

    chore(webpack): add source maps (#4471)

    * chore(webpack): add source maps

    * feat(build): fetch source maps for 3rd party libs

commit 4cd468ce21
Author: Maxime Bajeux <max.bajeux@gmail.com>
Date:   Tue Jan 12 02:35:59 2021 +0100

    Can't create kubernetes resources with a username longer than 63 characters (#4672)

    * fix(kubernetes): truncate username when we create resource

    * fix(k8s): remove forbidden characters in owner label

commit cbd7fdc62e
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Tue Jan 12 01:38:49 2021 +0200

    feat(docker/stacks): introduce date info for stacks (#4660)

    * feat(docker/stacks): add creation and update dates

    * feat(docker/stacks): put ownership column as the last column

    * feat(docker/stacks): fix the no stacks message

    * refactor(docker/stacks): make external stacks helpers more readable

    * feat(docker/stacks): add updated and created by

    * feat(docker/stacks): toggle updated column

    * refactor(datatable): create column visibility component

    Co-authored-by: alice groux <alice.grx@gmail.com>

commit b9fe8009dd
Author: DarkAEther <30438425+DarkAEther@users.noreply.github.com>
Date:   Mon Jan 11 08:05:19 2021 +0530

    feat(image-details): Show labels in images datatable (#4287)

    * feat(images): show labels in images datatable

    * move labels to image details view

commit 6a504e7134
Author: Stéphane Busso <sbusso@users.noreply.github.com>
Date:   Mon Jan 11 14:44:15 2021 +1300

    fix(settings): Use default setting if UserSessionTimeout not set (#4521)

    * fix(settings): Use default settings if UserSessionTimeout not set

    * Update UserSessionTimeout settings in database if set to empty string

commit 51ba0876a5
Author: Alice Groux <alice.grx@gmail.com>
Date:   Mon Jan 11 00:51:46 2021 +0100

    feat(k8s/configuration): rename add ingress controller button and changed information text (#4540)

commit 769e6a4c6c
Author: Alice Groux <alice.grx@gmail.com>
Date:   Sun Jan 10 23:30:31 2021 +0100

    feat(k8s/configuration): add extra information panel when creating a sensitive configuration (#4541)

commit 105d1ae519
Author: cong meng <mcpacino@gmail.com>
Date:   Fri Jan 8 15:30:43 2021 +1300

    feat(frontend): de-emphasize internal login when OAuth is enabled (#3065) (#4565)

    * feat(frontend): de-emphasize internal login when OAuth is enabled (#3065)

    * feat(frontend): change the "Use internal authentication" style to be primary (#3065)

    * feat(frontend): resize the login with "provider" button to use a 120% font size (#3065)

    * feat(frontend): remove unused css for h1 tag (#3065)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit cf508065ec
Author: cong meng <mcpacino@gmail.com>
Date:   Fri Jan 8 12:51:27 2021 +1300

    fix(frontend): application edit page initializes the overridenKeyType of new added configuration key  to NONE so that the user can select how to load it (#4548) (#4593)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit eab828279e
Author: itsconquest <william.conquest@portainer.io>
Date:   Fri Jan 8 12:46:57 2021 +1300

    chore(project): exclude refactors (#4689)

commit d5763a970b
Author: cong meng <mcpacino@gmail.com>
Date:   Fri Jan 8 12:45:06 2021 +1300

    fix(frontend): Resource pool 'created' attribute is showing the time you view it at & not actual creation time (#4568) (#4599)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit c9f68a4d8f
Author: cong meng <mcpacino@gmail.com>
Date:   Fri Jan 8 11:55:42 2021 +1300

    fix(kubernetes): removes kube client cache when edge proxy is removed (#4487) (#4574)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 7848bcf2f4
Author: Alice Groux <alice.grx@gmail.com>
Date:   Thu Jan 7 22:29:17 2021 +0100

    feat(k8s/resources-list-view): add advanced deployment panel to resources list view (#4516)

    * feat(k8s/resources-list-view): add advanced deployment panel to applications view, configurations view and volumes view

    * feat(k8s/resources-list-view): move advanced deployment into a template and use it everywhere

commit b924347c5b
Author: Stéphane Busso <stephane.busso@gmail.com>
Date:   Thu Jan 7 14:03:46 2021 +1300

    Bump portainer version

commit 9fbda9fb99
Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
Date:   Thu Jan 7 13:38:01 2021 +1300

    Merge in release fixes to develop (#4687)

    * fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180) (#4618)

    * fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180)

    * fix(frontend) rephrase comments (#4629)

    Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

    Co-authored-by: Simon Meng <simon.meng@portainer.io>
    Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

    * + silently continue when downloading artifacts in windows (#4637)

    * fix(docker/stack-details): do not display editor tab for external stack (#4650)

    * Revert "chore(build): bump Kompose version (#4475)" (#4676)

    This reverts commit 380f106571.

    Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

    Co-authored-by: cong meng <mcpacino@gmail.com>
    Co-authored-by: Simon Meng <simon.meng@portainer.io>
    Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>
    Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

commit 82f8062784
Author: Anthony Lapenna <lapenna.anthony@gmail.com>
Date:   Wed Jan 6 11:31:05 2021 +1300

    chore(github): update issue template

commit 49982eb98a
Author: knittl <knittl89+github@gmail.com>
Date:   Tue Jan 5 20:49:50 2021 +0100

commit 4be3ac470f
Merge: 7975ef79 a50ab51b
Author: Stéphane Busso <sbusso@users.noreply.github.com>
Date:   Thu Dec 24 23:45:53 2020 +1300

    Merge pull request #4658 from portainer/revert-4475-chore-ce-86-bump-kompose-version

    Revert "chore(build): bump Kompose version"

commit a50ab51bef
Author: Stéphane Busso <sbusso@users.noreply.github.com>
Date:   Thu Dec 24 12:12:28 2020 +1300

    Revert "chore(build): bump Kompose version (#4475)"

    This reverts commit 380f106571.
2021-02-04 18:08:27 +13:00
yi-portainer
535215833d * version change to 2.1.1 2021-02-04 18:04:18 +13:00
yi-portainer
666b09ad3b Squashed commit of the following:
commit c4a1243af9
Author: Dmitry Salakhov <to@dimasalakhov.com>
Date:   Thu Feb 4 03:00:25 2021 +0000

    fix: docker-compose use custom config.json to access private images (#4820)

commit 305d0d2da0
Author: LP B <xAt0mZ@users.noreply.github.com>
Date:   Wed Feb 3 06:38:56 2021 +0100

    fix(k8s/resource-pool): unusable RP access management (#4810)

    (cherry picked from commit e401724d43)

commit e4605d990d
Author: yi-portainer <yi.chen@portainer.io>
Date:   Tue Feb 2 17:42:57 2021 +1300

    * update portainer version

commit 768697157c
Author: LP B <xAt0mZ@users.noreply.github.com>
Date:   Tue Feb 2 05:00:19 2021 +0100

    sec(app): remove unused and vulnerable dependencies (#4801)

commit d3086da139
Author: cong meng <mcpacino@gmail.com>
Date:   Tue Feb 2 15:10:06 2021 +1300

    fix(k8s) trigger port validation while changing protocol (ce#394) (#4804)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 95894e8047
Author: cong meng <mcpacino@gmail.com>
Date:   Tue Feb 2 15:03:11 2021 +1300

    fix(k8s) parse empty configuration as empty string yaml instead of {} (ce#395) (#4805)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 81de55fedd
Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
Date:   Tue Feb 2 11:12:40 2021 +1300

    * fix missing kubectl download (#4802)

commit 84827b8782
Author: Steven Kang <skan070@gmail.com>
Date:   Sun Jan 31 17:32:30 2021 +1300

    feat(build): introducing buildx for Windows (#4792)

    * feat(build): introducing buildx for Windows

    * feat(build): re-ordered USER

    * feat(build): Fixed Typo

    * feat(build): fixed typo

commit a71e71f481
Author: Dmitry Salakhov <to@dimasalakhov.com>
Date:   Mon Jan 25 19:16:53 2021 +0000

    feat(compose): add docker-compose wrapper (#4713)

    * feat(compose): add docker-compose wrapper

    ce-187

    * fix(compose): pick compose implementation upon startup

    * Add static compose build for linux

    * Fix wget

    * Fix platofrm specific docker-compose download

    * Keep amd64 architecture as download parameter

    * Add tmp folder for docker-compose

    * fix: line endings

    * add proxy server

    * logs

    * Proxy

    * Add lite transport for compose

    * Fix local deployment

    * refactor: pass proxyManager by ref

    * fix: string conversion

    * refactor: compose wrapper remove unused code

    * fix: tests

    * Add edge

    * Fix merge issue

    * refactor: remove unused code

    * Move server to proxy implementation

    * Cleanup wrapper and manager

    * feat: pass max supported compose syntax version with each endpoint

    * fix: pick compose syntax version

    * fix: store wrapper version in portainer

    * Get and show composeSyntaxMaxVersion at stack creation screen

    * Get and show composeSyntaxMaxVersion at stack editor screen

    * refactor: proxy server

    * Fix used tmp

    * Bump docker-compose to 1.28.0

    * remove message for docker compose limitation

    * fix: markup typo

    * Rollback docker compose to 1.27.4

    * * attempt to fix the windows build issue

    * * attempt to debug grunt issue

    * * use console log in grunt file

    * fix: try to fix windows build by removing indirect deps from go.mod

    * Remove tmp folder

    * Remove builder stage

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose - fixed verbose output

    * refactor: renames

    * fix(stack): get endpoint by EndpointProvider

    * fix(stack): use margin to add space between line instead of using br tag

    Co-authored-by: Stéphane Busso <stephane.busso@gmail.com>
    Co-authored-by: Simon Meng <simon.meng@portainer.io>
    Co-authored-by: yi-portainer <yi.chen@portainer.io>
    Co-authored-by: Steven Kang <skan070@gmail.com>

commit 83f4c5ec0b
Author: LP B <xAt0mZ@users.noreply.github.com>
Date:   Mon Jan 25 02:43:54 2021 +0100

    fix(k8s/app): remove advanced deployment panel from app details view (#4730)

commit 41308d570d
Author: Maxime Bajeux <max.bajeux@gmail.com>
Date:   Mon Jan 25 02:14:35 2021 +0100

    feat(configurations): Review UI/UX configurations (#4691)

    * feat(configurations): Review UI/UX configurations

    * feat(configurations): fix binary secret value

    * fix(frontend): populate data between simple and advanced modes (#4503)

    * fix(configuration): parseYaml before create configuration

    * fix(configurations): change c to C in ConfigurationOwner

    * fix(application): change configuration index to configuration key in the view

    * fix(configuration): resolve problem in application create with configuration not overriden.

    * fix(configuration): fix bad import in helper

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 46ff8a01bc
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Fri Jan 22 03:08:08 2021 +0200

    fix(kubernetes/pods): save note (#4675)

    * feat(kubernetes/pods): introduce patch api

    * feat(k8s/pods): pod converter

    * feat(kubernetes/pods): introduce patch api

    * feat(k8s/pod): add annotations only if needed

    * fix(k8s/pod): replace class with factory function

commit 2b257d2785
Author: yi-portainer <yi.chen@portainer.io>
Date:   Thu Jan 21 00:02:22 2021 +1300

    Squashed commit of the following 2.0.1 release fixes:

    commit f90d6b55d6
    Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
    Date:   Wed Jan 13 00:56:19 2021 +0200

        feat(service): clear source volume when change type (#4627)

        * feat(service): clear source volume when change type

        * feat(service): init volume source to the correct value

    commit 1b82b450d7
    Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
    Date:   Thu Jan 7 14:47:32 2021 +1300

        * bump the APIVersion to 2.0.1 (#4688)

    commit b78d804881
    Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
    Date:   Wed Dec 30 23:03:43 2020 +1300

        Revert "chore(build): bump Kompose version (#4475)" (#4676)

        This reverts commit 380f106571.

        Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

    commit 51b72c12f9
    Author: Anthony Lapenna <anthony.lapenna@portainer.io>
    Date:   Wed Dec 23 14:45:32 2020 +1300

        fix(docker/stack-details): do not display editor tab for external stack (#4650)

    commit 58c04bdbe3
    Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
    Date:   Tue Dec 22 13:47:11 2020 +1300

        + silently continue when downloading artifacts in windows (#4637)

    commit a6320d5222
    Author: cong meng <mcpacino@gmail.com>
    Date:   Tue Dec 22 13:38:54 2020 +1300

        fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180) (#4618)

        * fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180)

        * fix(frontend) rephrase comments (#4629)

        Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

        Co-authored-by: Simon Meng <simon.meng@portainer.io>
        Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

commit da41dbb79a
Author: cong meng <mcpacino@gmail.com>
Date:   Wed Jan 20 15:19:35 2021 +1300

    fix(stack): stacks created via API are incorrectly marked as private with no owner (#3721) (#4725)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 68d42617f2
Author: Maxime Bajeux <max.bajeux@gmail.com>
Date:   Wed Jan 20 01:02:18 2021 +0100

    feat(placement): Add a warning notification under the placement tab when an application cannot be scheduled on any node in the cluster (#4525)

    * feat(placement): Add a warning notification under the placement tab when an application cannot be scheduled on any node in the cluster

    * fix(applications): if there is at least one node the application can schedule on, then do not show the warning

commit 8323e22309
Author: Anthony McMahon <75223906+Anthony-Portainer@users.noreply.github.com>
Date:   Wed Jan 20 12:06:25 2021 +1300

    Update issue templates

    Adding auto labelling to Bug Report (kind/bug, bug/unconfirmed) and Question (kind/question)

commit 20d4341170
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Tue Jan 19 00:10:08 2021 +0200

    fix(state): check validity of state (#4609)

commit 832cafc933
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Mon Jan 18 02:59:57 2021 +0200

    fix(registries): update password only when not empty (#4669)

commit f3c537ac2c
Author: cong meng <mcpacino@gmail.com>
Date:   Mon Jan 18 13:02:16 2021 +1300

    chore(build): bump Kompose version (#4473) (#4724)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 958baf6283
Author: Anthony McMahon <75223906+Anthony-Portainer@users.noreply.github.com>
Date:   Mon Jan 18 09:30:17 2021 +1300

    Update README.md

commit 08e392378e
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Sun Jan 17 09:28:09 2021 +0200

    chore(app): fail on angular components missing nginject (#4224)

commit a2d9734b8b
Author: Alice Groux <alice.grx@gmail.com>
Date:   Sun Jan 17 04:50:22 2021 +0100

    fix(k8s/datatables): reduce size of collapse/expand column for stacks datatable and storage datatable (#4511)

    * fix(k8s/datatables): reduce size of collapse/expand column for stacks datatable and storage datatable

    * fix(k8s/datatables): reduce size of expand/collapse column

commit 15aed9fc6f
Author: DarkAEther <30438425+DarkAEther@users.noreply.github.com>
Date:   Sun Jan 17 06:23:32 2021 +0530

    feat(area/kubernetes): show shared access policy in volume details (#4707)

commit 121d33538d
Author: Alice Groux <alice.grx@gmail.com>
Date:   Fri Jan 15 02:51:36 2021 +0100

    fix(k8s/application): validate load balancer ports inputs (#4426)

    * fix(k8s/application): validate load balancer ports inputs

    * fix(k8s/application): allow user to only change the protocol on the first port mapping

commit 7a03351df8
Author: Olli Janatuinen <olljanat@users.noreply.github.com>
Date:   Thu Jan 14 23:05:33 2021 +0200

    dep(api): Support Docker Stack 3.8 (#4333)

    - Linux: Update Docker binary to version 19.03.13
    - Windows: Update Docker binary to version 19.03.12

commit 0c2987893d
Author: Alice Groux <alice.grx@gmail.com>
Date:   Thu Jan 14 03:04:44 2021 +0100

    feat(app/images): in advanced mode, remove tooltip and add an information message (#4528)

commit d1eddaa188
Author: Alice Groux <alice.grx@gmail.com>
Date:   Thu Jan 14 00:24:56 2021 +0100

    feat(app/network): rename restrict external acces to the network label and add a tooltip (#4514)

commit d336ada3c2
Author: Anthony Lapenna <anthony.lapenna@portainer.io>
Date:   Wed Jan 13 16:13:27 2021 +1300

    feat(k8s/application): review application creation warning style (#4613)

commit 839198fbff
Author: Avadhut Tanugade <30384908+mrwhoknows55@users.noreply.github.com>
Date:   Wed Jan 13 04:49:18 2021 +0530

commit 486ffa5bbd
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Tue Jan 12 23:40:09 2021 +0200

    chore(webpack): add source maps (#4471)

    * chore(webpack): add source maps

    * feat(build): fetch source maps for 3rd party libs

commit 4cd468ce21
Author: Maxime Bajeux <max.bajeux@gmail.com>
Date:   Tue Jan 12 02:35:59 2021 +0100

    Can't create kubernetes resources with a username longer than 63 characters (#4672)

    * fix(kubernetes): truncate username when we create resource

    * fix(k8s): remove forbidden characters in owner label

commit cbd7fdc62e
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Tue Jan 12 01:38:49 2021 +0200

    feat(docker/stacks): introduce date info for stacks (#4660)

    * feat(docker/stacks): add creation and update dates

    * feat(docker/stacks): put ownership column as the last column

    * feat(docker/stacks): fix the no stacks message

    * refactor(docker/stacks): make external stacks helpers more readable

    * feat(docker/stacks): add updated and created by

    * feat(docker/stacks): toggle updated column

    * refactor(datatable): create column visibility component

    Co-authored-by: alice groux <alice.grx@gmail.com>

commit b9fe8009dd
Author: DarkAEther <30438425+DarkAEther@users.noreply.github.com>
Date:   Mon Jan 11 08:05:19 2021 +0530

    feat(image-details): Show labels in images datatable (#4287)

    * feat(images): show labels in images datatable

    * move labels to image details view

commit 6a504e7134
Author: Stéphane Busso <sbusso@users.noreply.github.com>
Date:   Mon Jan 11 14:44:15 2021 +1300

    fix(settings): Use default setting if UserSessionTimeout not set (#4521)

    * fix(settings): Use default settings if UserSessionTimeout not set

    * Update UserSessionTimeout settings in database if set to empty string

commit 51ba0876a5
Author: Alice Groux <alice.grx@gmail.com>
Date:   Mon Jan 11 00:51:46 2021 +0100

    feat(k8s/configuration): rename add ingress controller button and changed information text (#4540)

commit 769e6a4c6c
Author: Alice Groux <alice.grx@gmail.com>
Date:   Sun Jan 10 23:30:31 2021 +0100

    feat(k8s/configuration): add extra information panel when creating a sensitive configuration (#4541)

commit 105d1ae519
Author: cong meng <mcpacino@gmail.com>
Date:   Fri Jan 8 15:30:43 2021 +1300

    feat(frontend): de-emphasize internal login when OAuth is enabled (#3065) (#4565)

    * feat(frontend): de-emphasize internal login when OAuth is enabled (#3065)

    * feat(frontend): change the "Use internal authentication" style to be primary (#3065)

    * feat(frontend): resize the login with "provider" button to use a 120% font size (#3065)

    * feat(frontend): remove unused css for h1 tag (#3065)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit cf508065ec
Author: cong meng <mcpacino@gmail.com>
Date:   Fri Jan 8 12:51:27 2021 +1300

    fix(frontend): application edit page initializes the overridenKeyType of new added configuration key  to NONE so that the user can select how to load it (#4548) (#4593)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit eab828279e
Author: itsconquest <william.conquest@portainer.io>
Date:   Fri Jan 8 12:46:57 2021 +1300

    chore(project): exclude refactors (#4689)

commit d5763a970b
Author: cong meng <mcpacino@gmail.com>
Date:   Fri Jan 8 12:45:06 2021 +1300

    fix(frontend): Resource pool 'created' attribute is showing the time you view it at & not actual creation time (#4568) (#4599)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit c9f68a4d8f
Author: cong meng <mcpacino@gmail.com>
Date:   Fri Jan 8 11:55:42 2021 +1300

    fix(kubernetes): removes kube client cache when edge proxy is removed (#4487) (#4574)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 7848bcf2f4
Author: Alice Groux <alice.grx@gmail.com>
Date:   Thu Jan 7 22:29:17 2021 +0100

    feat(k8s/resources-list-view): add advanced deployment panel to resources list view (#4516)

    * feat(k8s/resources-list-view): add advanced deployment panel to applications view, configurations view and volumes view

    * feat(k8s/resources-list-view): move advanced deployment into a template and use it everywhere

commit b924347c5b
Author: Stéphane Busso <stephane.busso@gmail.com>
Date:   Thu Jan 7 14:03:46 2021 +1300

    Bump portainer version

commit 9fbda9fb99
Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
Date:   Thu Jan 7 13:38:01 2021 +1300

    Merge in release fixes to develop (#4687)

    * fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180) (#4618)

    * fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180)

    * fix(frontend) rephrase comments (#4629)

    Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

    Co-authored-by: Simon Meng <simon.meng@portainer.io>
    Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

    * + silently continue when downloading artifacts in windows (#4637)

    * fix(docker/stack-details): do not display editor tab for external stack (#4650)

    * Revert "chore(build): bump Kompose version (#4475)" (#4676)

    This reverts commit 380f106571.

    Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

    Co-authored-by: cong meng <mcpacino@gmail.com>
    Co-authored-by: Simon Meng <simon.meng@portainer.io>
    Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>
    Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

commit 82f8062784
Author: Anthony Lapenna <lapenna.anthony@gmail.com>
Date:   Wed Jan 6 11:31:05 2021 +1300

    chore(github): update issue template

commit 49982eb98a
Author: knittl <knittl89+github@gmail.com>
Date:   Tue Jan 5 20:49:50 2021 +0100

commit 4be3ac470f
Merge: 7975ef79 a50ab51b
Author: Stéphane Busso <sbusso@users.noreply.github.com>
Date:   Thu Dec 24 23:45:53 2020 +1300

    Merge pull request #4658 from portainer/revert-4475-chore-ce-86-bump-kompose-version

    Revert "chore(build): bump Kompose version"

commit a50ab51bef
Author: Stéphane Busso <sbusso@users.noreply.github.com>
Date:   Thu Dec 24 12:12:28 2020 +1300

    Revert "chore(build): bump Kompose version (#4475)"

    This reverts commit 380f106571.
2021-02-04 17:28:23 +13:00
Dmitry Salakhov
c4a1243af9 fix: docker-compose use custom config.json to access private images (#4820) 2021-02-04 16:00:25 +13:00
LP B
305d0d2da0 fix(k8s/resource-pool): unusable RP access management (#4810)
(cherry picked from commit e401724d43)
2021-02-04 15:58:32 +13:00
yi-portainer
9af9b70f3e Squashed commit of the following:
commit e4605d990d
Author: yi-portainer <yi.chen@portainer.io>
Date:   Tue Feb 2 17:42:57 2021 +1300

    * update portainer version

commit 768697157c
Author: LP B <xAt0mZ@users.noreply.github.com>
Date:   Tue Feb 2 05:00:19 2021 +0100

    sec(app): remove unused and vulnerable dependencies (#4801)

commit d3086da139
Author: cong meng <mcpacino@gmail.com>
Date:   Tue Feb 2 15:10:06 2021 +1300

    fix(k8s) trigger port validation while changing protocol (ce#394) (#4804)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 95894e8047
Author: cong meng <mcpacino@gmail.com>
Date:   Tue Feb 2 15:03:11 2021 +1300

    fix(k8s) parse empty configuration as empty string yaml instead of {} (ce#395) (#4805)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 81de55fedd
Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
Date:   Tue Feb 2 11:12:40 2021 +1300

    * fix missing kubectl download (#4802)

commit 84827b8782
Author: Steven Kang <skan070@gmail.com>
Date:   Sun Jan 31 17:32:30 2021 +1300

    feat(build): introducing buildx for Windows (#4792)

    * feat(build): introducing buildx for Windows

    * feat(build): re-ordered USER

    * feat(build): Fixed Typo

    * feat(build): fixed typo

commit a71e71f481
Author: Dmitry Salakhov <to@dimasalakhov.com>
Date:   Mon Jan 25 19:16:53 2021 +0000

    feat(compose): add docker-compose wrapper (#4713)

    * feat(compose): add docker-compose wrapper

    ce-187

    * fix(compose): pick compose implementation upon startup

    * Add static compose build for linux

    * Fix wget

    * Fix platofrm specific docker-compose download

    * Keep amd64 architecture as download parameter

    * Add tmp folder for docker-compose

    * fix: line endings

    * add proxy server

    * logs

    * Proxy

    * Add lite transport for compose

    * Fix local deployment

    * refactor: pass proxyManager by ref

    * fix: string conversion

    * refactor: compose wrapper remove unused code

    * fix: tests

    * Add edge

    * Fix merge issue

    * refactor: remove unused code

    * Move server to proxy implementation

    * Cleanup wrapper and manager

    * feat: pass max supported compose syntax version with each endpoint

    * fix: pick compose syntax version

    * fix: store wrapper version in portainer

    * Get and show composeSyntaxMaxVersion at stack creation screen

    * Get and show composeSyntaxMaxVersion at stack editor screen

    * refactor: proxy server

    * Fix used tmp

    * Bump docker-compose to 1.28.0

    * remove message for docker compose limitation

    * fix: markup typo

    * Rollback docker compose to 1.27.4

    * * attempt to fix the windows build issue

    * * attempt to debug grunt issue

    * * use console log in grunt file

    * fix: try to fix windows build by removing indirect deps from go.mod

    * Remove tmp folder

    * Remove builder stage

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose

    * feat(build/windows): add git for Docker Compose - fixed verbose output

    * refactor: renames

    * fix(stack): get endpoint by EndpointProvider

    * fix(stack): use margin to add space between line instead of using br tag

    Co-authored-by: Stéphane Busso <stephane.busso@gmail.com>
    Co-authored-by: Simon Meng <simon.meng@portainer.io>
    Co-authored-by: yi-portainer <yi.chen@portainer.io>
    Co-authored-by: Steven Kang <skan070@gmail.com>

commit 83f4c5ec0b
Author: LP B <xAt0mZ@users.noreply.github.com>
Date:   Mon Jan 25 02:43:54 2021 +0100

    fix(k8s/app): remove advanced deployment panel from app details view (#4730)

commit 41308d570d
Author: Maxime Bajeux <max.bajeux@gmail.com>
Date:   Mon Jan 25 02:14:35 2021 +0100

    feat(configurations): Review UI/UX configurations (#4691)

    * feat(configurations): Review UI/UX configurations

    * feat(configurations): fix binary secret value

    * fix(frontend): populate data between simple and advanced modes (#4503)

    * fix(configuration): parseYaml before create configuration

    * fix(configurations): change c to C in ConfigurationOwner

    * fix(application): change configuration index to configuration key in the view

    * fix(configuration): resolve problem in application create with configuration not overriden.

    * fix(configuration): fix bad import in helper

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 46ff8a01bc
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Fri Jan 22 03:08:08 2021 +0200

    fix(kubernetes/pods): save note (#4675)

    * feat(kubernetes/pods): introduce patch api

    * feat(k8s/pods): pod converter

    * feat(kubernetes/pods): introduce patch api

    * feat(k8s/pod): add annotations only if needed

    * fix(k8s/pod): replace class with factory function

commit 2b257d2785
Author: yi-portainer <yi.chen@portainer.io>
Date:   Thu Jan 21 00:02:22 2021 +1300

    Squashed commit of the following 2.0.1 release fixes:

    commit f90d6b55d6
    Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
    Date:   Wed Jan 13 00:56:19 2021 +0200

        feat(service): clear source volume when change type (#4627)

        * feat(service): clear source volume when change type

        * feat(service): init volume source to the correct value

    commit 1b82b450d7
    Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
    Date:   Thu Jan 7 14:47:32 2021 +1300

        * bump the APIVersion to 2.0.1 (#4688)

    commit b78d804881
    Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
    Date:   Wed Dec 30 23:03:43 2020 +1300

        Revert "chore(build): bump Kompose version (#4475)" (#4676)

        This reverts commit 380f106571.

        Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

    commit 51b72c12f9
    Author: Anthony Lapenna <anthony.lapenna@portainer.io>
    Date:   Wed Dec 23 14:45:32 2020 +1300

        fix(docker/stack-details): do not display editor tab for external stack (#4650)

    commit 58c04bdbe3
    Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
    Date:   Tue Dec 22 13:47:11 2020 +1300

        + silently continue when downloading artifacts in windows (#4637)

    commit a6320d5222
    Author: cong meng <mcpacino@gmail.com>
    Date:   Tue Dec 22 13:38:54 2020 +1300

        fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180) (#4618)

        * fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180)

        * fix(frontend) rephrase comments (#4629)

        Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

        Co-authored-by: Simon Meng <simon.meng@portainer.io>
        Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

commit da41dbb79a
Author: cong meng <mcpacino@gmail.com>
Date:   Wed Jan 20 15:19:35 2021 +1300

    fix(stack): stacks created via API are incorrectly marked as private with no owner (#3721) (#4725)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 68d42617f2
Author: Maxime Bajeux <max.bajeux@gmail.com>
Date:   Wed Jan 20 01:02:18 2021 +0100

    feat(placement): Add a warning notification under the placement tab when an application cannot be scheduled on any node in the cluster (#4525)

    * feat(placement): Add a warning notification under the placement tab when an application cannot be scheduled on any node in the cluster

    * fix(applications): if there is at least one node the application can schedule on, then do not show the warning

commit 8323e22309
Author: Anthony McMahon <75223906+Anthony-Portainer@users.noreply.github.com>
Date:   Wed Jan 20 12:06:25 2021 +1300

    Update issue templates

    Adding auto labelling to Bug Report (kind/bug, bug/unconfirmed) and Question (kind/question)

commit 20d4341170
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Tue Jan 19 00:10:08 2021 +0200

    fix(state): check validity of state (#4609)

commit 832cafc933
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Mon Jan 18 02:59:57 2021 +0200

    fix(registries): update password only when not empty (#4669)

commit f3c537ac2c
Author: cong meng <mcpacino@gmail.com>
Date:   Mon Jan 18 13:02:16 2021 +1300

    chore(build): bump Kompose version (#4473) (#4724)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 958baf6283
Author: Anthony McMahon <75223906+Anthony-Portainer@users.noreply.github.com>
Date:   Mon Jan 18 09:30:17 2021 +1300

    Update README.md

commit 08e392378e
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Sun Jan 17 09:28:09 2021 +0200

    chore(app): fail on angular components missing nginject (#4224)

commit a2d9734b8b
Author: Alice Groux <alice.grx@gmail.com>
Date:   Sun Jan 17 04:50:22 2021 +0100

    fix(k8s/datatables): reduce size of collapse/expand column for stacks datatable and storage datatable (#4511)

    * fix(k8s/datatables): reduce size of collapse/expand column for stacks datatable and storage datatable

    * fix(k8s/datatables): reduce size of expand/collapse column

commit 15aed9fc6f
Author: DarkAEther <30438425+DarkAEther@users.noreply.github.com>
Date:   Sun Jan 17 06:23:32 2021 +0530

    feat(area/kubernetes): show shared access policy in volume details (#4707)

commit 121d33538d
Author: Alice Groux <alice.grx@gmail.com>
Date:   Fri Jan 15 02:51:36 2021 +0100

    fix(k8s/application): validate load balancer ports inputs (#4426)

    * fix(k8s/application): validate load balancer ports inputs

    * fix(k8s/application): allow user to only change the protocol on the first port mapping

commit 7a03351df8
Author: Olli Janatuinen <olljanat@users.noreply.github.com>
Date:   Thu Jan 14 23:05:33 2021 +0200

    dep(api): Support Docker Stack 3.8 (#4333)

    - Linux: Update Docker binary to version 19.03.13
    - Windows: Update Docker binary to version 19.03.12

commit 0c2987893d
Author: Alice Groux <alice.grx@gmail.com>
Date:   Thu Jan 14 03:04:44 2021 +0100

    feat(app/images): in advanced mode, remove tooltip and add an information message (#4528)

commit d1eddaa188
Author: Alice Groux <alice.grx@gmail.com>
Date:   Thu Jan 14 00:24:56 2021 +0100

    feat(app/network): rename restrict external acces to the network label and add a tooltip (#4514)

commit d336ada3c2
Author: Anthony Lapenna <anthony.lapenna@portainer.io>
Date:   Wed Jan 13 16:13:27 2021 +1300

    feat(k8s/application): review application creation warning style (#4613)

commit 839198fbff
Author: Avadhut Tanugade <30384908+mrwhoknows55@users.noreply.github.com>
Date:   Wed Jan 13 04:49:18 2021 +0530

commit 486ffa5bbd
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Tue Jan 12 23:40:09 2021 +0200

    chore(webpack): add source maps (#4471)

    * chore(webpack): add source maps

    * feat(build): fetch source maps for 3rd party libs

commit 4cd468ce21
Author: Maxime Bajeux <max.bajeux@gmail.com>
Date:   Tue Jan 12 02:35:59 2021 +0100

    Can't create kubernetes resources with a username longer than 63 characters (#4672)

    * fix(kubernetes): truncate username when we create resource

    * fix(k8s): remove forbidden characters in owner label

commit cbd7fdc62e
Author: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Date:   Tue Jan 12 01:38:49 2021 +0200

    feat(docker/stacks): introduce date info for stacks (#4660)

    * feat(docker/stacks): add creation and update dates

    * feat(docker/stacks): put ownership column as the last column

    * feat(docker/stacks): fix the no stacks message

    * refactor(docker/stacks): make external stacks helpers more readable

    * feat(docker/stacks): add updated and created by

    * feat(docker/stacks): toggle updated column

    * refactor(datatable): create column visibility component

    Co-authored-by: alice groux <alice.grx@gmail.com>

commit b9fe8009dd
Author: DarkAEther <30438425+DarkAEther@users.noreply.github.com>
Date:   Mon Jan 11 08:05:19 2021 +0530

    feat(image-details): Show labels in images datatable (#4287)

    * feat(images): show labels in images datatable

    * move labels to image details view

commit 6a504e7134
Author: Stéphane Busso <sbusso@users.noreply.github.com>
Date:   Mon Jan 11 14:44:15 2021 +1300

    fix(settings): Use default setting if UserSessionTimeout not set (#4521)

    * fix(settings): Use default settings if UserSessionTimeout not set

    * Update UserSessionTimeout settings in database if set to empty string

commit 51ba0876a5
Author: Alice Groux <alice.grx@gmail.com>
Date:   Mon Jan 11 00:51:46 2021 +0100

    feat(k8s/configuration): rename add ingress controller button and changed information text (#4540)

commit 769e6a4c6c
Author: Alice Groux <alice.grx@gmail.com>
Date:   Sun Jan 10 23:30:31 2021 +0100

    feat(k8s/configuration): add extra information panel when creating a sensitive configuration (#4541)

commit 105d1ae519
Author: cong meng <mcpacino@gmail.com>
Date:   Fri Jan 8 15:30:43 2021 +1300

    feat(frontend): de-emphasize internal login when OAuth is enabled (#3065) (#4565)

    * feat(frontend): de-emphasize internal login when OAuth is enabled (#3065)

    * feat(frontend): change the "Use internal authentication" style to be primary (#3065)

    * feat(frontend): resize the login with "provider" button to use a 120% font size (#3065)

    * feat(frontend): remove unused css for h1 tag (#3065)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit cf508065ec
Author: cong meng <mcpacino@gmail.com>
Date:   Fri Jan 8 12:51:27 2021 +1300

    fix(frontend): application edit page initializes the overridenKeyType of new added configuration key  to NONE so that the user can select how to load it (#4548) (#4593)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit eab828279e
Author: itsconquest <william.conquest@portainer.io>
Date:   Fri Jan 8 12:46:57 2021 +1300

    chore(project): exclude refactors (#4689)

commit d5763a970b
Author: cong meng <mcpacino@gmail.com>
Date:   Fri Jan 8 12:45:06 2021 +1300

    fix(frontend): Resource pool 'created' attribute is showing the time you view it at & not actual creation time (#4568) (#4599)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit c9f68a4d8f
Author: cong meng <mcpacino@gmail.com>
Date:   Fri Jan 8 11:55:42 2021 +1300

    fix(kubernetes): removes kube client cache when edge proxy is removed (#4487) (#4574)

    Co-authored-by: Simon Meng <simon.meng@portainer.io>

commit 7848bcf2f4
Author: Alice Groux <alice.grx@gmail.com>
Date:   Thu Jan 7 22:29:17 2021 +0100

    feat(k8s/resources-list-view): add advanced deployment panel to resources list view (#4516)

    * feat(k8s/resources-list-view): add advanced deployment panel to applications view, configurations view and volumes view

    * feat(k8s/resources-list-view): move advanced deployment into a template and use it everywhere

commit b924347c5b
Author: Stéphane Busso <stephane.busso@gmail.com>
Date:   Thu Jan 7 14:03:46 2021 +1300

    Bump portainer version

commit 9fbda9fb99
Author: Yi Chen <69284638+yi-portainer@users.noreply.github.com>
Date:   Thu Jan 7 13:38:01 2021 +1300

    Merge in release fixes to develop (#4687)

    * fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180) (#4618)

    * fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180)

    * fix(frontend) rephrase comments (#4629)

    Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

    Co-authored-by: Simon Meng <simon.meng@portainer.io>
    Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

    * + silently continue when downloading artifacts in windows (#4637)

    * fix(docker/stack-details): do not display editor tab for external stack (#4650)

    * Revert "chore(build): bump Kompose version (#4475)" (#4676)

    This reverts commit 380f106571.

    Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

    Co-authored-by: cong meng <mcpacino@gmail.com>
    Co-authored-by: Simon Meng <simon.meng@portainer.io>
    Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>
    Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

commit 82f8062784
Author: Anthony Lapenna <lapenna.anthony@gmail.com>
Date:   Wed Jan 6 11:31:05 2021 +1300

    chore(github): update issue template

commit 49982eb98a
Author: knittl <knittl89+github@gmail.com>
Date:   Tue Jan 5 20:49:50 2021 +0100

commit 4be3ac470f
Merge: 7975ef79 a50ab51b
Author: Stéphane Busso <sbusso@users.noreply.github.com>
Date:   Thu Dec 24 23:45:53 2020 +1300

    Merge pull request #4658 from portainer/revert-4475-chore-ce-86-bump-kompose-version

    Revert "chore(build): bump Kompose version"

commit a50ab51bef
Author: Stéphane Busso <sbusso@users.noreply.github.com>
Date:   Thu Dec 24 12:12:28 2020 +1300

    Revert "chore(build): bump Kompose version (#4475)"

    This reverts commit 380f106571.
2021-02-02 17:54:02 +13:00
yi-portainer
e4605d990d * update portainer version 2021-02-02 17:42:57 +13:00
LP B
768697157c sec(app): remove unused and vulnerable dependencies (#4801) 2021-02-02 17:02:06 +13:00
cong meng
d3086da139 fix(k8s) trigger port validation while changing protocol (ce#394) (#4804)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-02-02 15:10:06 +13:00
cong meng
95894e8047 fix(k8s) parse empty configuration as empty string yaml instead of {} (ce#395) (#4805)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-02-02 15:03:11 +13:00
Yi Chen
81de55fedd * fix missing kubectl download (#4802) 2021-02-02 11:12:40 +13:00
Steven Kang
84827b8782 feat(build): introducing buildx for Windows (#4792)
* feat(build): introducing buildx for Windows

* feat(build): re-ordered USER

* feat(build): Fixed Typo

* feat(build): fixed typo
2021-01-31 17:32:30 +13:00
yi-portainer
fa38af5d81 Merge remote-tracking branch 'origin/release/2.0.1' 2021-01-07 14:56:52 +13:00
Yi Chen
1b82b450d7 * bump the APIVersion to 2.0.1 (#4688) 2021-01-07 14:47:32 +13:00
Yi Chen
b78d804881 Revert "chore(build): bump Kompose version (#4475)" (#4676)
This reverts commit 380f106571.

Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>
2020-12-30 23:03:43 +13:00
Anthony Lapenna
51b72c12f9 fix(docker/stack-details): do not display editor tab for external stack (#4650) 2020-12-23 14:45:32 +13:00
Yi Chen
58c04bdbe3 + silently continue when downloading artifacts in windows (#4637) 2020-12-22 13:47:11 +13:00
cong meng
a6320d5222 fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180) (#4618)
* fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ce#180)

* fix(frontend) rephrase comments (#4629)

Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>

Co-authored-by: Simon Meng <simon.meng@portainer.io>
Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>
2020-12-22 13:38:54 +13:00
Anthony Lapenna
cb4b4a43e6 update pull dog configuration 2020-08-31 18:09:19 +12:00
Anthony Lapenna
1e5a1d5bdd Merge branch 'develop' 2020-08-31 18:06:50 +12:00
Anthony Lapenna
5ed0d21c39 Merge branch 'ee-pulldog' 2020-08-28 15:26:30 +12:00
Anthony Lapenna
2972dbeafb feat(build/pulldog): review pulldog configuration 2020-08-18 12:36:01 +12:00
1225 changed files with 22392 additions and 35262 deletions

View File

@@ -1,5 +1,3 @@
*
!dist
!build
!metadata.json
!docker-extension/build

View File

@@ -1,5 +1,4 @@
# prettier
cf5056d9c03b62d91a25c3b9127caac838695f98
# prettier v2
42e7db0ae7897d3cb72b0ea1ecf57ee2dd694169
# prettier v2 (put here after fix/EE-2344/fix-eslint-issues is merged)

View File

@@ -2,7 +2,7 @@
Thanks for opening an issue on Portainer !
Do you need help or have a question? Come chat with us on Slack https://portainer.io/slack/ or gitter https://gitter.im/portainer/Lobby.
Do you need help or have a question? Come chat with us on Slack http://portainer.io/slack/ or gitter https://gitter.im/portainer/Lobby.
If you are reporting a new issue, make sure that we do not have any duplicates
already open. You can ensure this by searching the issue list for this

View File

@@ -12,7 +12,7 @@ Thanks for reporting a bug for Portainer !
You can find more information about Portainer support framework policy here: https://www.portainer.io/2019/04/portainer-support-policy/
Do you need help or have a question? Come chat with us on Slack https://portainer.io/slack/
Do you need help or have a question? Come chat with us on Slack http://portainer.slack.com/
Before opening a new issue, make sure that we do not have any duplicates
already open. You can ensure this by searching the issue list for this
@@ -47,7 +47,7 @@ You can see how [here](https://documentation.portainer.io/r/portainer-logs)
- Platform (windows/linux):
- Command used to start Portainer (`docker run -p 9443:9443 portainer/portainer`):
- Browser:
- Use Case (delete as appropriate): Using Portainer at Home, Using Portainer in a Commercial setup.
- Use Case (delete as appropriate): Using Portainer at Home, Using Portainer in a Commerical setup.
- Have you reviewed our technical documentation and knowledge base? Yes/No
**Additional context**

View File

@@ -4,11 +4,11 @@ about: Ask us a question about Portainer usage or deployment
title: ''
labels: ''
assignees: ''
---
---
Before you start, we need a little bit more information from you:
Use Case (delete as appropriate): Using Portainer at Home, Using Portainer in a Commercial setup.
Use Case (delete as appropriate): Using Portainer at Home, Using Portainer in a Commerical setup.
Have you reviewed our technical documentation and knowledge base? Yes/No
@@ -16,7 +16,7 @@ Have you reviewed our technical documentation and knowledge base? Yes/No
You can find more information about Portainer support framework policy here: https://old.portainer.io/2019/04/portainer-support-policy/
Do you need help or have a question? Come chat with us on Slack https://portainer.io/slack/
Do you need help or have a question? Come chat with us on Slack http://portainer.slack.com/
Also, be sure to check our FAQ and documentation first: https://documentation.portainer.io/
-->

View File

@@ -4,13 +4,14 @@ about: Suggest a feature/enhancement that should be added in Portainer
title: ''
labels: ''
assignees: ''
---
<!--
Thanks for opening a feature request for Portainer !
Do you need help or have a question? Come chat with us on Slack https://portainer.io/slack/
Do you need help or have a question? Come chat with us on Slack http://portainer.slack.com/
Before opening a new issue, make sure that we do not have any duplicates
already open. You can ensure this by searching the issue list for this

View File

@@ -1,4 +0,0 @@
closes #0 <!-- Github issue number (remove if unknown) -->
closes [CE-0] <!-- Jira link number (remove if unknown). Please also add the same [CE-XXX] at the back of the PR title -->
### Changes:

View File

@@ -18,12 +18,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- name: Check out Git repository
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v1
with:
node-version: '14'
cache: 'yarn'
- run: yarn --frozen-lockfile
node-version: 12
# ESLint and Prettier must be in `package.json`
- name: Install Node.js dependencies
run: yarn
- name: Run linters
uses: wearerequired/lint-action@v1
@@ -34,5 +39,3 @@ jobs:
prettier_dir: app/
gofmt: true
gofmt_dir: api/
- name: Typecheck
uses: icrawl/action-tsc@v1

View File

@@ -1,230 +0,0 @@
name: Nightly Code Security Scan
on:
schedule:
- cron: '0 8 * * *'
workflow_dispatch:
jobs:
client-dependencies:
name: Client dependency check
runs-on: ubuntu-latest
if: >- # only run for develop branch
github.ref == 'refs/heads/develop'
outputs:
js: ${{ steps.set-matrix.outputs.js_result }}
steps:
- uses: actions/checkout@master
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@master
continue-on-error: true # To make sure that artifact upload gets called
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
json: true
- name: Upload js security scan result as artifact
uses: actions/upload-artifact@v3
with:
name: js-security-scan-develop-result
path: snyk.json
- name: Export scan result to html file
run: |
$(docker run --rm -v ${{ github.workspace }}:/data oscarzhou/scan-report:0.1.8 summary -report-type=snyk -path="/data/snyk.json" -output-type=table -export -export-filename="/data/js-result")
- name: Upload js result html file
uses: actions/upload-artifact@v3
with:
name: html-js-result-${{github.run_id}}
path: js-result.html
- name: Analyse the js result
id: set-matrix
run: |
result=$(docker run --rm -v ${{ github.workspace }}:/data oscarzhou/scan-report:0.1.8 summary -report-type=snyk -path="/data/snyk.json" -output-type=matrix)
echo "::set-output name=js_result::${result}"
server-dependencies:
name: Server dependency check
runs-on: ubuntu-latest
if: >- # only run for develop branch
github.ref == 'refs/heads/develop'
outputs:
go: ${{ steps.set-matrix.outputs.go_result }}
steps:
- uses: actions/checkout@master
- name: Download go modules
run: cd ./api && go get -t -v -d ./...
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/golang@master
continue-on-error: true # To make sure that artifact upload gets called
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --file=./api/go.mod
json: true
- name: Upload go security scan result as artifact
uses: actions/upload-artifact@v3
with:
name: go-security-scan-develop-result
path: snyk.json
- name: Export scan result to html file
run: |
$(docker run --rm -v ${{ github.workspace }}:/data oscarzhou/scan-report:0.1.8 summary -report-type=snyk -path="/data/snyk.json" -output-type=table -export -export-filename="/data/go-result")
- name: Upload go result html file
uses: actions/upload-artifact@v3
with:
name: html-go-result-${{github.run_id}}
path: go-result.html
- name: Analyse the go result
id: set-matrix
run: |
result=$(docker run --rm -v ${{ github.workspace }}:/data oscarzhou/scan-report:0.1.8 summary -report-type=snyk -path="/data/snyk.json" -output-type=matrix)
echo "::set-output name=go_result::${result}"
image-vulnerability:
name: Build docker image and Image vulnerability check
runs-on: ubuntu-latest
if: >-
github.ref == 'refs/heads/develop'
outputs:
image: ${{ steps.set-matrix.outputs.image_result }}
steps:
- name: Checkout code
uses: actions/checkout@master
- name: Use golang 1.18
uses: actions/setup-go@v3
with:
go-version: '1.18'
- name: Use Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Install packages and build
run: yarn install && yarn build
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: build/linux/Dockerfile
tags: trivy-portainer:${{ github.sha }}
outputs: type=docker,dest=/tmp/trivy-portainer-image.tar
- name: Load docker image
run: |
docker load --input /tmp/trivy-portainer-image.tar
- name: Run Trivy vulnerability scanner
uses: docker://docker.io/aquasec/trivy:latest
continue-on-error: true
with:
args: image --ignore-unfixed=true --vuln-type="os,library" --exit-code=1 --format="json" --output="image-trivy.json" --no-progress trivy-portainer:${{ github.sha }}
- name: Upload image security scan result as artifact
uses: actions/upload-artifact@v3
with:
name: image-security-scan-develop-result
path: image-trivy.json
- name: Export scan result to html file
run: |
$(docker run --rm -v ${{ github.workspace }}:/data oscarzhou/scan-report:0.1.8 summary -report-type=trivy -path="/data/image-trivy.json" -output-type=table -export -export-filename="/data/image-result")
- name: Upload go result html file
uses: actions/upload-artifact@v3
with:
name: html-image-result-${{github.run_id}}
path: image-result.html
- name: Analyse the trivy result
id: set-matrix
run: |
result=$(docker run --rm -v ${{ github.workspace }}:/data oscarzhou/scan-report:0.1.8 summary -report-type=trivy -path="/data/image-trivy.json" -output-type=matrix)
echo "::set-output name=image_result::${result}"
result-analysis:
name: Analyse scan result
needs: [client-dependencies, server-dependencies, image-vulnerability]
runs-on: ubuntu-latest
if: >-
github.ref == 'refs/heads/develop'
strategy:
matrix:
js: ${{fromJson(needs.client-dependencies.outputs.js)}}
go: ${{fromJson(needs.server-dependencies.outputs.go)}}
image: ${{fromJson(needs.image-vulnerability.outputs.image)}}
steps:
- name: Display the results of js, go and image
run: |
echo ${{ matrix.js.status }}
echo ${{ matrix.go.status }}
echo ${{ matrix.image.status }}
echo ${{ matrix.js.summary }}
echo ${{ matrix.go.summary }}
echo ${{ matrix.image.summary }}
- name: Send Slack message
if: >-
matrix.js.status == 'failure' ||
matrix.go.status == 'failure' ||
matrix.image.status == 'failure'
uses: slackapi/slack-github-action@v1.18.0
with:
payload: |
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Code Scanning Result (*${{ github.repository }}*)\n*<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|GitHub Actions Workflow URL>*"
}
}
],
"attachments": [
{
"color": "#FF0000",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*JS dependency check*: *${{ matrix.js.status }}*\n${{ matrix.js.summary }}"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Go dependency check*: *${{ matrix.go.status }}*\n${{ matrix.go.summary }}"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Image vulnerability check*: *${{ matrix.image.status }}*\n${{ matrix.image.summary }}\n"
}
}
]
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SECURITY_SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

View File

@@ -1,233 +0,0 @@
name: PR Code Security Scan
on:
pull_request_review:
types:
- submitted
- edited
paths:
- 'package.json'
- 'api/go.mod'
- 'gruntfile.js'
- 'build/linux/Dockerfile'
- 'build/linux/alpine.Dockerfile'
- 'build/windows/Dockerfile'
jobs:
client-dependencies:
name: Client dependency check
runs-on: ubuntu-latest
if: >-
github.event.pull_request &&
github.event.review.body == '/scan'
outputs:
jsdiff: ${{ steps.set-diff-matrix.outputs.js_diff_result }}
steps:
- uses: actions/checkout@master
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@master
continue-on-error: true # To make sure that artifact upload gets called
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
json: true
- name: Upload js security scan result as artifact
uses: actions/upload-artifact@v3
with:
name: js-security-scan-feat-result
path: snyk.json
- name: Download artifacts from develop branch
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mv ./snyk.json ./js-snyk-feature.json
(gh run download -n js-security-scan-develop-result -R ${{ github.repository }} 2>&1 >/dev/null) || :
if [[ -e ./snyk.json ]]; then
mv ./snyk.json ./js-snyk-develop.json
else
echo "null" > ./js-snyk-develop.json
fi
- name: Export scan result to html file
run: |
$(docker run --rm -v ${{ github.workspace }}:/data oscarzhou/scan-report:0.1.8 diff -report-type=snyk -path="/data/js-snyk-feature.json" -compare-to="/data/js-snyk-develop.json" -output-type=table -export -export-filename="/data/js-result")
- name: Upload js result html file
uses: actions/upload-artifact@v3
with:
name: html-js-result-compare-to-develop-${{github.run_id}}
path: js-result.html
- name: Analyse the js diff result
id: set-diff-matrix
run: |
result=$(docker run --rm -v ${{ github.workspace }}:/data oscarzhou/scan-report:0.1.8 diff -report-type=snyk -path="/data/js-snyk-feature.json" -compare-to="./data/js-snyk-develop.json" -output-type=matrix)
echo "::set-output name=js_diff_result::${result}"
server-dependencies:
name: Server dependency check
runs-on: ubuntu-latest
if: >-
github.event.pull_request &&
github.event.review.body == '/scan'
outputs:
godiff: ${{ steps.set-diff-matrix.outputs.go_diff_result }}
steps:
- uses: actions/checkout@master
- name: Download go modules
run: cd ./api && go get -t -v -d ./...
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/golang@master
continue-on-error: true # To make sure that artifact upload gets called
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --file=./api/go.mod
json: true
- name: Upload go security scan result as artifact
uses: actions/upload-artifact@v3
with:
name: go-security-scan-feature-result
path: snyk.json
- name: Download artifacts from develop branch
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mv ./snyk.json ./go-snyk-feature.json
(gh run download -n go-security-scan-develop-result -R ${{ github.repository }} 2>&1 >/dev/null) || :
if [[ -e ./snyk.json ]]; then
mv ./snyk.json ./go-snyk-develop.json
else
echo "null" > ./go-snyk-develop.json
fi
- name: Export scan result to html file
run: |
$(docker run --rm -v ${{ github.workspace }}:/data oscarzhou/scan-report:0.1.8 diff -report-type=snyk -path="/data/go-snyk-feature.json" -compare-to="/data/go-snyk-develop.json" -output-type=table -export -export-filename="/data/go-result")
- name: Upload go result html file
uses: actions/upload-artifact@v3
with:
name: html-go-result-compare-to-develop-${{github.run_id}}
path: go-result.html
- name: Analyse the go diff result
id: set-diff-matrix
run: |
result=$(docker run --rm -v ${{ github.workspace }}:/data oscarzhou/scan-report:0.1.8 diff -report-type=snyk -path="/data/go-snyk-feature.json" -compare-to="/data/go-snyk-develop.json" -output-type=matrix)
echo "::set-output name=go_diff_result::${result}"
image-vulnerability:
name: Build docker image and Image vulnerability check
runs-on: ubuntu-latest
if: >-
github.event.pull_request &&
github.event.review.body == '/scan'
outputs:
imagediff: ${{ steps.set-diff-matrix.outputs.image_diff_result }}
steps:
- name: Checkout code
uses: actions/checkout@master
- name: Use golang 1.18
uses: actions/setup-go@v3
with:
go-version: '1.18'
- name: Use Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Install packages and build
run: yarn install && yarn build
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: build/linux/Dockerfile
tags: trivy-portainer:${{ github.sha }}
outputs: type=docker,dest=/tmp/trivy-portainer-image.tar
- name: Load docker image
run: |
docker load --input /tmp/trivy-portainer-image.tar
- name: Run Trivy vulnerability scanner
uses: docker://docker.io/aquasec/trivy:latest
continue-on-error: true
with:
args: image --ignore-unfixed=true --vuln-type="os,library" --exit-code=1 --format="json" --output="image-trivy.json" --no-progress trivy-portainer:${{ github.sha }}
- name: Upload image security scan result as artifact
uses: actions/upload-artifact@v3
with:
name: image-security-scan-feature-result
path: image-trivy.json
- name: Download artifacts from develop branch
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mv ./image-trivy.json ./image-trivy-feature.json
(gh run download -n image-security-scan-develop-result -R ${{ github.repository }} 2>&1 >/dev/null) || :
if [[ -e ./image-trivy.json ]]; then
mv ./image-trivy.json ./image-trivy-develop.json
else
echo "null" > ./image-trivy-develop.json
fi
- name: Export scan result to html file
run: |
$(docker run --rm -v ${{ github.workspace }}:/data oscarzhou/scan-report:0.1.8 diff -report-type=trivy -path="/data/image-trivy-feature.json" -compare-to="/data/image-trivy-develop.json" -output-type=table -export -export-filename="/data/image-result")
- name: Upload image result html file
uses: actions/upload-artifact@v3
with:
name: html-image-result-compare-to-develop-${{github.run_id}}
path: image-result.html
- name: Analyse the image diff result
id: set-diff-matrix
run: |
result=$(docker run --rm -v ${{ github.workspace }}:/data oscarzhou/scan-report:0.1.8 diff -report-type=trivy -path="/data/image-trivy-feature.json" -compare-to="./data/image-trivy-develop.json" -output-type=matrix)
echo "::set-output name=image_diff_result::${result}"
result-analysis:
name: Analyse scan result compared to develop
needs: [client-dependencies, server-dependencies, image-vulnerability]
runs-on: ubuntu-latest
if: >-
github.event.pull_request &&
github.event.review.body == '/scan'
strategy:
matrix:
jsdiff: ${{fromJson(needs.client-dependencies.outputs.jsdiff)}}
godiff: ${{fromJson(needs.server-dependencies.outputs.godiff)}}
imagediff: ${{fromJson(needs.image-vulnerability.outputs.imagediff)}}
steps:
- name: Check job status of diff result
if: >-
matrix.jsdiff.status == 'failure' ||
matrix.godiff.status == 'failure' ||
matrix.imagediff.status == 'failure'
run: |
echo ${{ matrix.jsdiff.status }}
echo ${{ matrix.godiff.status }}
echo ${{ matrix.imagediff.status }}
echo ${{ matrix.jsdiff.summary }}
echo ${{ matrix.godiff.summary }}
echo ${{ matrix.imagediff.summary }}
exit 1

11
.github/workflows/test-client.yaml vendored Normal file
View File

@@ -0,0 +1,11 @@
name: Test Frontend
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install modules
run: yarn
- name: Run tests
run: yarn test:client

View File

@@ -1,29 +0,0 @@
name: Test
on: push
jobs:
test-client:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '14'
cache: 'yarn'
- run: yarn --frozen-lockfile
- name: Run tests
run: yarn test:client
# test-server:
# runs-on: ubuntu-latest
# env:
# GOPRIVATE: "github.com/portainer"
# steps:
# - uses: actions/checkout@v3
# - uses: actions/setup-go@v3
# with:
# go-version: '1.18'
# - name: Run tests
# run: |
# cd api
# go test ./...

View File

@@ -1,2 +1 @@
dist
api/datastore/test_data
dist

View File

@@ -16,9 +16,6 @@ module.exports = {
exportLocalsConvention: 'camelCaseOnly',
},
},
postcssLoaderOptions: {
implementation: require('postcss'),
},
},
},
],

View File

@@ -3,7 +3,6 @@ import '../app/assets/css';
import { pushStateLocationPlugin, UIRouter } from '@uirouter/react';
import { initialize as initMSW, mswDecorator } from 'msw-storybook-addon';
import { handlers } from '@/setup-tests/server-handlers';
import { QueryClient, QueryClientProvider } from 'react-query';
// Initialize MSW
initMSW({
@@ -32,17 +31,11 @@ export const parameters = {
},
};
const testQueryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
export const decorators = [
(Story) => (
<QueryClientProvider client={testQueryClient}>
<UIRouter plugins={[pushStateLocationPlugin]}>
<Story />
</UIRouter>
</QueryClientProvider>
<UIRouter plugins={[pushStateLocationPlugin]}>
<Story />
</UIRouter>
),
mswDecorator,
];

View File

@@ -9,7 +9,7 @@
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceRoot}/api/cmd/portainer",
"program": "${workspaceRoot}/api/cmd/portainer/main.go",
"cwd": "${workspaceRoot}",
"env": {},
"showLog": true,

View File

@@ -1,8 +1,5 @@
{
"go.lintTool": "golangci-lint",
"go.lintFlags": ["--fast", "-E", "exportloopref"],
"gopls": {
"build.expandWorkspaceToModule": false
},
"gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"]
"gitlens.advanced.blame.customArguments": ["ignore-revs-file", ".git-blame-ignore-revs"]
}

View File

@@ -42,10 +42,10 @@ View [this](https://www.portainer.io/products) table to see all of the Portainer
Portainer CE is an open source project and is supported by the community. You can buy a supported version of Portainer at portainer.io
Learn more about Portainer's community support channels [here.](https://www.portainer.io/community_help)
Learn more about Portainers community support channels [here.](https://www.portainer.io/community_help)
- Issues: https://github.com/portainer/portainer/issues
- Slack (chat): [https://portainer.io/slack](https://portainer.io/slack)
- Slack (chat): [https://portainer.slack.com/](https://join.slack.com/t/portainer/shared_invite/zt-txh3ljab-52QHTyjCqbe5RibC2lcjKA)
You can join the Portainer Community by visiting community.portainer.io. This will give you advance notice of events, content and other related Portainer content.

View File

@@ -3,48 +3,32 @@ package adminmonitor
import (
"context"
"log"
"net/http"
"strings"
"sync"
"time"
httperror "github.com/portainer/libhttp/error"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
)
var logFatalf = log.Fatalf
const RedirectReasonAdminInitTimeout string = "AdminInitTimeout"
type Monitor struct {
timeout time.Duration
datastore dataservices.DataStore
shutdownCtx context.Context
cancellationFunc context.CancelFunc
mu sync.Mutex
adminInitDisabled bool
timeout time.Duration
datastore dataservices.DataStore
shutdownCtx context.Context
cancellationFunc context.CancelFunc
}
// New creates a monitor that when started will wait for the timeout duration and then sends the timeout signal to disable the application
// New creates a monitor that when started will wait for the timeout duration and then shutdown the application unless it has been initialized.
func New(timeout time.Duration, datastore dataservices.DataStore, shutdownCtx context.Context) *Monitor {
return &Monitor{
timeout: timeout,
datastore: datastore,
shutdownCtx: shutdownCtx,
adminInitDisabled: false,
timeout: timeout,
datastore: datastore,
shutdownCtx: shutdownCtx,
}
}
// Starts starts the monitor. Active monitor could be stopped or shuttted down by cancelling the shutdown context.
func (m *Monitor) Start() {
m.mu.Lock()
defer m.mu.Unlock()
if m.cancellationFunc != nil {
return
}
cancellationCtx, cancellationFunc := context.WithCancel(context.Background())
m.cancellationFunc = cancellationFunc
@@ -57,11 +41,7 @@ func (m *Monitor) Start() {
logFatalf("%s", err)
}
if !initialized {
log.Println("[INFO] [internal,init] The Portainer instance timed out for security purposes. To re-enable your Portainer instance, you will need to restart Portainer")
m.mu.Lock()
defer m.mu.Unlock()
m.adminInitDisabled = true
return
logFatalf("[FATAL] [internal,init] No administrator account was created in %f mins. Shutting down the Portainer instance for security reasons", m.timeout.Minutes())
}
case <-cancellationCtx.Done():
log.Println("[DEBUG] [internal,init] [message: canceling initialization monitor]")
@@ -73,9 +53,6 @@ func (m *Monitor) Start() {
// Stop stops monitor. Safe to call even if monitor wasn't started.
func (m *Monitor) Stop() {
m.mu.Lock()
defer m.mu.Unlock()
if m.cancellationFunc == nil {
return
}
@@ -91,25 +68,3 @@ func (m *Monitor) WasInitialized() (bool, error) {
}
return len(users) > 0, nil
}
func (m *Monitor) WasInstanceDisabled() bool {
m.mu.Lock()
defer m.mu.Unlock()
return m.adminInitDisabled
}
// WithRedirect checks whether administrator initialisation timeout. If so, it will return the error with redirect reason.
// Otherwise, it will pass through the request to next
func (m *Monitor) WithRedirect(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if m.WasInstanceDisabled() {
if strings.HasPrefix(r.RequestURI, "/api") && r.RequestURI != "/api/status" && r.RequestURI != "/api/settings/public" {
w.Header().Set("redirect-reason", RedirectReasonAdminInitTimeout)
httperror.WriteError(w, http.StatusSeeOther, "Administrator initialization timeout", nil)
return
}
}
next.ServeHTTP(w, r)
})
}

View File

@@ -21,18 +21,6 @@ func Test_stopCouldBeCalledMultipleTimes(t *testing.T) {
monitor.Stop()
}
func Test_startOrStopCouldBeCalledMultipleTimesConcurrently(t *testing.T) {
monitor := New(1*time.Minute, nil, context.Background())
go monitor.Start()
monitor.Start()
go monitor.Stop()
monitor.Stop()
time.Sleep(2 * time.Second)
}
func Test_canStopStartedMonitor(t *testing.T) {
monitor := New(1*time.Minute, nil, context.Background())
monitor.Start()
@@ -42,13 +30,21 @@ func Test_canStopStartedMonitor(t *testing.T) {
assert.Nil(t, monitor.cancellationFunc, "cancellation function should absent in stopped monitor")
}
func Test_start_shouldDisableInstanceAfterTimeout_ifNotInitialized(t *testing.T) {
func Test_start_shouldFatalAfterTimeout_ifNotInitialized(t *testing.T) {
timeout := 10 * time.Millisecond
datastore := i.NewDatastore(i.WithUsers([]portainer.User{}))
var fataled bool
origLogFatalf := logFatalf
logFatalf = func(s string, v ...interface{}) { fataled = true }
defer func() {
logFatalf = origLogFatalf
}()
monitor := New(timeout, datastore, context.Background())
monitor.Start()
<-time.After(2 * timeout)
<-time.After(20 * timeout)
assert.True(t, monitor.WasInstanceDisabled(), "monitor should have been timeout and instance is disabled")
assert.True(t, fataled, "monitor should been timeout and fatal")
}

View File

@@ -50,15 +50,4 @@ Instead, it acts as a reverse-proxy to the Docker HTTP API. This means that you
To do so, you can use the `/endpoints/{id}/docker` Portainer API environment(endpoint) (which is not documented below due to Swagger limitations). This environment(endpoint) has a restricted access policy so you still need to be authenticated to be able to query this environment(endpoint). Any query on this environment(endpoint) will be proxied to the Docker API of the associated environment(endpoint) (requests and responses objects are the same as documented in the Docker API).
# Private Registry
Using private registry, you will need to pass a based64 encoded JSON string {"registryId":\<registryID value\>} inside the Request Header. The parameter name is "X-Registry-Auth".
\<registryID value\> - The registry ID where the repository was created.
Example:
```
eyJyZWdpc3RyeUlkIjoxfQ==
```
**NOTE**: You can find more information on how to query the Docker API in the [Docker official documentation](https://docs.docker.com/engine/api/v1.30/) as well as in [this Portainer example](https://documentation.portainer.io/api/api-examples/).

View File

@@ -20,7 +20,7 @@ func Test_SatisfiesAPIKeyServiceInterface(t *testing.T) {
func Test_GenerateApiKey(t *testing.T) {
is := assert.New(t)
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
service := NewAPIKeyService(store.APIKeyRepository(), store.User())
@@ -74,7 +74,7 @@ func Test_GenerateApiKey(t *testing.T) {
func Test_GetAPIKey(t *testing.T) {
is := assert.New(t)
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
service := NewAPIKeyService(store.APIKeyRepository(), store.User())
@@ -94,7 +94,7 @@ func Test_GetAPIKey(t *testing.T) {
func Test_GetAPIKeys(t *testing.T) {
is := assert.New(t)
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
service := NewAPIKeyService(store.APIKeyRepository(), store.User())
@@ -115,7 +115,7 @@ func Test_GetAPIKeys(t *testing.T) {
func Test_GetDigestUserAndKey(t *testing.T) {
is := assert.New(t)
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
service := NewAPIKeyService(store.APIKeyRepository(), store.User())
@@ -151,7 +151,7 @@ func Test_GetDigestUserAndKey(t *testing.T) {
func Test_UpdateAPIKey(t *testing.T) {
is := assert.New(t)
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
service := NewAPIKeyService(store.APIKeyRepository(), store.User())
@@ -199,7 +199,7 @@ func Test_UpdateAPIKey(t *testing.T) {
func Test_DeleteAPIKey(t *testing.T) {
is := assert.New(t)
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
service := NewAPIKeyService(store.APIKeyRepository(), store.User())
@@ -240,7 +240,7 @@ func Test_DeleteAPIKey(t *testing.T) {
func Test_InvalidateUserKeyCache(t *testing.T) {
is := assert.New(t)
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
service := NewAPIKeyService(store.APIKeyRepository(), store.User())

View File

@@ -80,7 +80,8 @@ func CreateBackupArchive(password string, gate *offlinegate.OfflineGate, datasto
}
func backupDb(backupDirPath string, datastore dataservices.DataStore) error {
backupWriter, err := os.Create(filepath.Join(backupDirPath, "portainer.db"))
dbFileName := datastore.Connection().GetDatabaseFileName()
backupWriter, err := os.Create(filepath.Join(backupDirPath, dbFileName))
if err != nil {
return err
}

View File

@@ -16,7 +16,7 @@ import (
"github.com/portainer/portainer/api/http/offlinegate"
)
var filesToRestore = append(filesToBackup, "portainer.db")
var filesToRestore = filesToBackup
// Restores system state from backup archive, will trigger system shutdown, when finished.
func RestoreArchive(archive io.Reader, password string, filestorePath string, gate *offlinegate.OfflineGate, datastore dataservices.DataStore, shutdownTrigger context.CancelFunc) error {

View File

@@ -1,13 +1,14 @@
package chisel
import (
"strconv"
portainer "github.com/portainer/portainer/api"
)
// AddEdgeJob register an EdgeJob inside the tunnel details associated to an environment(endpoint).
func (service *Service) AddEdgeJob(endpointID portainer.EndpointID, edgeJob *portainer.EdgeJob) {
service.mu.Lock()
tunnel := service.getTunnelDetails(endpointID)
tunnel := service.GetTunnelDetails(endpointID)
existingJobIndex := -1
for idx, existingJob := range tunnel.Jobs {
@@ -23,25 +24,24 @@ func (service *Service) AddEdgeJob(endpointID portainer.EndpointID, edgeJob *por
tunnel.Jobs[existingJobIndex] = *edgeJob
}
service.mu.Unlock()
key := strconv.Itoa(int(endpointID))
service.tunnelDetailsMap.Set(key, tunnel)
}
// RemoveEdgeJob will remove the specified Edge job from each tunnel it was registered with.
func (service *Service) RemoveEdgeJob(edgeJobID portainer.EdgeJobID) {
service.mu.Lock()
for item := range service.tunnelDetailsMap.IterBuffered() {
tunnelDetails := item.Val.(*portainer.TunnelDetails)
for _, tunnel := range service.tunnelDetailsMap {
// Filter in-place
n := 0
for _, edgeJob := range tunnel.Jobs {
if edgeJob.ID != edgeJobID {
tunnel.Jobs[n] = edgeJob
n++
updatedJobs := make([]portainer.EdgeJob, 0)
for _, edgeJob := range tunnelDetails.Jobs {
if edgeJob.ID == edgeJobID {
continue
}
updatedJobs = append(updatedJobs, edgeJob)
}
tunnel.Jobs = tunnel.Jobs[:n]
tunnelDetails.Jobs = updatedJobs
service.tunnelDetailsMap.Set(item.Key, tunnelDetails)
}
service.mu.Unlock()
}

View File

@@ -3,16 +3,17 @@ package chisel
import (
"context"
"fmt"
"github.com/portainer/portainer/api/http/proxy"
"log"
"net/http"
"sync"
"strconv"
"time"
"github.com/dchest/uniuri"
chserver "github.com/jpillora/chisel/server"
cmap "github.com/orcaman/concurrent-map"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/http/proxy"
)
const (
@@ -27,19 +28,18 @@ const (
type Service struct {
serverFingerprint string
serverPort string
tunnelDetailsMap map[portainer.EndpointID]*portainer.TunnelDetails
tunnelDetailsMap cmap.ConcurrentMap
dataStore dataservices.DataStore
snapshotService portainer.SnapshotService
chiselServer *chserver.Server
shutdownCtx context.Context
ProxyManager *proxy.Manager
mu sync.Mutex
}
// NewService returns a pointer to a new instance of Service
func NewService(dataStore dataservices.DataStore, shutdownCtx context.Context) *Service {
return &Service{
tunnelDetailsMap: make(map[portainer.EndpointID]*portainer.TunnelDetails),
tunnelDetailsMap: cmap.New(),
dataStore: dataStore,
shutdownCtx: shutdownCtx,
}
@@ -58,7 +58,11 @@ func (service *Service) pingAgent(endpointID portainer.EndpointID) error {
Timeout: 3 * time.Second,
}
_, err = httpClient.Do(req)
return err
if err != nil {
return err
}
return nil
}
// KeepTunnelAlive keeps the tunnel of the given environment for maxAlive duration, or until ctx is done
@@ -181,37 +185,42 @@ func (service *Service) startTunnelVerificationLoop() {
}
func (service *Service) checkTunnels() {
tunnels := make(map[portainer.EndpointID]portainer.TunnelDetails)
for item := range service.tunnelDetailsMap.IterBuffered() {
tunnel := item.Val.(*portainer.TunnelDetails)
service.mu.Lock()
for key, tunnel := range service.tunnelDetailsMap {
tunnels[key] = *tunnel
}
service.mu.Unlock()
for endpointID, tunnel := range tunnels {
if tunnel.LastActivity.IsZero() || tunnel.Status == portainer.EdgeAgentIdle {
continue
}
elapsed := time.Since(tunnel.LastActivity)
log.Printf("[DEBUG] [chisel,monitoring] [endpoint_id: %d] [status: %s] [status_time_seconds: %f] [message: environment tunnel monitoring]", endpointID, tunnel.Status, elapsed.Seconds())
log.Printf("[DEBUG] [chisel,monitoring] [endpoint_id: %s] [status: %s] [status_time_seconds: %f] [message: environment tunnel monitoring]", item.Key, tunnel.Status, elapsed.Seconds())
if tunnel.Status == portainer.EdgeAgentManagementRequired && elapsed.Seconds() < requiredTimeout.Seconds() {
continue
} else if tunnel.Status == portainer.EdgeAgentManagementRequired && elapsed.Seconds() > requiredTimeout.Seconds() {
log.Printf("[DEBUG] [chisel,monitoring] [endpoint_id: %d] [status: %s] [status_time_seconds: %f] [timeout_seconds: %f] [message: REQUIRED state timeout exceeded]", endpointID, tunnel.Status, elapsed.Seconds(), requiredTimeout.Seconds())
log.Printf("[DEBUG] [chisel,monitoring] [endpoint_id: %s] [status: %s] [status_time_seconds: %f] [timeout_seconds: %f] [message: REQUIRED state timeout exceeded]", item.Key, tunnel.Status, elapsed.Seconds(), requiredTimeout.Seconds())
}
if tunnel.Status == portainer.EdgeAgentActive && elapsed.Seconds() < activeTimeout.Seconds() {
continue
} else if tunnel.Status == portainer.EdgeAgentActive && elapsed.Seconds() > activeTimeout.Seconds() {
log.Printf("[DEBUG] [chisel,monitoring] [endpoint_id: %d] [status: %s] [status_time_seconds: %f] [timeout_seconds: %f] [message: ACTIVE state timeout exceeded]", endpointID, tunnel.Status, elapsed.Seconds(), activeTimeout.Seconds())
log.Printf("[DEBUG] [chisel,monitoring] [endpoint_id: %s] [status: %s] [status_time_seconds: %f] [timeout_seconds: %f] [message: ACTIVE state timeout exceeded]", item.Key, tunnel.Status, elapsed.Seconds(), activeTimeout.Seconds())
err := service.snapshotEnvironment(endpointID, tunnel.Port)
endpointID, err := strconv.Atoi(item.Key)
if err != nil {
log.Printf("[ERROR] [snapshot] Unable to snapshot Edge environment (id: %d): %s", endpointID, err)
log.Printf("[ERROR] [chisel,snapshot,conversion] Invalid environment identifier (id: %s): %s", item.Key, err)
}
err = service.snapshotEnvironment(portainer.EndpointID(endpointID), tunnel.Port)
if err != nil {
log.Printf("[ERROR] [snapshot] Unable to snapshot Edge environment (id: %s): %s", item.Key, err)
}
}
endpointID, err := strconv.Atoi(item.Key)
if err != nil {
log.Printf("[ERROR] [chisel,conversion] Invalid environment identifier (id: %s): %s", item.Key, err)
continue
}
service.SetTunnelStatusToIdle(portainer.EndpointID(endpointID))

View File

@@ -4,11 +4,13 @@ import (
"encoding/base64"
"fmt"
"math/rand"
"strconv"
"strings"
"time"
"github.com/dchest/uniuri"
"github.com/portainer/libcrypto"
"github.com/dchest/uniuri"
portainer "github.com/portainer/portainer/api"
)
@@ -17,13 +19,13 @@ const (
maxAvailablePort = 65535
)
// NOTE: it needs to be called with the lock acquired
// getUnusedPort is used to generate an unused random port in the dynamic port range.
// Dynamic ports (also called private ports) are 49152 to 65535.
func (service *Service) getUnusedPort() int {
port := randomInt(minAvailablePort, maxAvailablePort)
for _, tunnel := range service.tunnelDetailsMap {
for item := range service.tunnelDetailsMap.IterBuffered() {
tunnel := item.Val.(*portainer.TunnelDetails)
if tunnel.Port == port {
return service.getUnusedPort()
}
@@ -36,32 +38,26 @@ func randomInt(min, max int) int {
return min + rand.Intn(max-min)
}
// NOTE: it needs to be called with the lock acquired
func (service *Service) getTunnelDetails(endpointID portainer.EndpointID) *portainer.TunnelDetails {
if tunnel, ok := service.tunnelDetailsMap[endpointID]; ok {
return tunnel
}
tunnel := &portainer.TunnelDetails{
Status: portainer.EdgeAgentIdle,
}
service.tunnelDetailsMap[endpointID] = tunnel
return tunnel
}
// GetTunnelDetails returns information about the tunnel associated to an environment(endpoint).
func (service *Service) GetTunnelDetails(endpointID portainer.EndpointID) portainer.TunnelDetails {
service.mu.Lock()
defer service.mu.Unlock()
func (service *Service) GetTunnelDetails(endpointID portainer.EndpointID) *portainer.TunnelDetails {
key := strconv.Itoa(int(endpointID))
return *service.getTunnelDetails(endpointID)
if item, ok := service.tunnelDetailsMap.Get(key); ok {
tunnelDetails := item.(*portainer.TunnelDetails)
return tunnelDetails
}
jobs := make([]portainer.EdgeJob, 0)
return &portainer.TunnelDetails{
Status: portainer.EdgeAgentIdle,
Port: 0,
Jobs: jobs,
Credentials: "",
}
}
// GetActiveTunnel retrieves an active tunnel which allows communicating with edge agent
func (service *Service) GetActiveTunnel(endpoint *portainer.Endpoint) (portainer.TunnelDetails, error) {
func (service *Service) GetActiveTunnel(endpoint *portainer.Endpoint) (*portainer.TunnelDetails, error) {
tunnel := service.GetTunnelDetails(endpoint.ID)
if tunnel.Status == portainer.EdgeAgentActive {
@@ -72,13 +68,13 @@ func (service *Service) GetActiveTunnel(endpoint *portainer.Endpoint) (portainer
if tunnel.Status == portainer.EdgeAgentIdle || tunnel.Status == portainer.EdgeAgentManagementRequired {
err := service.SetTunnelStatusToRequired(endpoint.ID)
if err != nil {
return portainer.TunnelDetails{}, fmt.Errorf("failed opening tunnel to endpoint: %w", err)
return nil, fmt.Errorf("failed opening tunnel to endpoint: %w", err)
}
if endpoint.EdgeCheckinInterval == 0 {
settings, err := service.dataStore.Settings().Settings()
if err != nil {
return portainer.TunnelDetails{}, fmt.Errorf("failed fetching settings from db: %w", err)
return nil, fmt.Errorf("failed fetching settings from db: %w", err)
}
endpoint.EdgeCheckinInterval = settings.EdgeAgentCheckinInterval
@@ -87,27 +83,29 @@ func (service *Service) GetActiveTunnel(endpoint *portainer.Endpoint) (portainer
time.Sleep(2 * time.Duration(endpoint.EdgeCheckinInterval) * time.Second)
}
return service.GetTunnelDetails(endpoint.ID), nil
tunnel = service.GetTunnelDetails(endpoint.ID)
return tunnel, nil
}
// SetTunnelStatusToActive update the status of the tunnel associated to the specified environment(endpoint).
// It sets the status to ACTIVE.
func (service *Service) SetTunnelStatusToActive(endpointID portainer.EndpointID) {
service.mu.Lock()
tunnel := service.getTunnelDetails(endpointID)
tunnel := service.GetTunnelDetails(endpointID)
tunnel.Status = portainer.EdgeAgentActive
tunnel.Credentials = ""
tunnel.LastActivity = time.Now()
service.mu.Unlock()
key := strconv.Itoa(int(endpointID))
service.tunnelDetailsMap.Set(key, tunnel)
}
// SetTunnelStatusToIdle update the status of the tunnel associated to the specified environment(endpoint).
// It sets the status to IDLE.
// It removes any existing credentials associated to the tunnel.
func (service *Service) SetTunnelStatusToIdle(endpointID portainer.EndpointID) {
service.mu.Lock()
tunnel := service.GetTunnelDetails(endpointID)
tunnel := service.getTunnelDetails(endpointID)
tunnel.Status = portainer.EdgeAgentIdle
tunnel.Port = 0
tunnel.LastActivity = time.Now()
@@ -118,9 +116,10 @@ func (service *Service) SetTunnelStatusToIdle(endpointID portainer.EndpointID) {
service.chiselServer.DeleteUser(strings.Split(credentials, ":")[0])
}
service.ProxyManager.DeleteEndpointProxy(endpointID)
key := strconv.Itoa(int(endpointID))
service.tunnelDetailsMap.Set(key, tunnel)
service.mu.Unlock()
service.ProxyManager.DeleteEndpointProxy(endpointID)
}
// SetTunnelStatusToRequired update the status of the tunnel associated to the specified environment(endpoint).
@@ -129,10 +128,7 @@ func (service *Service) SetTunnelStatusToIdle(endpointID portainer.EndpointID) {
// and generate temporary credentials that can be used to establish a reverse tunnel on that port.
// Credentials are encrypted using the Edge ID associated to the environment(endpoint).
func (service *Service) SetTunnelStatusToRequired(endpointID portainer.EndpointID) error {
tunnel := service.getTunnelDetails(endpointID)
service.mu.Lock()
defer service.mu.Unlock()
tunnel := service.GetTunnelDetails(endpointID)
if tunnel.Port == 0 {
endpoint, err := service.dataStore.Endpoint().Endpoint(endpointID)
@@ -156,6 +152,9 @@ func (service *Service) SetTunnelStatusToRequired(endpointID portainer.EndpointI
return err
}
tunnel.Credentials = credentials
key := strconv.Itoa(int(endpointID))
service.tunnelDetailsMap.Set(key, tunnel)
}
return nil

View File

@@ -35,7 +35,6 @@ func (*Service) ParseFlags(version string) (*portainer.CLIFlags, error) {
TunnelPort: kingpin.Flag("tunnel-port", "Port to serve the tunnel server").Default(defaultTunnelServerPort).String(),
Assets: kingpin.Flag("assets", "Path to the assets").Default(defaultAssetsDirectory).Short('a').String(),
Data: kingpin.Flag("data", "Path to the folder where the data is stored").Default(defaultDataDirectory).Short('d').String(),
DemoEnvironment: kingpin.Flag("demo", "Demo environment").Bool(),
EndpointURL: kingpin.Flag("host", "Environment URL").Short('H').String(),
FeatureFlags: BoolPairs(kingpin.Flag("feat", "List of feature flags").Hidden()),
EnableEdgeComputeFeatures: kingpin.Flag("edge-compute", "Enable Edge Compute features").Bool(),
@@ -52,7 +51,7 @@ func (*Service) ParseFlags(version string) (*portainer.CLIFlags, error) {
SSLKey: kingpin.Flag("sslkey", "Path to the SSL key used to secure the Portainer instance").String(),
Rollback: kingpin.Flag("rollback", "Rollback the database store to the previous version").Bool(),
SnapshotInterval: kingpin.Flag("snapshot-interval", "Duration between each environment snapshot job").String(),
AdminPassword: kingpin.Flag("admin-password", "Set admin password with provided hash").String(),
AdminPassword: kingpin.Flag("admin-password", "Hashed admin password").String(),
AdminPasswordFile: kingpin.Flag("admin-password-file", "Path to the file containing the password for the admin user").String(),
Labels: pairs(kingpin.Flag("hide-label", "Hide containers with a specific label in the UI").Short('l')),
Logo: kingpin.Flag("logo", "URL for the logo displayed in the UI").String(),

View File

@@ -18,6 +18,8 @@ const (
defaultHTTPDisabled = "false"
defaultHTTPEnabled = "false"
defaultSSL = "false"
defaultSSLCertPath = "/certs/portainer.crt"
defaultSSLKeyPath = "/certs/portainer.key"
defaultBaseURL = "/"
defaultSecretKeyName = "portainer"
)

View File

@@ -15,6 +15,8 @@ const (
defaultHTTPDisabled = "false"
defaultHTTPEnabled = "false"
defaultSSL = "false"
defaultSSLCertPath = "C:\\certs\\portainer.crt"
defaultSSLKeyPath = "C:\\certs\\portainer.key"
defaultSnapshotInterval = "5m"
defaultBaseURL = "/"
defaultSecretKeyName = "portainer"

View File

@@ -1,19 +1,41 @@
package main
import (
"fmt"
"log"
"strings"
"github.com/sirupsen/logrus"
)
type portainerFormatter struct {
logrus.TextFormatter
}
func (f *portainerFormatter) Format(entry *logrus.Entry) ([]byte, error) {
var levelColor int
switch entry.Level {
case logrus.DebugLevel, logrus.TraceLevel:
levelColor = 31 // gray
case logrus.WarnLevel:
levelColor = 33 // yellow
case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
levelColor = 31 // red
default:
levelColor = 36 // blue
}
return []byte(fmt.Sprintf("\x1b[%dm%s\x1b[0m %s %s\n", levelColor, strings.ToUpper(entry.Level.String()), entry.Time.Format(f.TimestampFormat), entry.Message)), nil
}
func configureLogger() {
logger := logrus.New() // logger is to implicitly substitute stdlib's log
log.SetOutput(logger.Writer())
formatter := &logrus.TextFormatter{DisableTimestamp: false, DisableLevelTruncation: true}
formatter := &logrus.TextFormatter{DisableTimestamp: true, DisableLevelTruncation: true}
formatterLogrus := &portainerFormatter{logrus.TextFormatter{DisableTimestamp: false, DisableLevelTruncation: true, TimestampFormat: "2006/01/02 15:04:05", FullTimestamp: true}}
logger.SetFormatter(formatter)
logrus.SetFormatter(formatter)
logrus.SetFormatter(formatterLogrus)
logger.SetLevel(logrus.DebugLevel)
logrus.SetLevel(logrus.DebugLevel)

View File

@@ -4,12 +4,10 @@ import (
"context"
"crypto/sha256"
"fmt"
"log"
"os"
"path"
"strconv"
"strings"
"time"
"github.com/sirupsen/logrus"
@@ -23,7 +21,6 @@ import (
"github.com/portainer/portainer/api/database/boltdb"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/datastore"
"github.com/portainer/portainer/api/demo"
"github.com/portainer/portainer/api/docker"
"github.com/portainer/portainer/api/exec"
"github.com/portainer/portainer/api/filesystem"
@@ -108,11 +105,6 @@ func initDataStore(flags *portainer.CLIFlags, secretKey []byte, fileService port
if isNew {
// from MigrateData
store.VersionService.StoreDBVersion(portainer.DBVersion)
err := updateSettingsFromFlags(store, flags)
if err != nil {
logrus.Fatalf("Failed updating settings from flags: %v", err)
}
} else {
storedVersion, err := store.VersionService.DBVersion()
if err != nil {
@@ -128,24 +120,15 @@ func initDataStore(flags *portainer.CLIFlags, secretKey []byte, fileService port
err = updateSettingsFromFlags(store, flags)
if err != nil {
log.Fatalf("Failed updating settings from flags: %v", err)
logrus.Fatalf("Failed updating settings from flags: %v", err)
}
// this is for the db restore functionality - needs more tests.
go func() {
<-shutdownCtx.Done()
defer connection.Close()
exportFilename := path.Join(*flags.Data, fmt.Sprintf("export-%d.json", time.Now().Unix()))
err := store.Export(exportFilename)
if err != nil {
logrus.WithError(err).Debugf("Failed to export to %s", exportFilename)
} else {
logrus.Debugf("exported to %s", exportFilename)
}
connection.Close()
}()
return store
}
@@ -158,14 +141,7 @@ func initComposeStackManager(assetsPath string, configPath string, reverseTunnel
return composeWrapper
}
func initSwarmStackManager(
assetsPath string,
configPath string,
signatureService portainer.DigitalSignatureService,
fileService portainer.FileService,
reverseTunnelService portainer.ReverseTunnelService,
dataStore dataservices.DataStore,
) (portainer.SwarmStackManager, error) {
func initSwarmStackManager(assetsPath string, configPath string, signatureService portainer.DigitalSignatureService, fileService portainer.FileService, reverseTunnelService portainer.ReverseTunnelService, dataStore dataservices.DataStore) (portainer.SwarmStackManager, error) {
return exec.NewSwarmStackManager(assetsPath, configPath, signatureService, fileService, reverseTunnelService, dataStore)
}
@@ -209,7 +185,7 @@ func initGitService() portainer.GitService {
return git.NewService()
}
func initSSLService(addr, certPath, keyPath string, fileService portainer.FileService, dataStore dataservices.DataStore, shutdownTrigger context.CancelFunc) (*ssl.Service, error) {
func initSSLService(addr, dataPath, certPath, keyPath string, fileService portainer.FileService, dataStore dataservices.DataStore, shutdownTrigger context.CancelFunc) (*ssl.Service, error) {
slices := strings.Split(addr, ":")
host := slices[0]
if host == "" {
@@ -279,12 +255,6 @@ func updateSettingsFromFlags(dataStore dataservices.DataStore, flags *portainer.
settings.BlackListedLabels = *flags.Labels
}
if agentKey, ok := os.LookupEnv("AGENT_SECRET"); ok {
settings.AgentSecret = agentKey
} else {
settings.AgentSecret = ""
}
err = dataStore.Settings().UpdateSettings(settings)
if err != nil {
return err
@@ -405,6 +375,7 @@ func createTLSSecuredEndpoint(flags *portainer.CLIFlags, dataStore dataservices.
TLSConfig: tlsConfiguration,
UserAccessPolicies: portainer.UserAccessPolicies{},
TeamAccessPolicies: portainer.TeamAccessPolicies{},
Extensions: []portainer.EndpointExtension{},
TagIDs: []portainer.TagID{},
Status: portainer.EndpointStatusUp,
Snapshots: []portainer.DockerSnapshot{},
@@ -466,6 +437,7 @@ func createUnsecuredEndpoint(endpointURL string, dataStore dataservices.DataStor
TLSConfig: portainer.TLSConfiguration{},
UserAccessPolicies: portainer.UserAccessPolicies{},
TeamAccessPolicies: portainer.TeamAccessPolicies{},
Extensions: []portainer.EndpointExtension{},
TagIDs: []portainer.TagID{},
Status: portainer.EndpointStatusUp,
Snapshots: []portainer.DockerSnapshot{},
@@ -573,10 +545,9 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
openAMTService := openamt.NewService()
cryptoService := initCryptoService()
digitalSignatureService := initDigitalSignatureService()
sslService, err := initSSLService(*flags.AddrHTTPS, *flags.SSLCert, *flags.SSLKey, fileService, dataStore, shutdownTrigger)
sslService, err := initSSLService(*flags.AddrHTTPS, *flags.Data, *flags.SSLCert, *flags.SSLKey, fileService, dataStore, shutdownTrigger)
if err != nil {
logrus.Fatal(err)
}
@@ -607,9 +578,9 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
kubernetesTokenCacheManager := kubeproxy.NewTokenCacheManager()
kubeClusterAccessService := kubernetes.NewKubeClusterAccessService(*flags.BaseURL, *flags.AddrHTTPS, sslSettings.CertPath)
kubeConfigService := kubernetes.NewKubeConfigCAService(*flags.AddrHTTPS, sslSettings.CertPath)
proxyManager := proxy.NewManager(dataStore, digitalSignatureService, reverseTunnelService, dockerClientFactory, kubernetesClientFactory, kubernetesTokenCacheManager, gitService)
proxyManager := proxy.NewManager(dataStore, digitalSignatureService, reverseTunnelService, dockerClientFactory, kubernetesClientFactory, kubernetesTokenCacheManager)
reverseTunnelService.ProxyManager = proxyManager
@@ -636,14 +607,6 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
applicationStatus := initStatus(instanceID)
demoService := demo.NewService()
if *flags.DemoEnvironment {
err := demoService.Init(dataStore, cryptoService)
if err != nil {
log.Fatalf("failed initializing demo environment: %v", err)
}
}
err = initEndpoint(flags, dataStore, snapshotService)
if err != nil {
logrus.Fatalf("Failed initializing environment: %v", err)
@@ -722,7 +685,7 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
OpenAMTService: openAMTService,
ProxyManager: proxyManager,
KubernetesTokenCacheManager: kubernetesTokenCacheManager,
KubeClusterAccessService: kubeClusterAccessService,
KubeConfigService: kubeConfigService,
SignatureService: digitalSignatureService,
SnapshotService: snapshotService,
SSLService: sslService,
@@ -732,7 +695,7 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server {
ShutdownCtx: shutdownCtx,
ShutdownTrigger: shutdownTrigger,
StackDeployer: stackDeployer,
DemoService: demoService,
BaseURL: *flags.BaseURL,
}
}

View File

@@ -21,7 +21,7 @@ func (m mockKingpinSetting) SetValue(value kingpin.Value) {
func Test_enableFeaturesFromFlags(t *testing.T) {
is := assert.New(t)
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
tests := []struct {
@@ -76,7 +76,7 @@ func Test_optionalFeature(t *testing.T) {
is := assert.New(t)
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
// Enable the test feature

View File

@@ -29,12 +29,8 @@ type Connection interface {
GetNextIdentifier(bucketName string) int
CreateObject(bucketName string, fn func(uint64) (int, interface{})) error
CreateObjectWithId(bucketName string, id int, obj interface{}) error
CreateObjectWithStringId(bucketName string, id []byte, obj interface{}) error
CreateObjectWithSetSequence(bucketName string, id int, obj interface{}) error
GetAll(bucketName string, obj interface{}, append func(o interface{}) (interface{}, error)) error
GetAllWithJsoniter(bucketName string, obj interface{}, append func(o interface{}) (interface{}, error)) error
ConvertToKey(v int) []byte
BackupMetadata() (map[string]interface{}, error)
RestoreMetadata(s map[string]interface{}) error
}

View File

@@ -9,11 +9,11 @@ type Service struct{}
// Hash hashes a string using the bcrypt algorithm
func (*Service) Hash(data string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(data), bcrypt.DefaultCost)
hash, err := bcrypt.GenerateFromPassword([]byte(data), bcrypt.DefaultCost)
if err != nil {
return "", err
return "", nil
}
return string(bytes), err
return string(hash), nil
}
// CompareHashAndData compares a hash to clear data and returns an error if the comparison fails.

View File

@@ -1,53 +0,0 @@
package crypto
import (
"testing"
)
func TestService_Hash(t *testing.T) {
var s = &Service{}
type args struct {
hash string
data string
}
tests := []struct {
name string
args args
expect bool
}{
{
name: "Empty",
args: args{
hash: "",
data: "",
},
expect: false,
},
{
name: "Matching",
args: args{
hash: "$2a$10$6BFGd94oYx8k0bFNO6f33uPUpcpAJyg8UVX.akLe9EthF/ZBTXqcy",
data: "Passw0rd!",
},
expect: true,
},
{
name: "Not matching",
args: args{
hash: "$2a$10$ltKrUZ7492xyutHOb0/XweevU4jyw7QO66rP32jTVOMb3EX3JxA/a",
data: "Passw0rd!",
},
expect: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := s.CompareHashAndData(tt.args.hash, tt.args.data)
if (err != nil) == tt.expect {
t.Errorf("Service.CompareHashAndData() = %v", err)
}
})
}
}

View File

@@ -10,9 +10,9 @@ import (
"path"
"time"
"github.com/boltdb/bolt"
dserrors "github.com/portainer/portainer/api/dataservices/errors"
"github.com/sirupsen/logrus"
bolt "go.etcd.io/bbolt"
)
const (
@@ -161,7 +161,7 @@ func (connection *DbConnection) ExportRaw(filename string) error {
return fmt.Errorf("stat on %s failed: %s", databasePath, err)
}
b, err := connection.ExportJson(databasePath, true)
b, err := connection.exportJson(databasePath)
if err != nil {
return err
}
@@ -181,7 +181,10 @@ func (connection *DbConnection) ConvertToKey(v int) []byte {
func (connection *DbConnection) SetServiceName(bucketName string) error {
return connection.Batch(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(bucketName))
return err
if err != nil {
return err
}
return nil
})
}
@@ -311,19 +314,6 @@ func (connection *DbConnection) CreateObjectWithId(bucketName string, id int, ob
})
}
// CreateObjectWithStringId creates a new object in the bucket, using the specified id
func (connection *DbConnection) CreateObjectWithStringId(bucketName string, id []byte, obj interface{}) error {
return connection.Batch(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(bucketName))
data, err := connection.MarshalObject(obj)
if err != nil {
return err
}
return bucket.Put(id, data)
})
}
// CreateObjectWithSetSequence creates a new object in the bucket, using the specified id, and sets the bucket sequence
// avoid this :)
func (connection *DbConnection) CreateObjectWithSetSequence(bucketName string, id int, obj interface{}) error {
@@ -386,43 +376,3 @@ func (connection *DbConnection) GetAllWithJsoniter(bucketName string, obj interf
})
return err
}
func (connection *DbConnection) BackupMetadata() (map[string]interface{}, error) {
buckets := map[string]interface{}{}
err := connection.View(func(tx *bolt.Tx) error {
err := tx.ForEach(func(name []byte, bucket *bolt.Bucket) error {
bucketName := string(name)
bucket = tx.Bucket([]byte(bucketName))
seqId := bucket.Sequence()
buckets[bucketName] = int(seqId)
return nil
})
return err
})
return buckets, err
}
func (connection *DbConnection) RestoreMetadata(s map[string]interface{}) error {
var err error
for bucketName, v := range s {
id, ok := v.(float64) // JSON ints are unmarshalled to interface as float64. See: https://pkg.go.dev/encoding/json#Decoder.Decode
if !ok {
logrus.Errorf("Failed to restore metadata to bucket %s, skipped", bucketName)
continue
}
err = connection.Batch(func(tx *bolt.Tx) error {
bucket, err := tx.CreateBucketIfNotExists([]byte(bucketName))
if err != nil {
return err
}
return bucket.SetSequence(uint64(id))
})
}
return err
}

View File

@@ -4,34 +4,13 @@ import (
"encoding/json"
"time"
"github.com/boltdb/bolt"
"github.com/sirupsen/logrus"
bolt "go.etcd.io/bbolt"
)
func backupMetadata(connection *bolt.DB) (map[string]interface{}, error) {
buckets := map[string]interface{}{}
err := connection.View(func(tx *bolt.Tx) error {
err := tx.ForEach(func(name []byte, bucket *bolt.Bucket) error {
bucketName := string(name)
bucket = tx.Bucket([]byte(bucketName))
seqId := bucket.Sequence()
buckets[bucketName] = int(seqId)
return nil
})
return err
})
return buckets, err
}
// ExportJSON creates a JSON representation from a DbConnection. You can include
// the database's metadata or ignore it. Ensure the database is closed before
// using this function
// inspired by github.com/konoui/boltdb-exporter (which has no license)
// but very much simplified, based on how we use boltdb
func (c *DbConnection) ExportJson(databasePath string, metadata bool) ([]byte, error) {
func (c *DbConnection) exportJson(databasePath string) ([]byte, error) {
logrus.WithField("databasePath", databasePath).Infof("exportJson")
connection, err := bolt.Open(databasePath, 0600, &bolt.Options{Timeout: 1 * time.Second, ReadOnly: true})
@@ -41,13 +20,6 @@ func (c *DbConnection) ExportJson(databasePath string, metadata bool) ([]byte, e
defer connection.Close()
backup := make(map[string]interface{})
if metadata {
meta, err := backupMetadata(connection)
if err != nil {
logrus.WithError(err).Errorf("Failed exporting metadata: %v", err)
}
backup["__metadata"] = meta
}
err = connection.View(func(tx *bolt.Tx) error {
err = tx.ForEach(func(name []byte, bucket *bolt.Bucket) error {
@@ -73,20 +45,15 @@ func (c *DbConnection) ExportJson(databasePath string, metadata bool) ([]byte, e
}
if bucketName == "version" {
backup[bucketName] = version
return nil
}
if len(list) > 0 {
if bucketName == "ssl" ||
bucketName == "settings" ||
bucketName == "tunnel_server" {
backup[bucketName] = nil
if len(list) > 0 {
backup[bucketName] = list[0]
}
backup[bucketName] = list[0]
return nil
}
backup[bucketName] = list
return nil
}
return nil

View File

@@ -10,7 +10,7 @@ import (
)
const (
jsonobject = `{"LogoURL":"","BlackListedLabels":[],"AuthenticationMethod":1,"InternalAuthSettings": {"RequiredPasswordLength": 12}"LDAPSettings":{"AnonymousMode":true,"ReaderDN":"","URL":"","TLSConfig":{"TLS":false,"TLSSkipVerify":false},"StartTLS":false,"SearchSettings":[{"BaseDN":"","Filter":"","UserNameAttribute":""}],"GroupSearchSettings":[{"GroupBaseDN":"","GroupFilter":"","GroupAttribute":""}],"AutoCreateUsers":true},"OAuthSettings":{"ClientID":"","AccessTokenURI":"","AuthorizationURI":"","ResourceURI":"","RedirectURI":"","UserIdentifier":"","Scopes":"","OAuthAutoCreateUsers":false,"DefaultTeamID":0,"SSO":true,"LogoutURI":"","KubeSecretKey":"j0zLVtY/lAWBk62ByyF0uP80SOXaitsABP0TTJX8MhI="},"OpenAMTConfiguration":{"Enabled":false,"MPSServer":"","MPSUser":"","MPSPassword":"","MPSToken":"","CertFileContent":"","CertFileName":"","CertFilePassword":"","DomainName":""},"FeatureFlagSettings":{},"SnapshotInterval":"5m","TemplatesURL":"https://raw.githubusercontent.com/portainer/templates/master/templates-2.0.json","EdgeAgentCheckinInterval":5,"EnableEdgeComputeFeatures":false,"UserSessionTimeout":"8h","KubeconfigExpiry":"0","EnableTelemetry":true,"HelmRepositoryURL":"https://charts.bitnami.com/bitnami","KubectlShellImage":"portainer/kubectl-shell","DisplayDonationHeader":false,"DisplayExternalContributors":false,"EnableHostManagementFeatures":false,"AllowVolumeBrowserForRegularUsers":false,"AllowBindMountsForRegularUsers":false,"AllowPrivilegedModeForRegularUsers":false,"AllowHostNamespaceForRegularUsers":false,"AllowStackManagementForRegularUsers":false,"AllowDeviceMappingForRegularUsers":false,"AllowContainerCapabilitiesForRegularUsers":false}`
jsonobject = `{"LogoURL":"","BlackListedLabels":[],"AuthenticationMethod":1,"LDAPSettings":{"AnonymousMode":true,"ReaderDN":"","URL":"","TLSConfig":{"TLS":false,"TLSSkipVerify":false},"StartTLS":false,"SearchSettings":[{"BaseDN":"","Filter":"","UserNameAttribute":""}],"GroupSearchSettings":[{"GroupBaseDN":"","GroupFilter":"","GroupAttribute":""}],"AutoCreateUsers":true},"OAuthSettings":{"ClientID":"","AccessTokenURI":"","AuthorizationURI":"","ResourceURI":"","RedirectURI":"","UserIdentifier":"","Scopes":"","OAuthAutoCreateUsers":false,"DefaultTeamID":0,"SSO":true,"LogoutURI":"","KubeSecretKey":"j0zLVtY/lAWBk62ByyF0uP80SOXaitsABP0TTJX8MhI="},"OpenAMTConfiguration":{"Enabled":false,"MPSServer":"","MPSUser":"","MPSPassword":"","MPSToken":"","CertFileContent":"","CertFileName":"","CertFilePassword":"","DomainName":""},"FeatureFlagSettings":{},"SnapshotInterval":"5m","TemplatesURL":"https://raw.githubusercontent.com/portainer/templates/master/templates-2.0.json","EdgeAgentCheckinInterval":5,"EnableEdgeComputeFeatures":false,"UserSessionTimeout":"8h","KubeconfigExpiry":"0","EnableTelemetry":true,"HelmRepositoryURL":"https://charts.bitnami.com/bitnami","KubectlShellImage":"portainer/kubectl-shell","DisplayDonationHeader":false,"DisplayExternalContributors":false,"EnableHostManagementFeatures":false,"AllowVolumeBrowserForRegularUsers":false,"AllowBindMountsForRegularUsers":false,"AllowPrivilegedModeForRegularUsers":false,"AllowHostNamespaceForRegularUsers":false,"AllowStackManagementForRegularUsers":false,"AllowDeviceMappingForRegularUsers":false,"AllowContainerCapabilitiesForRegularUsers":false}`
passphrase = "my secret key"
)

View File

@@ -67,14 +67,14 @@ func (service *Service) EdgeJob(ID portainer.EdgeJobID) (*portainer.EdgeJob, err
return &edgeJob, nil
}
// Create creates a new EdgeJob
func (service *Service) Create(ID portainer.EdgeJobID, edgeJob *portainer.EdgeJob) error {
edgeJob.ID = ID
return service.connection.CreateObjectWithId(
// CreateEdgeJob creates a new Edge job
func (service *Service) Create(edgeJob *portainer.EdgeJob) error {
return service.connection.CreateObject(
BucketName,
int(edgeJob.ID),
edgeJob,
func(id uint64) (int, interface{}) {
edgeJob.ID = portainer.EdgeJobID(id)
return int(edgeJob.ID), edgeJob
},
)
}

View File

@@ -2,7 +2,6 @@ package fdoprofile
import (
"fmt"
portainer "github.com/portainer/portainer/api"
"github.com/sirupsen/logrus"
)

View File

@@ -23,7 +23,7 @@ type (
BackupTo(w io.Writer) error
Export(filename string) (err error)
IsErrObjectNotFound(err error) bool
Connection() portainer.Connection
CustomTemplate() CustomTemplateService
EdgeGroup() EdgeGroupService
EdgeJob() EdgeJobService
@@ -74,7 +74,7 @@ type (
EdgeJobService interface {
EdgeJobs() ([]portainer.EdgeJob, error)
EdgeJob(ID portainer.EdgeJobID) (*portainer.EdgeJob, error)
Create(ID portainer.EdgeJobID, edgeJob *portainer.EdgeJob) error
Create(edgeJob *portainer.EdgeJob) error
UpdateEdgeJob(ID portainer.EdgeJobID, edgeJob *portainer.EdgeJob) error
DeleteEdgeJob(ID portainer.EdgeJobID) error
GetNextIdentifier() int

View File

@@ -29,7 +29,7 @@ func TestService_StackByWebhookID(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode. Normally takes ~1s to run.")
}
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
b := stackBuilder{t: t, store: store}
@@ -87,7 +87,7 @@ func Test_RefreshableStacks(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode. Normally takes ~1s to run.")
}
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
staticStack := portainer.Stack{ID: 1}

View File

@@ -10,7 +10,7 @@ import (
func Test_teamByName(t *testing.T) {
t.Run("When store is empty should return ErrObjectNotFound", func(t *testing.T) {
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
_, err := store.Team().TeamByName("name")
@@ -19,7 +19,7 @@ func Test_teamByName(t *testing.T) {
})
t.Run("When there is no object with the same name should return ErrObjectNotFound", func(t *testing.T) {
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
teamBuilder := teamBuilder{
@@ -35,7 +35,7 @@ func Test_teamByName(t *testing.T) {
})
t.Run("When there is an object with the same name should return the object", func(t *testing.T) {
_, store, teardown := datastore.MustNewTestStore(true, true)
_, store, teardown := datastore.MustNewTestStore(true)
defer teardown()
teamBuilder := teamBuilder{

View File

@@ -69,11 +69,6 @@ func getBackupRestoreOptions(backupDir string) *BackupOptions {
}
}
// Backup current database with default options
func (store *Store) Backup() (string, error) {
return store.backupWithOptions(nil)
}
func (store *Store) setupOptions(options *BackupOptions) *BackupOptions {
if options == nil {
options = &BackupOptions{}

View File

@@ -10,7 +10,7 @@ import (
)
func TestCreateBackupFolders(t *testing.T) {
_, store, teardown := MustNewTestStore(false, true)
_, store, teardown := MustNewTestStore(false)
defer teardown()
connection := store.GetConnection()
@@ -27,7 +27,7 @@ func TestCreateBackupFolders(t *testing.T) {
}
func TestStoreCreation(t *testing.T) {
_, store, teardown := MustNewTestStore(true, true)
_, store, teardown := MustNewTestStore(true)
defer teardown()
if store == nil {
@@ -40,7 +40,7 @@ func TestStoreCreation(t *testing.T) {
}
func TestBackup(t *testing.T) {
_, store, teardown := MustNewTestStore(true, true)
_, store, teardown := MustNewTestStore(true)
connection := store.GetConnection()
defer teardown()
@@ -67,7 +67,7 @@ func TestBackup(t *testing.T) {
}
func TestRemoveWithOptions(t *testing.T) {
_, store, teardown := MustNewTestStore(true, true)
_, store, teardown := MustNewTestStore(true)
defer teardown()
t.Run("successfully removes file if existent", func(t *testing.T) {
@@ -86,7 +86,7 @@ func TestRemoveWithOptions(t *testing.T) {
err = store.removeWithOptions(options)
if err != nil {
t.Errorf("RemoveWithOptions should successfully remove file; err=%v", err)
t.Errorf("RemoveWithOptions should successfully remove file; err=%w", err)
}
if isFileExist(f.Name()) {

View File

@@ -103,6 +103,10 @@ func (store *Store) IsErrObjectNotFound(e error) bool {
return e == portainerErrors.ErrObjectNotFound
}
func (store *Store) Connection() portainer.Connection {
return store.connection
}
func (store *Store) Rollback(force bool) error {
return store.connectionRollback(force)
}

View File

@@ -27,7 +27,7 @@ const (
// TestStoreFull an eventually comprehensive set of tests for the Store.
// The idea is what we write to the store, we should read back.
func TestStoreFull(t *testing.T) {
_, store, teardown := MustNewTestStore(true, true)
_, store, teardown := MustNewTestStore(true)
defer teardown()
testCases := map[string]func(t *testing.T){
@@ -96,6 +96,7 @@ func newEndpoint(endpointType portainer.EndpointType, id portainer.EndpointID, n
},
UserAccessPolicies: portainer.UserAccessPolicies{},
TeamAccessPolicies: portainer.TeamAccessPolicies{},
Extensions: []portainer.EndpointExtension{},
TagIDs: []portainer.TagID{},
Status: portainer.EndpointStatusUp,
Snapshots: []portainer.DockerSnapshot{},

View File

@@ -22,18 +22,23 @@ func (store *Store) Init() error {
return err
}
return store.checkOrCreateDefaultData()
err = store.checkOrCreateDefaultData()
if err != nil {
return err
}
return nil
}
func (store *Store) checkOrCreateInstanceID() error {
_, err := store.VersionService.InstanceID()
instanceID, err := store.VersionService.InstanceID()
if store.IsErrObjectNotFound(err) {
uid, err := uuid.NewV4()
if err != nil {
return err
}
instanceID := uid.String()
instanceID = uid.String()
return store.VersionService.StoreInstanceID(instanceID)
}
return err
@@ -47,9 +52,6 @@ func (store *Store) checkOrCreateDefaultSettings() error {
EnableTelemetry: true,
AuthenticationMethod: portainer.AuthenticationInternal,
BlackListedLabels: make([]portainer.Pair, 0),
InternalAuthSettings: portainer.InternalAuthSettings{
RequiredPasswordLength: 12,
},
LDAPSettings: portainer.LDAPSettings{
AnonymousMode: true,
AutoCreateUsers: true,

View File

@@ -28,20 +28,10 @@ func (slog *ScopedLog) Debug(message string) {
slog.print(DEBUG, fmt.Sprintf("[message: %s]", message))
}
func (slog *ScopedLog) Debugf(message string, vars ...interface{}) {
message = fmt.Sprintf(message, vars...)
slog.print(DEBUG, fmt.Sprintf("[message: %s]", message))
}
func (slog *ScopedLog) Info(message string) {
slog.print(INFO, fmt.Sprintf("[message: %s]", message))
}
func (slog *ScopedLog) Infof(message string, vars ...interface{}) {
message = fmt.Sprintf(message, vars...)
slog.print(INFO, fmt.Sprintf("[message: %s]", message))
}
func (slog *ScopedLog) Error(message string, err error) {
slog.print(ERROR, fmt.Sprintf("[message: %s] [error: %s]", message, err))
}

View File

@@ -9,7 +9,6 @@ import (
plog "github.com/portainer/portainer/api/datastore/log"
"github.com/portainer/portainer/api/datastore/migrator"
"github.com/portainer/portainer/api/internal/authorization"
"github.com/sirupsen/logrus"
werrors "github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
@@ -25,12 +24,6 @@ func (store *Store) MigrateData() error {
return err
}
// Backup Database
backupPath, err := store.Backup()
if err != nil {
return werrors.Wrap(err, "while backing up db before migration")
}
migratorParams := &migrator.MigratorParameters{
DatabaseVersion: version,
EndpointGroupService: store.EndpointGroupService,
@@ -53,27 +46,7 @@ func (store *Store) MigrateData() error {
AuthorizationService: authorization.NewService(store),
}
// restore on error
err = store.connectionMigrateData(migratorParams)
if err != nil {
logrus.Errorf("While DB migration %v. Restoring DB", err)
// Restore options
options := BackupOptions{
BackupPath: backupPath,
}
err := store.restoreWithOptions(&options)
if err != nil {
logrus.Fatalf(
"Failed restoring the backup. portainer database file needs to restored manually by "+
"replacing %s database file with recent backup %s. Error %v",
store.databasePath(),
options.BackupPath,
err,
)
}
}
return err
return store.connectionMigrateData(migratorParams)
}
// FailSafeMigrate backup and restore DB if migration fail

View File

@@ -1,19 +1,13 @@
package datastore
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/database/boltdb"
)
// testVersion is a helper which tests current store version against wanted version
@@ -28,32 +22,8 @@ func testVersion(store *Store, versionWant int, t *testing.T) {
}
func TestMigrateData(t *testing.T) {
snapshotTests := []struct {
testName string
srcPath string
wantPath string
}{
{
testName: "migrate version 24 to latest",
srcPath: "test_data/input_24.json",
wantPath: "test_data/output_24_to_latest.json",
},
}
for _, test := range snapshotTests {
t.Run(test.testName, func(t *testing.T) {
err := migrateDBTestHelper(t, test.srcPath, test.wantPath)
if err != nil {
t.Errorf(
"Failed migrating mock database %v: %v",
test.srcPath,
err,
)
}
})
}
t.Run("MigrateData for New Store & Re-Open Check", func(t *testing.T) {
newStore, store, teardown := MustNewTestStore(false, true)
newStore, store, teardown := MustNewTestStore(false)
defer teardown()
if !newStore {
@@ -80,7 +50,7 @@ func TestMigrateData(t *testing.T) {
{version: 21, expectedVersion: portainer.DBVersion},
}
for _, tc := range tests {
_, store, teardown := MustNewTestStore(true, true)
_, store, teardown := MustNewTestStore(true)
defer teardown()
// Setup data
@@ -105,7 +75,7 @@ func TestMigrateData(t *testing.T) {
}
t.Run("Error in MigrateData should restore backup before MigrateData", func(t *testing.T) {
_, store, teardown := MustNewTestStore(false, true)
_, store, teardown := MustNewTestStore(false)
defer teardown()
version := 17
@@ -117,7 +87,7 @@ func TestMigrateData(t *testing.T) {
})
t.Run("MigrateData should create backup file upon update", func(t *testing.T) {
_, store, teardown := MustNewTestStore(false, true)
_, store, teardown := MustNewTestStore(false)
defer teardown()
store.VersionService.StoreDBVersion(0)
@@ -131,7 +101,7 @@ func TestMigrateData(t *testing.T) {
})
t.Run("MigrateData should fail to create backup if database file is set to updating", func(t *testing.T) {
_, store, teardown := MustNewTestStore(false, true)
_, store, teardown := MustNewTestStore(false)
defer teardown()
store.VersionService.StoreIsUpdating(true)
@@ -146,7 +116,7 @@ func TestMigrateData(t *testing.T) {
})
t.Run("MigrateData should not create backup on startup if portainer version matches db", func(t *testing.T) {
_, store, teardown := MustNewTestStore(false, true)
_, store, teardown := MustNewTestStore(false)
defer teardown()
store.MigrateData()
@@ -161,7 +131,7 @@ func TestMigrateData(t *testing.T) {
}
func Test_getBackupRestoreOptions(t *testing.T) {
_, store, teardown := MustNewTestStore(false, true)
_, store, teardown := MustNewTestStore(false)
defer teardown()
options := getBackupRestoreOptions(store.commonBackupDir())
@@ -180,7 +150,7 @@ func Test_getBackupRestoreOptions(t *testing.T) {
func TestRollback(t *testing.T) {
t.Run("Rollback should restore upgrade after backup", func(t *testing.T) {
version := 21
_, store, teardown := MustNewTestStore(false, true)
_, store, teardown := MustNewTestStore(false)
defer teardown()
store.VersionService.StoreDBVersion(version)
@@ -215,250 +185,3 @@ func isFileExist(path string) bool {
}
return len(matches) > 0
}
// migrateDBTestHelper loads a json representation of a bolt database from srcPath,
// parses it into a database, runs a migration on that database, and then
// compares it with an expected output database.
func migrateDBTestHelper(t *testing.T, srcPath, wantPath string) error {
srcJSON, err := os.ReadFile(srcPath)
if err != nil {
t.Fatalf("failed loading source JSON file %v: %v", srcPath, err)
}
// Parse source json to db.
_, store, teardown := MustNewTestStore(true, false)
defer teardown()
err = importJSON(t, bytes.NewReader(srcJSON), store)
if err != nil {
return err
}
// Run the actual migrations on our input database.
err = store.MigrateData()
if err != nil {
return err
}
// Assert that our database connection is using bolt so we can call
// exportJson rather than ExportRaw. The exportJson function allows us to
// strip out the metadata which we don't want for our tests.
// TODO: update connection interface in CE to allow us to use ExportRaw and pass meta false
err = store.connection.Close()
if err != nil {
t.Fatalf("err closing bolt connection: %v", err)
}
con, ok := store.connection.(*boltdb.DbConnection)
if !ok {
t.Fatalf("backing database is not using boltdb, but the migrations test requires it")
}
// Convert database back to json.
databasePath := con.GetDatabaseFilePath()
if _, err := os.Stat(databasePath); err != nil {
return fmt.Errorf("stat on %s failed: %s", databasePath, err)
}
gotJSON, err := con.ExportJson(databasePath, false)
if err != nil {
t.Logf(
"failed re-exporting database %s to JSON: %v",
databasePath,
err,
)
}
wantJSON, err := os.ReadFile(wantPath)
if err != nil {
t.Fatalf("failed loading want JSON file %v: %v", wantPath, err)
}
// Compare the result we got with the one we wanted.
if diff := cmp.Diff(wantJSON, gotJSON); diff != "" {
gotPath := filepath.Join(os.TempDir(), "portainer-migrator-test-fail.json")
os.WriteFile(
gotPath,
gotJSON,
0600,
)
t.Errorf(
"migrate data from %s to %s failed\nwrote migrated input to %s\nmismatch (-want +got):\n%s",
srcPath,
wantPath,
gotPath,
diff,
)
}
return nil
}
// importJSON reads input JSON and commits it to a portainer datastore.Store.
// Errors are logged with the testing package.
func importJSON(t *testing.T, r io.Reader, store *Store) error {
objects := make(map[string]interface{})
// Parse json into map of objects.
d := json.NewDecoder(r)
d.UseNumber()
err := d.Decode(&objects)
if err != nil {
return err
}
// Get database connection from store.
con := store.connection
for k, v := range objects {
switch k {
case "version":
versions, ok := v.(map[string]interface{})
if !ok {
t.Logf("failed casting %s to map[string]interface{}", k)
}
dbVersion, ok := versions["DB_VERSION"]
if !ok {
t.Logf("failed getting DB_VERSION from %s", k)
}
numDBVersion, ok := dbVersion.(json.Number)
if !ok {
t.Logf("failed parsing DB_VERSION as json number from %s", k)
}
intDBVersion, err := numDBVersion.Int64()
if err != nil {
t.Logf("failed casting %v to int: %v", numDBVersion, intDBVersion)
}
err = con.CreateObjectWithStringId(
k,
[]byte("DB_VERSION"),
int(intDBVersion),
)
if err != nil {
t.Logf("failed writing DB_VERSION in %s: %v", k, err)
}
instanceID, ok := versions["INSTANCE_ID"]
if !ok {
t.Logf("failed getting INSTANCE_ID from %s", k)
}
err = con.CreateObjectWithStringId(
k,
[]byte("INSTANCE_ID"),
instanceID,
)
if err != nil {
t.Logf("failed writing INSTANCE_ID in %s: %v", k, err)
}
case "dockerhub":
obj, ok := v.([]interface{})
if !ok {
t.Logf("failed to cast %s to []interface{}", k)
}
err := con.CreateObjectWithStringId(
k,
[]byte("DOCKERHUB"),
obj[0],
)
if err != nil {
t.Logf("failed writing DOCKERHUB in %s: %v", k, err)
}
case "ssl":
obj, ok := v.(map[string]interface{})
if !ok {
t.Logf("failed to case %s to map[string]interface{}", k)
}
err := con.CreateObjectWithStringId(
k,
[]byte("SSL"),
obj,
)
if err != nil {
t.Logf("failed writing SSL in %s: %v", k, err)
}
case "settings":
obj, ok := v.(map[string]interface{})
if !ok {
t.Logf("failed to case %s to map[string]interface{}", k)
}
err := con.CreateObjectWithStringId(
k,
[]byte("SETTINGS"),
obj,
)
if err != nil {
t.Logf("failed writing SETTINGS in %s: %v", k, err)
}
case "tunnel_server":
obj, ok := v.(map[string]interface{})
if !ok {
t.Logf("failed to case %s to map[string]interface{}", k)
}
err := con.CreateObjectWithStringId(
k,
[]byte("INFO"),
obj,
)
if err != nil {
t.Logf("failed writing INFO in %s: %v", k, err)
}
case "templates":
continue
default:
objlist, ok := v.([]interface{})
if !ok {
t.Logf("failed to cast %s to []interface{}", k)
}
for _, obj := range objlist {
value, ok := obj.(map[string]interface{})
if !ok {
t.Logf("failed to cast %v to map[string]interface{}", obj)
} else {
var ok bool
var id interface{}
switch k {
case "endpoint_relations":
// TODO: need to make into an int, then do that weird
// stringification
id, ok = value["EndpointID"]
default:
id, ok = value["Id"]
}
if !ok {
// endpoint_relations: EndpointID
t.Logf("missing Id field: %s", k)
id = "error"
}
n, ok := id.(json.Number)
if !ok {
t.Logf("failed to cast %v to json.Number in %s", id, k)
} else {
key, err := n.Int64()
if err != nil {
t.Logf("failed to cast %v to int in %s", n, k)
} else {
err := con.CreateObjectWithId(
k,
int(key),
value,
)
if err != nil {
t.Logf("failed writing %v in %s: %v", key, k, err)
}
}
}
}
}
}
}
return nil
}

View File

@@ -33,7 +33,7 @@ func setup(store *Store) error {
}
func TestMigrateSettings(t *testing.T) {
_, store, teardown := MustNewTestStore(false, true)
_, store, teardown := MustNewTestStore(false)
defer teardown()
err := setup(store)

View File

@@ -10,7 +10,7 @@ import (
)
func TestMigrateStackEntryPoint(t *testing.T) {
_, store, teardown := MustNewTestStore(false, true)
_, store, teardown := MustNewTestStore(false)
defer teardown()
stackService := store.Stack()

View File

@@ -1,38 +1,16 @@
package migrator
import (
"errors"
"reflect"
"runtime"
"fmt"
werrors "github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
)
type migration struct {
dbversion int
migrate func() error
}
func migrationError(err error, context string) error {
return werrors.Wrap(err, "failed in "+context)
}
func newMigration(dbversion int, migrate func() error) migration {
return migration{
dbversion: dbversion,
migrate: migrate,
}
}
func dbTooOldError() error {
return errors.New("migrating from less than Portainer 1.21.0 is not supported, please contact Portainer support.")
}
func GetFunctionName(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
// Migrate checks the database version and migrate the existing data to the most recent data model.
func (m *Migrator) Migrate() error {
// set DB to updating status
@@ -41,93 +19,175 @@ func (m *Migrator) Migrate() error {
return migrationError(err, "StoreIsUpdating")
}
migrations := []migration{
// Portainer < 1.21.0
newMigration(17, dbTooOldError),
// Portainer 1.21.0
newMigration(18, m.updateUsersToDBVersion18),
newMigration(18, m.updateEndpointsToDBVersion18),
newMigration(18, m.updateEndpointGroupsToDBVersion18),
newMigration(18, m.updateRegistriesToDBVersion18),
// 1.22.0
newMigration(19, m.updateSettingsToDBVersion19),
// 1.22.1
newMigration(20, m.updateUsersToDBVersion20),
newMigration(20, m.updateSettingsToDBVersion20),
newMigration(20, m.updateSchedulesToDBVersion20),
// Portainer 1.23.0
// DBVersion 21 is missing as it was shipped as via hotfix 1.22.2
newMigration(22, m.updateResourceControlsToDBVersion22),
newMigration(22, m.updateUsersAndRolesToDBVersion22),
// Portainer 1.24.0
newMigration(23, m.updateTagsToDBVersion23),
newMigration(23, m.updateEndpointsAndEndpointGroupsToDBVersion23),
// Portainer 1.24.1
newMigration(24, m.updateSettingsToDB24),
// Portainer 2.0.0
newMigration(25, m.updateSettingsToDB25),
newMigration(25, m.updateStacksToDB24), // yes this looks odd. Don't be tempted to move it
// Portainer 2.1.0
newMigration(26, m.updateEndpointSettingsToDB25),
// Portainer 2.2.0
newMigration(27, m.updateStackResourceControlToDB27),
// Portainer 2.6.0
newMigration(30, m.migrateDBVersionToDB30),
// Portainer 2.9.0
newMigration(32, m.migrateDBVersionToDB32),
// Portainer 2.9.1, 2.9.2
newMigration(33, m.migrateDBVersionToDB33),
// Portainer 2.10
newMigration(34, m.migrateDBVersionToDB34),
// Portainer 2.9.3 (yep out of order, but 2.10 is EE only)
newMigration(35, m.migrateDBVersionToDB35),
newMigration(36, m.migrateDBVersionToDB36),
// Portainer 2.13
newMigration(40, m.migrateDBVersionToDB40),
// Portainer 2.14
newMigration(50, m.migrateDBVersionToDB50),
if m.currentDBVersion < 17 {
return migrationError(err, "migrating from less than Portainer 1.21.0 is not supported, please contact Portainer support.")
}
var lastDbVersion int
for _, migration := range migrations {
if m.currentDBVersion < migration.dbversion {
// Print the next line only when the version changes
if migration.dbversion > lastDbVersion {
migrateLog.Infof("Migrating DB to version %d", migration.dbversion)
}
err := migration.migrate()
if err != nil {
return migrationError(err, GetFunctionName(migration.migrate))
}
// Portainer 1.21.0
if m.currentDBVersion < 18 {
err := m.updateUsersToDBVersion18()
if err != nil {
return migrationError(err, "updateUsersToDBVersion18")
}
err = m.updateEndpointsToDBVersion18()
if err != nil {
return migrationError(err, "updateEndpointsToDBVersion18")
}
err = m.updateEndpointGroupsToDBVersion18()
if err != nil {
return migrationError(err, "updateEndpointGroupsToDBVersion18")
}
err = m.updateRegistriesToDBVersion18()
if err != nil {
return migrationError(err, "updateRegistriesToDBVersion18")
}
}
// Portainer 1.22.0
if m.currentDBVersion < 19 {
err := m.updateSettingsToDBVersion19()
if err != nil {
return migrationError(err, "updateSettingsToDBVersion19")
}
}
// Portainer 1.22.1
if m.currentDBVersion < 20 {
err := m.updateUsersToDBVersion20()
if err != nil {
return migrationError(err, "updateUsersToDBVersion20")
}
err = m.updateSettingsToDBVersion20()
if err != nil {
return migrationError(err, "updateSettingsToDBVersion20")
}
err = m.updateSchedulesToDBVersion20()
if err != nil {
return migrationError(err, "updateSchedulesToDBVersion20")
}
}
// Portainer 1.23.0
// DBVersion 21 is missing as it was shipped as via hotfix 1.22.2
if m.currentDBVersion < 22 {
err := m.updateResourceControlsToDBVersion22()
if err != nil {
return migrationError(err, "updateResourceControlsToDBVersion22")
}
err = m.updateUsersAndRolesToDBVersion22()
if err != nil {
return migrationError(err, "updateUsersAndRolesToDBVersion22")
}
}
// Portainer 1.24.0
if m.currentDBVersion < 23 {
migrateLog.Info("Migrating to DB 23")
err := m.updateTagsToDBVersion23()
if err != nil {
return migrationError(err, "updateTagsToDBVersion23")
}
err = m.updateEndpointsAndEndpointGroupsToDBVersion23()
if err != nil {
return migrationError(err, "updateEndpointsAndEndpointGroupsToDBVersion23")
}
}
// Portainer 1.24.1
if m.currentDBVersion < 24 {
migrateLog.Info("Migrating to DB 24")
err := m.updateSettingsToDB24()
if err != nil {
return migrationError(err, "updateSettingsToDB24")
}
}
// Portainer 2.0.0
if m.currentDBVersion < 25 {
migrateLog.Info("Migrating to DB 25")
err := m.updateSettingsToDB25()
if err != nil {
return migrationError(err, "updateSettingsToDB25")
}
err = m.updateStacksToDB24()
if err != nil {
return migrationError(err, "updateStacksToDB24")
}
}
// Portainer 2.1.0
if m.currentDBVersion < 26 {
migrateLog.Info("Migrating to DB 26")
err := m.updateEndpointSettingsToDB25()
if err != nil {
return migrationError(err, "updateEndpointSettingsToDB25")
}
}
// Portainer 2.2.0
if m.currentDBVersion < 27 {
migrateLog.Info("Migrating to DB 27")
err := m.updateStackResourceControlToDB27()
if err != nil {
return migrationError(err, "updateStackResourceControlToDB27")
}
}
// Portainer 2.6.0
if m.currentDBVersion < 30 {
migrateLog.Info("Migrating to DB 30")
err := m.migrateDBVersionToDB30()
if err != nil {
return migrationError(err, "migrateDBVersionToDB30")
}
}
// Portainer 2.9.0
if m.currentDBVersion < 32 {
err := m.migrateDBVersionToDB32()
if err != nil {
return migrationError(err, "migrateDBVersionToDB32")
}
}
// Portainer 2.9.1, 2.9.2
if m.currentDBVersion < 33 {
migrateLog.Info("Migrating to DB 33")
err := m.migrateDBVersionToDB33()
if err != nil {
return migrationError(err, "migrateDBVersionToDB33")
}
}
// Portainer 2.10
if m.currentDBVersion < 34 {
migrateLog.Info("Migrating to DB 34")
if err := m.migrateDBVersionToDB34(); err != nil {
return migrationError(err, "migrateDBVersionToDB34")
}
}
// Portainer 2.9.3 (yep out of order, but 2.10 is EE only)
if m.currentDBVersion < 35 {
migrateLog.Info("Migrating to DB 35")
if err := m.migrateDBVersionToDB35(); err != nil {
return migrationError(err, "migrateDBVersionToDB35")
}
lastDbVersion = migration.dbversion
}
migrateLog.Infof("Setting DB version to %d", portainer.DBVersion)
err = m.versionService.StoreDBVersion(portainer.DBVersion)
if err != nil {
return migrationError(err, "StoreDBVersion")
}
migrateLog.Infof("Updated DB version to %d", portainer.DBVersion)
migrateLog.Info(fmt.Sprintf("Updated DB version to %d", portainer.DBVersion))
// reset DB updating status
return m.versionService.StoreIsUpdating(false)

View File

@@ -5,7 +5,6 @@ import (
)
func (m *Migrator) updateUsersToDBVersion18() error {
migrateLog.Info("- updating users")
legacyUsers, err := m.userService.Users()
if err != nil {
return err
@@ -40,7 +39,6 @@ func (m *Migrator) updateUsersToDBVersion18() error {
}
func (m *Migrator) updateEndpointsToDBVersion18() error {
migrateLog.Info("- updating endpoints")
legacyEndpoints, err := m.endpointService.Endpoints()
if err != nil {
return err
@@ -71,7 +69,6 @@ func (m *Migrator) updateEndpointsToDBVersion18() error {
}
func (m *Migrator) updateEndpointGroupsToDBVersion18() error {
migrateLog.Info("- updating endpoint groups")
legacyEndpointGroups, err := m.endpointGroupService.EndpointGroups()
if err != nil {
return err
@@ -102,7 +99,6 @@ func (m *Migrator) updateEndpointGroupsToDBVersion18() error {
}
func (m *Migrator) updateRegistriesToDBVersion18() error {
migrateLog.Info("- updating registries")
legacyRegistries, err := m.registryService.Registries()
if err != nil {
return err

View File

@@ -3,7 +3,6 @@ package migrator
import portainer "github.com/portainer/portainer/api"
func (m *Migrator) updateSettingsToDBVersion19() error {
migrateLog.Info("- updating settings")
legacySettings, err := m.settingsService.Settings()
if err != nil {
return err

View File

@@ -7,7 +7,6 @@ import (
const scheduleScriptExecutionJobType = 1
func (m *Migrator) updateUsersToDBVersion20() error {
migrateLog.Info("- updating user authentication")
return m.authorizationService.UpdateUsersAuthorizations()
}
@@ -23,7 +22,6 @@ func (m *Migrator) updateSettingsToDBVersion20() error {
}
func (m *Migrator) updateSchedulesToDBVersion20() error {
migrateLog.Info("- updating schedules")
legacySchedules, err := m.scheduleService.Schedules()
if err != nil {
return err

View File

@@ -6,7 +6,6 @@ import (
)
func (m *Migrator) updateResourceControlsToDBVersion22() error {
migrateLog.Info("- updating resource controls")
legacyResourceControls, err := m.resourceControlService.ResourceControls()
if err != nil {
return err
@@ -25,7 +24,6 @@ func (m *Migrator) updateResourceControlsToDBVersion22() error {
}
func (m *Migrator) updateUsersAndRolesToDBVersion22() error {
migrateLog.Info("- updating users and roles")
legacyUsers, err := m.userService.Users()
if err != nil {
return err

View File

@@ -3,7 +3,7 @@ package migrator
import portainer "github.com/portainer/portainer/api"
func (m *Migrator) updateTagsToDBVersion23() error {
migrateLog.Info("- Updating tags")
migrateLog.Info("Updating tags")
tags, err := m.tagService.Tags()
if err != nil {
return err
@@ -21,7 +21,7 @@ func (m *Migrator) updateTagsToDBVersion23() error {
}
func (m *Migrator) updateEndpointsAndEndpointGroupsToDBVersion23() error {
migrateLog.Info("- updating endpoints and endpoint groups")
migrateLog.Info("Updating endpoints and endpoint groups")
tags, err := m.tagService.Tags()
if err != nil {
return err

View File

@@ -3,7 +3,7 @@ package migrator
import portainer "github.com/portainer/portainer/api"
func (m *Migrator) updateSettingsToDB24() error {
migrateLog.Info("- updating Settings")
migrateLog.Info("Updating Settings")
legacySettings, err := m.settingsService.Settings()
if err != nil {
@@ -18,7 +18,7 @@ func (m *Migrator) updateSettingsToDB24() error {
}
func (m *Migrator) updateStacksToDB24() error {
migrateLog.Info("- updating stacks")
migrateLog.Info("Updating stacks")
stacks, err := m.stackService.Stacks()
if err != nil {
return err

View File

@@ -5,7 +5,7 @@ import (
)
func (m *Migrator) updateSettingsToDB25() error {
migrateLog.Info("- updating settings")
migrateLog.Info("Updating settings")
legacySettings, err := m.settingsService.Settings()
if err != nil {

View File

@@ -5,7 +5,7 @@ import (
)
func (m *Migrator) updateEndpointSettingsToDB25() error {
migrateLog.Info("- updating endpoint settings")
migrateLog.Info("Updating endpoint settings")
settings, err := m.settingsService.Settings()
if err != nil {
return err

View File

@@ -7,7 +7,7 @@ import (
)
func (m *Migrator) updateStackResourceControlToDB27() error {
migrateLog.Info("- updating stack resource controls")
migrateLog.Info("Updating stack resource controls")
resourceControls, err := m.resourceControlService.ResourceControls()
if err != nil {
return err

View File

@@ -1,7 +1,7 @@
package migrator
func (m *Migrator) migrateDBVersionToDB30() error {
migrateLog.Info("- updating legacy settings")
migrateLog.Info("Updating legacy settings")
if err := m.MigrateSettingsToDB30(); err != nil {
return err
}

View File

@@ -2,10 +2,8 @@ package migrator
import (
"fmt"
"log"
"github.com/docker/docker/api/types/volume"
"github.com/portainer/portainer/api/dataservices/errors"
"log"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/internal/endpointutils"
@@ -13,24 +11,29 @@ import (
)
func (m *Migrator) migrateDBVersionToDB32() error {
migrateLog.Info("Updating registries")
err := m.updateRegistriesToDB32()
if err != nil {
return err
}
migrateLog.Info("Updating dockerhub")
err = m.updateDockerhubToDB32()
if err != nil {
return err
}
migrateLog.Info("Updating resource controls")
if err := m.updateVolumeResourceControlToDB32(); err != nil {
return err
}
migrateLog.Info("Updating kubeconfig expiry")
if err := m.kubeconfigExpiryToDB32(); err != nil {
return err
}
migrateLog.Info("Setting default helm repository url")
if err := m.helmRepositoryURLToDB32(); err != nil {
return err
}
@@ -39,7 +42,6 @@ func (m *Migrator) migrateDBVersionToDB32() error {
}
func (m *Migrator) updateRegistriesToDB32() error {
migrateLog.Info("- updating registries")
registries, err := m.registryService.Registries()
if err != nil {
return err
@@ -82,7 +84,6 @@ func (m *Migrator) updateRegistriesToDB32() error {
}
func (m *Migrator) updateDockerhubToDB32() error {
migrateLog.Info("- updating dockerhub")
dockerhub, err := m.dockerhubService.DockerHub()
if err == errors.ErrObjectNotFound {
return nil
@@ -171,7 +172,6 @@ func (m *Migrator) updateDockerhubToDB32() error {
}
func (m *Migrator) updateVolumeResourceControlToDB32() error {
migrateLog.Info("- updating resource controls")
endpoints, err := m.endpointService.Endpoints()
if err != nil {
return fmt.Errorf("failed fetching environments: %w", err)
@@ -211,14 +211,14 @@ func (m *Migrator) updateVolumeResourceControlToDB32() error {
continue
}
volumesData := snapshot.SnapshotRaw.Volumes
if volumesData.Volumes == nil {
log.Println("[DEBUG] [volume migration] [message: no volume data found]")
continue
if volumesData, done := snapshot.SnapshotRaw.Volumes.(map[string]interface{}); done {
if volumesData["Volumes"] == nil {
log.Println("[DEBUG] [volume migration] [message: no volume data found]")
continue
}
findResourcesToUpdateForDB32(endpointDockerID, volumesData, toUpdate, volumeResourceControls)
}
findResourcesToUpdateForDB32(endpointDockerID, volumesData, toUpdate, volumeResourceControls)
}
for _, resourceControl := range volumeResourceControls {
@@ -241,11 +241,18 @@ func (m *Migrator) updateVolumeResourceControlToDB32() error {
return nil
}
func findResourcesToUpdateForDB32(dockerID string, volumesData volume.VolumeListOKBody, toUpdate map[portainer.ResourceControlID]string, volumeResourceControls map[string]*portainer.ResourceControl) {
volumes := volumesData.Volumes
for _, volume := range volumes {
volumeName := volume.Name
createTime := volume.CreatedAt
func findResourcesToUpdateForDB32(dockerID string, volumesData map[string]interface{}, toUpdate map[portainer.ResourceControlID]string, volumeResourceControls map[string]*portainer.ResourceControl) {
volumes := volumesData["Volumes"].([]interface{})
for _, volumeMeta := range volumes {
volume := volumeMeta.(map[string]interface{})
volumeName, nameExist := volume["Name"].(string)
if !nameExist {
continue
}
createTime, createTimeExist := volume["CreatedAt"].(string)
if !createTimeExist {
continue
}
oldResourceID := fmt.Sprintf("%s%s", volumeName, createTime)
resourceControl, ok := volumeResourceControls[oldResourceID]
@@ -257,7 +264,6 @@ func findResourcesToUpdateForDB32(dockerID string, volumesData volume.VolumeList
}
func (m *Migrator) kubeconfigExpiryToDB32() error {
migrateLog.Info("- updating kubeconfig expiry")
settings, err := m.settingsService.Settings()
if err != nil {
return err
@@ -267,7 +273,6 @@ func (m *Migrator) kubeconfigExpiryToDB32() error {
}
func (m *Migrator) helmRepositoryURLToDB32() error {
migrateLog.Info("- setting default helm repository URL")
settings, err := m.settingsService.Settings()
if err != nil {
return err

View File

@@ -1,11 +1,8 @@
package migrator
import (
portainer "github.com/portainer/portainer/api"
)
import portainer "github.com/portainer/portainer/api"
func (m *Migrator) migrateDBVersionToDB33() error {
migrateLog.Info("- updating settings")
if err := m.migrateSettingsToDB33(); err != nil {
return err
}
@@ -19,7 +16,7 @@ func (m *Migrator) migrateSettingsToDB33() error {
return err
}
migrateLog.Info("- setting default kubectl shell image")
migrateLog.Info("Setting default kubectl shell image")
settings.KubectlShellImage = portainer.DefaultKubectlShellImage
return m.settingsService.UpdateSettings(settings)
}

View File

@@ -1,11 +1,9 @@
package migrator
import (
"github.com/portainer/portainer/api/dataservices"
)
import "github.com/portainer/portainer/api/dataservices"
func (m *Migrator) migrateDBVersionToDB34() error {
migrateLog.Info("- updating stacks")
migrateLog.Info("Migrating stacks")
err := MigrateStackEntryPoint(m.stackService)
if err != nil {
return err

View File

@@ -3,7 +3,7 @@ package migrator
func (m *Migrator) migrateDBVersionToDB35() error {
// These should have been migrated already, but due to an earlier bug and a bunch of duplicates,
// calling it again will now fix the issue as the function has been repaired.
migrateLog.Info("- updating dockerhub registries")
migrateLog.Info("Updating dockerhub registries")
err := m.updateDockerhubToDB32()
if err != nil {
return err

View File

@@ -1,36 +0,0 @@
package migrator
import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/internal/authorization"
)
func (m *Migrator) migrateDBVersionToDB36() error {
migrateLog.Info("Updating user authorizations")
if err := m.migrateUsersToDB36(); err != nil {
return err
}
return nil
}
func (m *Migrator) migrateUsersToDB36() error {
users, err := m.userService.Users()
if err != nil {
return err
}
for _, user := range users {
currentAuthorizations := authorization.DefaultPortainerAuthorizations()
currentAuthorizations[portainer.OperationPortainerUserListToken] = true
currentAuthorizations[portainer.OperationPortainerUserCreateToken] = true
currentAuthorizations[portainer.OperationPortainerUserRevokeToken] = true
user.PortainerAuthorizations = currentAuthorizations
err = m.userService.UpdateUser(user.ID, &user)
if err != nil {
return err
}
}
return nil
}

View File

@@ -1,31 +0,0 @@
package migrator
import "github.com/portainer/portainer/api/internal/endpointutils"
func (m *Migrator) migrateDBVersionToDB40() error {
if err := m.trustCurrentEdgeEndpointsDB40(); err != nil {
return err
}
return nil
}
func (m *Migrator) trustCurrentEdgeEndpointsDB40() error {
migrateLog.Info("- trusting current edge endpoints")
endpoints, err := m.endpointService.Endpoints()
if err != nil {
return err
}
for _, endpoint := range endpoints {
if endpointutils.IsEdgeEndpoint(&endpoint) {
endpoint.UserTrusted = true
err = m.endpointService.UpdateEndpoint(endpoint.ID, &endpoint)
if err != nil {
return err
}
}
}
return nil
}

View File

@@ -1,20 +0,0 @@
package migrator
import (
"github.com/pkg/errors"
)
func (m *Migrator) migrateDBVersionToDB50() error {
return m.migratePasswordLengthSettings()
}
func (m *Migrator) migratePasswordLengthSettings() error {
migrateLog.Info("Updating required password length")
s, err := m.settingsService.Settings()
if err != nil {
return errors.Wrap(err, "unable to retrieve settings")
}
s.InternalAuthSettings.RequiredPasswordLength = 12
return m.settingsService.UpdateSettings(s)
}

View File

@@ -369,7 +369,6 @@ type storeExport struct {
User []portainer.User `json:"users,omitempty"`
Version map[string]string `json:"version,omitempty"`
Webhook []portainer.Webhook `json:"webhooks,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
func (store *Store) Export(filename string) (err error) {
@@ -562,11 +561,6 @@ func (store *Store) Export(filename string) (err error) {
"INSTANCE_ID": instance,
}
backup.Metadata, err = store.connection.BackupMetadata()
if err != nil {
logrus.WithError(err).Errorf("Exporting Metadata")
}
b, err := json.MarshalIndent(backup, "", " ")
if err != nil {
return err
@@ -575,7 +569,6 @@ func (store *Store) Export(filename string) (err error) {
}
func (store *Store) Import(filename string) (err error) {
backup := storeExport{}
s, err := ioutil.ReadFile(filename)
@@ -676,5 +669,5 @@ func (store *Store) Import(filename string) (err error) {
store.Webhook().UpdateWebhook(v.ID, &v)
}
return store.connection.RestoreMetadata(backup.Metadata)
return nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,916 +0,0 @@
{
"dockerhub": [
{
"Authentication": false,
"Username": ""
}
],
"endpoint_groups": [
{
"AuthorizedTeams": null,
"AuthorizedUsers": null,
"Description": "Unassigned endpoints",
"Id": 1,
"Labels": [],
"Name": "Unassigned",
"TagIds": [],
"Tags": null,
"TeamAccessPolicies": {},
"UserAccessPolicies": {}
}
],
"endpoint_relations": [
{
"EdgeStacks": {},
"EndpointID": 1
}
],
"endpoints": [
{
"AuthorizedTeams": null,
"AuthorizedUsers": null,
"AzureCredentials": {
"ApplicationID": "",
"AuthenticationKey": "",
"TenantID": ""
},
"ComposeSyntaxMaxVersion": "",
"Edge": {
"AsyncMode": false,
"CommandInterval": 0,
"PingInterval": 0,
"SnapshotInterval": 0
},
"EdgeCheckinInterval": 0,
"EdgeKey": "",
"GroupId": 1,
"Id": 1,
"IsEdgeDevice": false,
"Kubernetes": {
"Configuration": {
"IngressClasses": null,
"RestrictDefaultNamespace": false,
"StorageClasses": null,
"UseLoadBalancer": false,
"UseServerMetrics": false
},
"Snapshots": null
},
"LastCheckInDate": 0,
"Name": "local",
"PublicURL": "",
"QueryDate": 0,
"SecuritySettings": {
"allowBindMountsForRegularUsers": true,
"allowContainerCapabilitiesForRegularUsers": true,
"allowDeviceMappingForRegularUsers": true,
"allowHostNamespaceForRegularUsers": true,
"allowPrivilegedModeForRegularUsers": true,
"allowStackManagementForRegularUsers": true,
"allowSysctlSettingForRegularUsers": false,
"allowVolumeBrowserForRegularUsers": false,
"enableHostManagementFeatures": false
},
"Snapshots": [
{
"DockerSnapshotRaw": {
"Containers": null,
"Images": null,
"Info": {
"Architecture": "",
"BridgeNfIp6tables": false,
"BridgeNfIptables": false,
"CPUSet": false,
"CPUShares": false,
"CgroupDriver": "",
"ContainerdCommit": {
"Expected": "",
"ID": ""
},
"Containers": 0,
"ContainersPaused": 0,
"ContainersRunning": 0,
"ContainersStopped": 0,
"CpuCfsPeriod": false,
"CpuCfsQuota": false,
"Debug": false,
"DefaultRuntime": "",
"DockerRootDir": "",
"Driver": "",
"DriverStatus": null,
"ExperimentalBuild": false,
"GenericResources": null,
"HttpProxy": "",
"HttpsProxy": "",
"ID": "",
"IPv4Forwarding": false,
"Images": 0,
"IndexServerAddress": "",
"InitBinary": "",
"InitCommit": {
"Expected": "",
"ID": ""
},
"Isolation": "",
"KernelMemory": false,
"KernelMemoryTCP": false,
"KernelVersion": "",
"Labels": null,
"LiveRestoreEnabled": false,
"LoggingDriver": "",
"MemTotal": 0,
"MemoryLimit": false,
"NCPU": 0,
"NEventsListener": 0,
"NFd": 0,
"NGoroutines": 0,
"Name": "",
"NoProxy": "",
"OSType": "",
"OSVersion": "",
"OomKillDisable": false,
"OperatingSystem": "",
"PidsLimit": false,
"Plugins": {
"Authorization": null,
"Log": null,
"Network": null,
"Volume": null
},
"RegistryConfig": null,
"RuncCommit": {
"Expected": "",
"ID": ""
},
"Runtimes": null,
"SecurityOptions": null,
"ServerVersion": "",
"SwapLimit": false,
"Swarm": {
"ControlAvailable": false,
"Error": "",
"LocalNodeState": "",
"NodeAddr": "",
"NodeID": "",
"RemoteManagers": null
},
"SystemTime": "",
"Warnings": null
},
"Networks": null,
"Version": {
"ApiVersion": "",
"Arch": "",
"GitCommit": "",
"GoVersion": "",
"Os": "",
"Platform": {
"Name": ""
},
"Version": ""
},
"Volumes": {
"Volumes": null,
"Warnings": null
}
},
"DockerVersion": "20.10.13",
"HealthyContainerCount": 0,
"ImageCount": 9,
"NodeCount": 0,
"RunningContainerCount": 5,
"ServiceCount": 0,
"StackCount": 2,
"StoppedContainerCount": 0,
"Swarm": false,
"Time": 1648610112,
"TotalCPU": 8,
"TotalMemory": 25098706944,
"UnhealthyContainerCount": 0,
"VolumeCount": 10
}
],
"Status": 1,
"TLSConfig": {
"TLS": false,
"TLSSkipVerify": false
},
"TagIds": [],
"Tags": null,
"TeamAccessPolicies": {},
"Type": 1,
"URL": "unix:///var/run/docker.sock",
"UserAccessPolicies": {},
"UserTrusted": false
}
],
"registries": [
{
"Authentication": true,
"AuthorizedTeams": null,
"AuthorizedUsers": null,
"BaseURL": "",
"Ecr": {
"Region": ""
},
"Gitlab": {
"InstanceURL": "",
"ProjectId": 0,
"ProjectPath": ""
},
"Id": 1,
"ManagementConfiguration": null,
"Name": "canister.io",
"Password": "MjWbx8A6YK7cw7",
"Quay": {
"OrganisationName": "",
"UseOrganisation": false
},
"RegistryAccesses": {
"1": {
"Namespaces": [],
"TeamAccessPolicies": {},
"UserAccessPolicies": {}
}
},
"TeamAccessPolicies": {},
"Type": 3,
"URL": "cloud.canister.io:5000",
"UserAccessPolicies": {},
"Username": "prabhatkhera"
}
],
"resource_control": [
{
"AdministratorsOnly": false,
"Id": 2,
"Public": true,
"ResourceId": "762gbwaj8r4gcsdy8ld1u4why",
"SubResourceIds": [],
"System": false,
"TeamAccesses": [],
"Type": 5,
"UserAccesses": []
},
{
"AdministratorsOnly": false,
"Id": 3,
"Public": true,
"ResourceId": "1_alpine",
"SubResourceIds": [],
"System": false,
"TeamAccesses": [],
"Type": 6,
"UserAccesses": []
},
{
"AdministratorsOnly": false,
"Id": 4,
"Public": true,
"ResourceId": "1_redis",
"SubResourceIds": [],
"System": false,
"TeamAccesses": [],
"Type": 6,
"UserAccesses": []
},
{
"AdministratorsOnly": false,
"Id": 5,
"Public": false,
"ResourceId": "1_nginx",
"SubResourceIds": [],
"System": false,
"TeamAccesses": [
{
"AccessLevel": 1,
"TeamId": 1
}
],
"Type": 6,
"UserAccesses": []
}
],
"roles": [
{
"Authorizations": {
"DockerAgentBrowseDelete": true,
"DockerAgentBrowseGet": true,
"DockerAgentBrowseList": true,
"DockerAgentBrowsePut": true,
"DockerAgentBrowseRename": true,
"DockerAgentHostInfo": true,
"DockerAgentList": true,
"DockerAgentPing": true,
"DockerAgentUndefined": true,
"DockerBuildCancel": true,
"DockerBuildPrune": true,
"DockerConfigCreate": true,
"DockerConfigDelete": true,
"DockerConfigInspect": true,
"DockerConfigList": true,
"DockerConfigUpdate": true,
"DockerContainerArchive": true,
"DockerContainerArchiveInfo": true,
"DockerContainerAttach": true,
"DockerContainerAttachWebsocket": true,
"DockerContainerChanges": true,
"DockerContainerCreate": true,
"DockerContainerDelete": true,
"DockerContainerExec": true,
"DockerContainerExport": true,
"DockerContainerInspect": true,
"DockerContainerKill": true,
"DockerContainerList": true,
"DockerContainerLogs": true,
"DockerContainerPause": true,
"DockerContainerPrune": true,
"DockerContainerPutContainerArchive": true,
"DockerContainerRename": true,
"DockerContainerResize": true,
"DockerContainerRestart": true,
"DockerContainerStart": true,
"DockerContainerStats": true,
"DockerContainerStop": true,
"DockerContainerTop": true,
"DockerContainerUnpause": true,
"DockerContainerUpdate": true,
"DockerContainerWait": true,
"DockerDistributionInspect": true,
"DockerEvents": true,
"DockerExecInspect": true,
"DockerExecResize": true,
"DockerExecStart": true,
"DockerImageBuild": true,
"DockerImageCommit": true,
"DockerImageCreate": true,
"DockerImageDelete": true,
"DockerImageGet": true,
"DockerImageGetAll": true,
"DockerImageHistory": true,
"DockerImageInspect": true,
"DockerImageList": true,
"DockerImageLoad": true,
"DockerImagePrune": true,
"DockerImagePush": true,
"DockerImageSearch": true,
"DockerImageTag": true,
"DockerInfo": true,
"DockerNetworkConnect": true,
"DockerNetworkCreate": true,
"DockerNetworkDelete": true,
"DockerNetworkDisconnect": true,
"DockerNetworkInspect": true,
"DockerNetworkList": true,
"DockerNetworkPrune": true,
"DockerNodeDelete": true,
"DockerNodeInspect": true,
"DockerNodeList": true,
"DockerNodeUpdate": true,
"DockerPing": true,
"DockerPluginCreate": true,
"DockerPluginDelete": true,
"DockerPluginDisable": true,
"DockerPluginEnable": true,
"DockerPluginInspect": true,
"DockerPluginList": true,
"DockerPluginPrivileges": true,
"DockerPluginPull": true,
"DockerPluginPush": true,
"DockerPluginSet": true,
"DockerPluginUpgrade": true,
"DockerSecretCreate": true,
"DockerSecretDelete": true,
"DockerSecretInspect": true,
"DockerSecretList": true,
"DockerSecretUpdate": true,
"DockerServiceCreate": true,
"DockerServiceDelete": true,
"DockerServiceInspect": true,
"DockerServiceList": true,
"DockerServiceLogs": true,
"DockerServiceUpdate": true,
"DockerSessionStart": true,
"DockerSwarmInit": true,
"DockerSwarmInspect": true,
"DockerSwarmJoin": true,
"DockerSwarmLeave": true,
"DockerSwarmUnlock": true,
"DockerSwarmUnlockKey": true,
"DockerSwarmUpdate": true,
"DockerSystem": true,
"DockerTaskInspect": true,
"DockerTaskList": true,
"DockerTaskLogs": true,
"DockerUndefined": true,
"DockerVersion": true,
"DockerVolumeCreate": true,
"DockerVolumeDelete": true,
"DockerVolumeInspect": true,
"DockerVolumeList": true,
"DockerVolumePrune": true,
"EndpointResourcesAccess": true,
"IntegrationStoridgeAdmin": true,
"PortainerResourceControlCreate": true,
"PortainerResourceControlUpdate": true,
"PortainerStackCreate": true,
"PortainerStackDelete": true,
"PortainerStackFile": true,
"PortainerStackInspect": true,
"PortainerStackList": true,
"PortainerStackMigrate": true,
"PortainerStackUpdate": true,
"PortainerWebhookCreate": true,
"PortainerWebhookDelete": true,
"PortainerWebhookList": true,
"PortainerWebsocketExec": true
},
"Description": "Full control of all resources in an endpoint",
"Id": 1,
"Name": "Endpoint administrator",
"Priority": 1
},
{
"Authorizations": {
"DockerAgentHostInfo": true,
"DockerAgentList": true,
"DockerAgentPing": true,
"DockerConfigInspect": true,
"DockerConfigList": true,
"DockerContainerArchiveInfo": true,
"DockerContainerChanges": true,
"DockerContainerInspect": true,
"DockerContainerList": true,
"DockerContainerLogs": true,
"DockerContainerStats": true,
"DockerContainerTop": true,
"DockerDistributionInspect": true,
"DockerEvents": true,
"DockerImageGet": true,
"DockerImageGetAll": true,
"DockerImageHistory": true,
"DockerImageInspect": true,
"DockerImageList": true,
"DockerImageSearch": true,
"DockerInfo": true,
"DockerNetworkInspect": true,
"DockerNetworkList": true,
"DockerNodeInspect": true,
"DockerNodeList": true,
"DockerPing": true,
"DockerPluginList": true,
"DockerSecretInspect": true,
"DockerSecretList": true,
"DockerServiceInspect": true,
"DockerServiceList": true,
"DockerServiceLogs": true,
"DockerSwarmInspect": true,
"DockerSystem": true,
"DockerTaskInspect": true,
"DockerTaskList": true,
"DockerTaskLogs": true,
"DockerVersion": true,
"DockerVolumeInspect": true,
"DockerVolumeList": true,
"EndpointResourcesAccess": true,
"PortainerStackFile": true,
"PortainerStackInspect": true,
"PortainerStackList": true,
"PortainerWebhookList": true
},
"Description": "Read-only access of all resources in an endpoint",
"Id": 2,
"Name": "Helpdesk",
"Priority": 2
},
{
"Authorizations": {
"DockerAgentHostInfo": true,
"DockerAgentList": true,
"DockerAgentPing": true,
"DockerAgentUndefined": true,
"DockerBuildCancel": true,
"DockerBuildPrune": true,
"DockerConfigCreate": true,
"DockerConfigDelete": true,
"DockerConfigInspect": true,
"DockerConfigList": true,
"DockerConfigUpdate": true,
"DockerContainerArchive": true,
"DockerContainerArchiveInfo": true,
"DockerContainerAttach": true,
"DockerContainerAttachWebsocket": true,
"DockerContainerChanges": true,
"DockerContainerCreate": true,
"DockerContainerDelete": true,
"DockerContainerExec": true,
"DockerContainerExport": true,
"DockerContainerInspect": true,
"DockerContainerKill": true,
"DockerContainerList": true,
"DockerContainerLogs": true,
"DockerContainerPause": true,
"DockerContainerPutContainerArchive": true,
"DockerContainerRename": true,
"DockerContainerResize": true,
"DockerContainerRestart": true,
"DockerContainerStart": true,
"DockerContainerStats": true,
"DockerContainerStop": true,
"DockerContainerTop": true,
"DockerContainerUnpause": true,
"DockerContainerUpdate": true,
"DockerContainerWait": true,
"DockerDistributionInspect": true,
"DockerEvents": true,
"DockerExecInspect": true,
"DockerExecResize": true,
"DockerExecStart": true,
"DockerImageBuild": true,
"DockerImageCommit": true,
"DockerImageCreate": true,
"DockerImageDelete": true,
"DockerImageGet": true,
"DockerImageGetAll": true,
"DockerImageHistory": true,
"DockerImageInspect": true,
"DockerImageList": true,
"DockerImageLoad": true,
"DockerImagePush": true,
"DockerImageSearch": true,
"DockerImageTag": true,
"DockerInfo": true,
"DockerNetworkConnect": true,
"DockerNetworkCreate": true,
"DockerNetworkDelete": true,
"DockerNetworkDisconnect": true,
"DockerNetworkInspect": true,
"DockerNetworkList": true,
"DockerNodeDelete": true,
"DockerNodeInspect": true,
"DockerNodeList": true,
"DockerNodeUpdate": true,
"DockerPing": true,
"DockerPluginCreate": true,
"DockerPluginDelete": true,
"DockerPluginDisable": true,
"DockerPluginEnable": true,
"DockerPluginInspect": true,
"DockerPluginList": true,
"DockerPluginPrivileges": true,
"DockerPluginPull": true,
"DockerPluginPush": true,
"DockerPluginSet": true,
"DockerPluginUpgrade": true,
"DockerSecretCreate": true,
"DockerSecretDelete": true,
"DockerSecretInspect": true,
"DockerSecretList": true,
"DockerSecretUpdate": true,
"DockerServiceCreate": true,
"DockerServiceDelete": true,
"DockerServiceInspect": true,
"DockerServiceList": true,
"DockerServiceLogs": true,
"DockerServiceUpdate": true,
"DockerSessionStart": true,
"DockerSwarmInit": true,
"DockerSwarmInspect": true,
"DockerSwarmJoin": true,
"DockerSwarmLeave": true,
"DockerSwarmUnlock": true,
"DockerSwarmUnlockKey": true,
"DockerSwarmUpdate": true,
"DockerSystem": true,
"DockerTaskInspect": true,
"DockerTaskList": true,
"DockerTaskLogs": true,
"DockerUndefined": true,
"DockerVersion": true,
"DockerVolumeCreate": true,
"DockerVolumeDelete": true,
"DockerVolumeInspect": true,
"DockerVolumeList": true,
"PortainerResourceControlUpdate": true,
"PortainerStackCreate": true,
"PortainerStackDelete": true,
"PortainerStackFile": true,
"PortainerStackInspect": true,
"PortainerStackList": true,
"PortainerStackMigrate": true,
"PortainerStackUpdate": true,
"PortainerWebhookCreate": true,
"PortainerWebhookList": true,
"PortainerWebsocketExec": true
},
"Description": "Full control of assigned resources in an endpoint",
"Id": 3,
"Name": "Standard user",
"Priority": 3
},
{
"Authorizations": {
"DockerAgentHostInfo": true,
"DockerAgentList": true,
"DockerAgentPing": true,
"DockerConfigInspect": true,
"DockerConfigList": true,
"DockerContainerArchiveInfo": true,
"DockerContainerChanges": true,
"DockerContainerInspect": true,
"DockerContainerList": true,
"DockerContainerLogs": true,
"DockerContainerStats": true,
"DockerContainerTop": true,
"DockerDistributionInspect": true,
"DockerEvents": true,
"DockerImageGet": true,
"DockerImageGetAll": true,
"DockerImageHistory": true,
"DockerImageInspect": true,
"DockerImageList": true,
"DockerImageSearch": true,
"DockerInfo": true,
"DockerNetworkInspect": true,
"DockerNetworkList": true,
"DockerNodeInspect": true,
"DockerNodeList": true,
"DockerPing": true,
"DockerPluginList": true,
"DockerSecretInspect": true,
"DockerSecretList": true,
"DockerServiceInspect": true,
"DockerServiceList": true,
"DockerServiceLogs": true,
"DockerSwarmInspect": true,
"DockerSystem": true,
"DockerTaskInspect": true,
"DockerTaskList": true,
"DockerTaskLogs": true,
"DockerVersion": true,
"DockerVolumeInspect": true,
"DockerVolumeList": true,
"PortainerStackFile": true,
"PortainerStackInspect": true,
"PortainerStackList": true,
"PortainerWebhookList": true
},
"Description": "Read-only access of assigned resources in an endpoint",
"Id": 4,
"Name": "Read-only user",
"Priority": 4
}
],
"schedules": [
{
"Created": 1648608136,
"CronExpression": "@every 5m",
"EdgeSchedule": null,
"EndpointSyncJob": null,
"Id": 1,
"JobType": 2,
"Name": "system_snapshot",
"Recurring": true,
"ScriptExecutionJob": null,
"SnapshotJob": {}
}
],
"settings": {
"AgentSecret": "",
"AllowBindMountsForRegularUsers": true,
"AllowContainerCapabilitiesForRegularUsers": true,
"AllowDeviceMappingForRegularUsers": true,
"AllowHostNamespaceForRegularUsers": true,
"AllowPrivilegedModeForRegularUsers": true,
"AllowStackManagementForRegularUsers": true,
"AllowVolumeBrowserForRegularUsers": false,
"AuthenticationMethod": 1,
"BlackListedLabels": [],
"DisplayDonationHeader": false,
"DisplayExternalContributors": false,
"Edge": {
"AsyncMode": false,
"CommandInterval": 0,
"PingInterval": 0,
"SnapshotInterval": 0
},
"EdgeAgentCheckinInterval": 5,
"EdgePortainerUrl": "",
"EnableEdgeComputeFeatures": false,
"EnableHostManagementFeatures": false,
"EnableTelemetry": true,
"EnforceEdgeID": false,
"FeatureFlagSettings": null,
"HelmRepositoryURL": "https://charts.bitnami.com/bitnami",
"InternalAuthSettings": {
"RequiredPasswordLength": 12
},
"KubeconfigExpiry": "0",
"KubectlShellImage": "portainer/kubectl-shell",
"LDAPSettings": {
"AnonymousMode": true,
"AutoCreateUsers": true,
"GroupSearchSettings": [
{
"GroupAttribute": "",
"GroupBaseDN": "",
"GroupFilter": ""
}
],
"ReaderDN": "",
"SearchSettings": [
{
"BaseDN": "",
"Filter": "",
"UserNameAttribute": ""
}
],
"StartTLS": false,
"TLSConfig": {
"TLS": false,
"TLSSkipVerify": false
},
"URL": ""
},
"LogoURL": "",
"OAuthSettings": {
"AccessTokenURI": "",
"AuthorizationURI": "",
"ClientID": "",
"DefaultTeamID": 0,
"KubeSecretKey": null,
"LogoutURI": "",
"OAuthAutoCreateUsers": false,
"RedirectURI": "",
"ResourceURI": "",
"SSO": false,
"Scopes": "",
"UserIdentifier": ""
},
"SnapshotInterval": "5m",
"TemplatesURL": "https://raw.githubusercontent.com/portainer/templates/master/templates-2.0.json",
"TrustOnFirstConnect": false,
"UserSessionTimeout": "8h",
"fdoConfiguration": {
"enabled": false,
"ownerPassword": "",
"ownerURL": "",
"ownerUsername": ""
},
"openAMTConfiguration": {
"certFileContent": "",
"certFileName": "",
"certFilePassword": "",
"domainName": "",
"enabled": false,
"mpsPassword": "",
"mpsServer": "",
"mpsToken": "",
"mpsUser": ""
}
},
"ssl": {
"certPath": "",
"httpEnabled": true,
"keyPath": "",
"selfSigned": false
},
"stacks": [
{
"AdditionalFiles": null,
"AutoUpdate": null,
"CreatedBy": "",
"CreationDate": 0,
"EndpointId": 1,
"EntryPoint": "docker/alpine37-compose.yml",
"Env": [],
"FromAppTemplate": false,
"GitConfig": null,
"Id": 2,
"IsComposeFormat": false,
"Name": "alpine",
"Namespace": "",
"ProjectPath": "/home/prabhat/portainer/data/ce1.25/compose/2",
"ResourceControl": null,
"Status": 1,
"SwarmId": "s3fd604zdba7z13tbq2x6lyue",
"Type": 1,
"UpdateDate": 0,
"UpdatedBy": ""
},
{
"AdditionalFiles": null,
"AutoUpdate": null,
"CreatedBy": "",
"CreationDate": 0,
"EndpointId": 1,
"EntryPoint": "docker-compose.yml",
"Env": [],
"FromAppTemplate": false,
"GitConfig": null,
"Id": 5,
"IsComposeFormat": false,
"Name": "redis",
"Namespace": "",
"ProjectPath": "/home/prabhat/portainer/data/ce1.25/compose/5",
"ResourceControl": null,
"Status": 1,
"SwarmId": "",
"Type": 2,
"UpdateDate": 0,
"UpdatedBy": ""
},
{
"AdditionalFiles": null,
"AutoUpdate": null,
"CreatedBy": "",
"CreationDate": 0,
"EndpointId": 1,
"EntryPoint": "docker-compose.yml",
"Env": [],
"FromAppTemplate": false,
"GitConfig": null,
"Id": 6,
"IsComposeFormat": false,
"Name": "nginx",
"Namespace": "",
"ProjectPath": "/home/prabhat/portainer/data/ce1.25/compose/6",
"ResourceControl": null,
"Status": 1,
"SwarmId": "",
"Type": 2,
"UpdateDate": 0,
"UpdatedBy": ""
}
],
"teams": [
{
"Id": 1,
"Name": "hello"
}
],
"tunnel_server": {
"PrivateKeySeed": "IvX6ZPRuWtLS5zyg"
},
"users": [
{
"EndpointAuthorizations": null,
"Id": 1,
"Password": "$2a$10$siRDprr/5uUFAU8iom3Sr./WXQkN2dhSNjAC471pkJaALkghS762a",
"PortainerAuthorizations": {
"PortainerDockerHubInspect": true,
"PortainerEndpointGroupList": true,
"PortainerEndpointInspect": true,
"PortainerEndpointList": true,
"PortainerMOTD": true,
"PortainerRegistryInspect": true,
"PortainerRegistryList": true,
"PortainerTeamList": true,
"PortainerTemplateInspect": true,
"PortainerTemplateList": true,
"PortainerUserCreateToken": true,
"PortainerUserInspect": true,
"PortainerUserList": true,
"PortainerUserListToken": true,
"PortainerUserMemberships": true,
"PortainerUserRevokeToken": true
},
"Role": 1,
"TokenIssueAt": 0,
"UserTheme": "",
"Username": "admin"
},
{
"EndpointAuthorizations": null,
"Id": 2,
"Password": "$2a$10$WpCAW8mSt6FRRp1GkynbFOGSZnHR6E5j9cETZ8HiMlw06hVlDW/Li",
"PortainerAuthorizations": {
"PortainerDockerHubInspect": true,
"PortainerEndpointGroupList": true,
"PortainerEndpointInspect": true,
"PortainerEndpointList": true,
"PortainerMOTD": true,
"PortainerRegistryInspect": true,
"PortainerRegistryList": true,
"PortainerTeamList": true,
"PortainerTemplateInspect": true,
"PortainerTemplateList": true,
"PortainerUserCreateToken": true,
"PortainerUserInspect": true,
"PortainerUserList": true,
"PortainerUserListToken": true,
"PortainerUserMemberships": true,
"PortainerUserRevokeToken": true
},
"Role": 1,
"TokenIssueAt": 0,
"UserTheme": "",
"Username": "prabhat"
}
],
"version": {
"DB_UPDATING": "false",
"DB_VERSION": "50",
"INSTANCE_ID": "null"
}
}

View File

@@ -18,8 +18,8 @@ func (store *Store) GetConnection() portainer.Connection {
return store.connection
}
func MustNewTestStore(init, secure bool) (bool, *Store, func()) {
newStore, store, teardown, err := NewTestStore(init, secure)
func MustNewTestStore(init bool) (bool, *Store, func()) {
newStore, store, teardown, err := NewTestStore(init)
if err != nil {
if !errors.Is(err, errTempDir) {
teardown()
@@ -30,7 +30,7 @@ func MustNewTestStore(init, secure bool) (bool, *Store, func()) {
return newStore, store, teardown
}
func NewTestStore(init, secure bool) (bool, *Store, func(), error) {
func NewTestStore(init bool) (bool, *Store, func(), error) {
// Creates unique temp directory in a concurrency friendly manner.
storePath, err := ioutil.TempDir("", "test-store")
if err != nil {
@@ -42,12 +42,7 @@ func NewTestStore(init, secure bool) (bool, *Store, func(), error) {
return false, nil, nil, err
}
secretKey := []byte("apassphrasewhichneedstobe32bytes")
if !secure {
secretKey = nil
}
connection, err := database.NewDatabase("boltdb", storePath, secretKey)
connection, err := database.NewDatabase("boltdb", storePath, []byte("apassphrasewhichneedstobe32bytes"))
if err != nil {
panic(err)
}

View File

@@ -1,15 +0,0 @@
package validate
import (
"github.com/go-playground/validator/v10"
portainer "github.com/portainer/portainer/api"
)
var validate *validator.Validate
func ValidateLDAPSettings(ldp *portainer.LDAPSettings) error {
validate = validator.New()
registerValidationMethods(validate)
return validate.Struct(ldp)
}

View File

@@ -1,61 +0,0 @@
package validate
import (
"testing"
portainer "github.com/portainer/portainer/api"
)
func TestValidateLDAPSettings(t *testing.T) {
tests := []struct {
name string
ldap portainer.LDAPSettings
wantErr bool
}{
{
name: "Empty LDAP Settings",
ldap: portainer.LDAPSettings{},
wantErr: true,
},
{
name: "With URL",
ldap: portainer.LDAPSettings{
AnonymousMode: true,
URL: "192.168.0.1:323",
},
wantErr: false,
},
{
name: "Validate URL and URLs",
ldap: portainer.LDAPSettings{
AnonymousMode: true,
URL: "192.168.0.1:323",
},
wantErr: false,
},
{
name: "validate client ldap",
ldap: portainer.LDAPSettings{
AnonymousMode: false,
ReaderDN: "CN=LDAP API Service Account",
Password: "Qu**dfUUU**",
URL: "aukdc15.pgc.co:389",
TLSConfig: portainer.TLSConfiguration{
TLS: false,
TLSSkipVerify: false,
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateLDAPSettings(&tt.ldap)
if (err == nil) == tt.wantErr {
t.Errorf("No error expected but got %s", err)
}
})
}
}

View File

@@ -1,17 +0,0 @@
package validate
import (
"github.com/go-playground/validator/v10"
)
func registerValidationMethods(v *validator.Validate) {
v.RegisterValidation("validate_bool", ValidateBool)
}
/**
* Validation methods below are being used for custom validation
*/
func ValidateBool(fl validator.FieldLevel) bool {
_, ok := fl.Field().Interface().(bool)
return ok
}

View File

@@ -1,118 +0,0 @@
package demo
import (
"log"
"github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
)
type EnvironmentDetails struct {
Enabled bool `json:"enabled"`
Users []portainer.UserID `json:"users"`
Environments []portainer.EndpointID `json:"environments"`
}
type Service struct {
details EnvironmentDetails
}
func NewService() *Service {
return &Service{}
}
func (service *Service) Details() EnvironmentDetails {
return service.details
}
func (service *Service) Init(store dataservices.DataStore, cryptoService portainer.CryptoService) error {
log.Print("[INFO] [main] Starting demo environment")
isClean, err := isCleanStore(store)
if err != nil {
return errors.WithMessage(err, "failed checking if store is clean")
}
if !isClean {
return errors.New(" Demo environment can only be initialized on a clean database")
}
id, err := initDemoUser(store, cryptoService)
if err != nil {
return errors.WithMessage(err, "failed creating demo user")
}
endpointIds, err := initDemoEndpoints(store)
if err != nil {
return errors.WithMessage(err, "failed creating demo endpoint")
}
err = initDemoSettings(store)
if err != nil {
return errors.WithMessage(err, "failed updating demo settings")
}
service.details = EnvironmentDetails{
Enabled: true,
Users: []portainer.UserID{id},
// endpoints 2,3 are created after deployment of portainer
Environments: endpointIds,
}
return nil
}
func isCleanStore(store dataservices.DataStore) (bool, error) {
endpoints, err := store.Endpoint().Endpoints()
if err != nil {
return false, err
}
if len(endpoints) > 0 {
return false, nil
}
users, err := store.User().Users()
if err != nil {
return false, err
}
if len(users) > 0 {
return false, nil
}
return true, nil
}
func (service *Service) IsDemo() bool {
return service.details.Enabled
}
func (service *Service) IsDemoEnvironment(environmentID portainer.EndpointID) bool {
if !service.IsDemo() {
return false
}
for _, demoEndpointID := range service.details.Environments {
if environmentID == demoEndpointID {
return true
}
}
return false
}
func (service *Service) IsDemoUser(userID portainer.UserID) bool {
if !service.IsDemo() {
return false
}
for _, demoUserID := range service.details.Users {
if userID == demoUserID {
return true
}
}
return false
}

View File

@@ -1,79 +0,0 @@
package demo
import (
"github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices"
)
func initDemoUser(
store dataservices.DataStore,
cryptoService portainer.CryptoService,
) (portainer.UserID, error) {
password, err := cryptoService.Hash("tryportainer")
if err != nil {
return 0, errors.WithMessage(err, "failed creating password hash")
}
admin := &portainer.User{
Username: "admin",
Password: password,
Role: portainer.AdministratorRole,
}
err = store.User().Create(admin)
return admin.ID, errors.WithMessage(err, "failed creating user")
}
func initDemoEndpoints(store dataservices.DataStore) ([]portainer.EndpointID, error) {
localEndpointId, err := initDemoLocalEndpoint(store)
if err != nil {
return nil, err
}
// second and third endpoints are going to be created with docker-compose as a part of the demo environment set up.
// ref: https://github.com/portainer/portainer-demo/blob/master/docker-compose.yml
return []portainer.EndpointID{localEndpointId, localEndpointId + 1, localEndpointId + 2}, nil
}
func initDemoLocalEndpoint(store dataservices.DataStore) (portainer.EndpointID, error) {
id := portainer.EndpointID(store.Endpoint().GetNextIdentifier())
localEndpoint := &portainer.Endpoint{
ID: id,
Name: "local",
URL: "unix:///var/run/docker.sock",
PublicURL: "demo.portainer.io",
Type: portainer.DockerEnvironment,
GroupID: portainer.EndpointGroupID(1),
TLSConfig: portainer.TLSConfiguration{
TLS: false,
},
AuthorizedUsers: []portainer.UserID{},
AuthorizedTeams: []portainer.TeamID{},
UserAccessPolicies: portainer.UserAccessPolicies{},
TeamAccessPolicies: portainer.TeamAccessPolicies{},
TagIDs: []portainer.TagID{},
Status: portainer.EndpointStatusUp,
Snapshots: []portainer.DockerSnapshot{},
Kubernetes: portainer.KubernetesDefault(),
}
err := store.Endpoint().Create(localEndpoint)
return id, errors.WithMessage(err, "failed creating local endpoint")
}
func initDemoSettings(
store dataservices.DataStore,
) error {
settings, err := store.Settings().Settings()
if err != nil {
return errors.WithMessage(err, "failed fetching settings")
}
settings.EnableTelemetry = false
settings.LogoURL = ""
err = store.Settings().UpdateSettings(settings)
return errors.WithMessage(err, "failed updating settings")
}

View File

@@ -11,7 +11,6 @@ import (
"testing"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/internal/testhelpers"
)
const composeFile = `version: "3.9"
@@ -42,8 +41,6 @@ func setup(t *testing.T) (*portainer.Stack, *portainer.Endpoint) {
func Test_UpAndDown(t *testing.T) {
testhelpers.IntegrationTest(t)
stack, endpoint := setup(t)
w, err := NewComposeStackManager("", "", nil)

View File

@@ -3,7 +3,6 @@ package exec
import (
"bytes"
"fmt"
"os"
"os/exec"
"path"
"runtime"
@@ -124,8 +123,6 @@ func (deployer *KubernetesDeployer) command(operation string, userID portainer.U
var stderr bytes.Buffer
cmd := exec.Command(command, args...)
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, "POD_NAMESPACE=default")
cmd.Stderr = &stderr
output, err := cmd.Output()

View File

@@ -56,12 +56,10 @@ const (
TempPath = "tmp"
// SSLCertPath represents the default ssl certificates path
SSLCertPath = "certs"
// SSLCertFilename represents the ssl certificate file name
SSLCertFilename = "cert.pem"
// SSLKeyFilename represents the ssl key file name
SSLKeyFilename = "key.pem"
// SSLCACertFilename represents the CA ssl certificate file name for mTLS
SSLCACertFilename = "ca-cert.pem"
// DefaultSSLCertFilename represents the default ssl certificate file name
DefaultSSLCertFilename = "cert.pem"
// DefaultSSLKeyFilename represents the default ssl key file name
DefaultSSLKeyFilename = "key.pem"
)
// ErrUndefinedTLSFileType represents an error returned on undefined TLS file type
@@ -163,7 +161,7 @@ func (service *Service) Copy(fromFilePath string, toFilePath string, deleteIfExi
}
if !exists {
return errors.New(fmt.Sprintf("File (%s) doesn't exist", fromFilePath))
return errors.New("File doesn't exist")
}
finput, err := os.Open(fromFilePath)
@@ -582,8 +580,8 @@ func (service *Service) wrapFileStore(filepath string) string {
}
func defaultCertPathUnderFileStore() (string, string) {
certPath := JoinPaths(SSLCertPath, SSLCertFilename)
keyPath := JoinPaths(SSLCertPath, SSLKeyFilename)
certPath := JoinPaths(SSLCertPath, DefaultSSLCertFilename)
keyPath := JoinPaths(SSLCertPath, DefaultSSLKeyFilename)
return certPath, keyPath
}
@@ -629,18 +627,6 @@ func (service *Service) CopySSLCertPair(certPath, keyPath string) (string, strin
return defCertPath, defKeyPath, nil
}
// CopySSLCACert copies the specified caCert pem file
func (service *Service) CopySSLCACert(caCertPath string) (string, error) {
toFilePath := service.wrapFileStore(JoinPaths(SSLCertPath, SSLCACertFilename))
err := service.Copy(caCertPath, toFilePath, true)
if err != nil {
return "", err
}
return toFilePath, nil
}
// FileExists checks for the existence of the specified file.
func FileExists(filePath string) (bool, error) {
if _, err := os.Stat(filePath); err != nil {

View File

@@ -7,7 +7,6 @@ import (
"github.com/pkg/errors"
)
// WriteToFile creates a file in the filesystem storage
func WriteToFile(dst string, content []byte) error {
if err := os.MkdirAll(filepath.Dir(dst), 0744); err != nil {
return errors.Wrapf(err, "failed to create filestructure for the path %q", dst)

View File

@@ -108,12 +108,12 @@ func (a *azureDownloader) latestCommitID(ctx context.Context, options fetchOptio
return "", errors.WithMessage(err, "failed to parse url")
}
rootItemUrl, err := a.buildRootItemUrl(config, options.referenceName)
refsUrl, err := a.buildRefsUrl(config, options.referenceName)
if err != nil {
return "", errors.WithMessage(err, "failed to build azure root item url")
return "", errors.WithMessage(err, "failed to build azure refs url")
}
req, err := http.NewRequestWithContext(ctx, "GET", rootItemUrl, nil)
req, err := http.NewRequestWithContext(ctx, "GET", refsUrl, nil)
if options.username != "" || options.password != "" {
req.SetBasicAuth(options.username, options.password)
} else if config.username != "" || config.password != "" {
@@ -131,24 +131,26 @@ func (a *azureDownloader) latestCommitID(ctx context.Context, options fetchOptio
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to get repository root item with a status \"%v\"", resp.Status)
return "", fmt.Errorf("failed to get repository refs with a status \"%v\"", resp.Status)
}
var items struct {
var refs struct {
Value []struct {
CommitId string `json:"commitId"`
Name string `json:"name"`
ObjectId string `json:"objectId"`
}
}
if err := json.NewDecoder(resp.Body).Decode(&refs); err != nil {
return "", errors.Wrap(err, "could not parse Azure Refs response")
}
for _, ref := range refs.Value {
if strings.EqualFold(ref.Name, options.referenceName) {
return ref.ObjectId, nil
}
}
if err := json.NewDecoder(resp.Body).Decode(&items); err != nil {
return "", errors.Wrap(err, "could not parse Azure items response")
}
if len(items.Value) == 0 || items.Value[0].CommitId == "" {
return "", errors.Errorf("failed to get latest commitID in the repository")
}
return items.Value[0].CommitId, nil
return "", errors.Errorf("could not find ref %q in the repository", options.referenceName)
}
func parseUrl(rawUrl string) (*azureOptions, error) {
@@ -234,10 +236,8 @@ func (a *azureDownloader) buildDownloadUrl(config *azureOptions, referenceName s
// scopePath=/&download=true&versionDescriptor.version=main&$format=zip&recursionLevel=full&api-version=6.0
q.Set("scopePath", "/")
q.Set("download", "true")
if referenceName != "" {
q.Set("versionDescriptor.versionType", getVersionType(referenceName))
q.Set("versionDescriptor.version", formatReferenceName(referenceName))
}
q.Set("versionDescriptor.versionType", getVersionType(referenceName))
q.Set("versionDescriptor.version", formatReferenceName(referenceName))
q.Set("$format", "zip")
q.Set("recursionLevel", "full")
q.Set("api-version", "6.0")
@@ -246,8 +246,8 @@ func (a *azureDownloader) buildDownloadUrl(config *azureOptions, referenceName s
return u.String(), nil
}
func (a *azureDownloader) buildRootItemUrl(config *azureOptions, referenceName string) (string, error) {
rawUrl := fmt.Sprintf("%s/%s/%s/_apis/git/repositories/%s/items",
func (a *azureDownloader) buildRefsUrl(config *azureOptions, referenceName string) (string, error) {
rawUrl := fmt.Sprintf("%s/%s/%s/_apis/git/repositories/%s/refs",
a.baseUrl,
url.PathEscape(config.organisation),
url.PathEscape(config.project),
@@ -255,15 +255,12 @@ func (a *azureDownloader) buildRootItemUrl(config *azureOptions, referenceName s
u, err := url.Parse(rawUrl)
if err != nil {
return "", errors.Wrapf(err, "failed to parse root item url path %s", rawUrl)
return "", errors.Wrapf(err, "failed to parse refs url path %s", rawUrl)
}
// filterContains=main&api-version=6.0
q := u.Query()
q.Set("scopePath", "/")
if referenceName != "" {
q.Set("versionDescriptor.versionType", getVersionType(referenceName))
q.Set("versionDescriptor.version", formatReferenceName(referenceName))
}
q.Set("filterContains", formatReferenceName(referenceName))
q.Set("api-version", "6.0")
u.RawQuery = q.Encode()

View File

@@ -28,15 +28,15 @@ func Test_buildDownloadUrl(t *testing.T) {
}
}
func Test_buildRootItemUrl(t *testing.T) {
func Test_buildRefsUrl(t *testing.T) {
a := NewAzureDownloader(nil)
u, err := a.buildRootItemUrl(&azureOptions{
u, err := a.buildRefsUrl(&azureOptions{
organisation: "organisation",
project: "project",
repository: "repository",
}, "refs/heads/main")
expectedUrl, _ := url.Parse("https://dev.azure.com/organisation/project/_apis/git/repositories/repository/items?scopePath=/&api-version=6.0&versionDescriptor.version=main&versionDescriptor.versionType=branch")
expectedUrl, _ := url.Parse("https://dev.azure.com/organisation/project/_apis/git/repositories/repository/refs?filterContains=main&api-version=6.0")
actualUrl, _ := url.Parse(u)
assert.NoError(t, err)
assert.Equal(t, expectedUrl.Host, actualUrl.Host)
@@ -270,17 +270,63 @@ func Test_azureDownloader_downloadZipFromAzureDevOps(t *testing.T) {
func Test_azureDownloader_latestCommitID(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `{
"count": 1,
"value": [
{
"objectId": "1a5630f017127db7de24d8771da0f536ff98fc9b",
"gitObjectType": "tree",
"commitId": "27104ad7549d9e66685e115a497533f18024be9c",
"path": "/",
"isFolder": true,
"url": "https://dev.azure.com/simonmeng0474/4b546a97-c481-4506-bdd5-976e9592f91a/_apis/git/repositories/a22247ad-053f-43bc-88a7-62ff4846bb97/items?path=%2F&versionType=Branch&versionOptions=None"
}
]
"value": [
{
"name": "refs/heads/feature/calcApp",
"objectId": "ffe9cba521f00d7f60e322845072238635edb451",
"creator": {
"displayName": "Normal Paulk",
"url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/ac5aaba6-a66a-4e1d-b508-b060ec624fa9",
"_links": {
"avatar": {
"href": "https://dev.azure.com/fabrikam/_apis/GraphProfile/MemberAvatars/aad.YmFjMGYyZDctNDA3ZC03OGRhLTlhMjUtNmJhZjUwMWFjY2U5"
}
},
"id": "ac5aaba6-a66a-4e1d-b508-b060ec624fa9",
"uniqueName": "dev@mailserver.com",
"imageUrl": "https://dev.azure.com/fabrikam/_api/_common/identityImage?id=ac5aaba6-a66a-4e1d-b508-b060ec624fa9",
"descriptor": "aad.YmFjMGYyZDctNDA3ZC03OGRhLTlhMjUtNmJhZjUwMWFjY2U5"
},
"url": "https://dev.azure.com/fabrikam/7484f783-66a3-4f27-b7cd-6b08b0b077ed/_apis/git/repositories/d3d1760b-311c-4175-a726-20dfc6a7f885/refs?filter=heads%2Ffeature%2FcalcApp"
},
{
"name": "refs/heads/feature/replacer",
"objectId": "917131a709996c5cfe188c3b57e9a6ad90e8b85c",
"creator": {
"displayName": "Normal Paulk",
"url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/ac5aaba6-a66a-4e1d-b508-b060ec624fa9",
"_links": {
"avatar": {
"href": "https://dev.azure.com/fabrikam/_apis/GraphProfile/MemberAvatars/aad.YmFjMGYyZDctNDA3ZC03OGRhLTlhMjUtNmJhZjUwMWFjY2U5"
}
},
"id": "ac5aaba6-a66a-4e1d-b508-b060ec624fa9",
"uniqueName": "dev@mailserver.com",
"imageUrl": "https://dev.azure.com/fabrikam/_api/_common/identityImage?id=ac5aaba6-a66a-4e1d-b508-b060ec624fa9",
"descriptor": "aad.YmFjMGYyZDctNDA3ZC03OGRhLTlhMjUtNmJhZjUwMWFjY2U5"
},
"url": "https://dev.azure.com/fabrikam/7484f783-66a3-4f27-b7cd-6b08b0b077ed/_apis/git/repositories/d3d1760b-311c-4175-a726-20dfc6a7f885/refs?filter=heads%2Ffeature%2Freplacer"
},
{
"name": "refs/heads/master",
"objectId": "ffe9cba521f00d7f60e322845072238635edb451",
"creator": {
"displayName": "Normal Paulk",
"url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/ac5aaba6-a66a-4e1d-b508-b060ec624fa9",
"_links": {
"avatar": {
"href": "https://dev.azure.com/fabrikam/_apis/GraphProfile/MemberAvatars/aad.YmFjMGYyZDctNDA3ZC03OGRhLTlhMjUtNmJhZjUwMWFjY2U5"
}
},
"id": "ac5aaba6-a66a-4e1d-b508-b060ec624fa9",
"uniqueName": "dev@mailserver.com",
"imageUrl": "https://dev.azure.com/fabrikam/_api/_common/identityImage?id=ac5aaba6-a66a-4e1d-b508-b060ec624fa9",
"descriptor": "aad.YmFjMGYyZDctNDA3ZC03OGRhLTlhMjUtNmJhZjUwMWFjY2U5"
},
"url": "https://dev.azure.com/fabrikam/7484f783-66a3-4f27-b7cd-6b08b0b077ed/_apis/git/repositories/d3d1760b-311c-4175-a726-20dfc6a7f885/refs?filter=heads%2Fmaster"
}
],
"count": 3
}`
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(response))
@@ -301,11 +347,19 @@ func Test_azureDownloader_latestCommitID(t *testing.T) {
{
name: "should be able to parse response",
args: fetchOptions{
referenceName: "",
referenceName: "refs/heads/master",
repositoryUrl: "https://dev.azure.com/Organisation/Project/_git/Repository"},
want: "27104ad7549d9e66685e115a497533f18024be9c",
want: "ffe9cba521f00d7f60e322845072238635edb451",
wantErr: false,
},
{
name: "should be able to parse response",
args: fetchOptions{
referenceName: "refs/heads/unknown",
repositoryUrl: "https://dev.azure.com/Organisation/Project/_git/Repository"},
want: "",
wantErr: true,
},
}
for _, tt := range tests {

View File

@@ -82,17 +82,8 @@ func (c gitClient) latestCommitID(ctx context.Context, opt fetchOptions) (string
return "", errors.Wrap(err, "failed to list repository refs")
}
referenceName := opt.referenceName
if referenceName == "" {
for _, ref := range refs {
if strings.EqualFold(ref.Name().String(), "HEAD") {
referenceName = ref.Target().String()
}
}
}
for _, ref := range refs {
if strings.EqualFold(ref.Name().String(), referenceName) {
if strings.EqualFold(ref.Name().String(), opt.referenceName) {
return ref.Hash().String(), nil
}
}

View File

@@ -3,53 +3,49 @@ module github.com/portainer/portainer/api
go 1.17
require (
github.com/Microsoft/go-winio v0.5.1
github.com/Microsoft/go-winio v0.4.17
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535
github.com/aws/aws-sdk-go-v2 v1.11.1
github.com/aws/aws-sdk-go-v2/credentials v1.6.2
github.com/aws/aws-sdk-go-v2/service/ecr v1.10.1
github.com/boltdb/bolt v1.3.1
github.com/coreos/go-semver v0.3.0
github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/docker/cli v20.10.9+incompatible
github.com/docker/docker v20.10.9+incompatible
github.com/fvbommel/sortorder v1.0.2
github.com/fxamacker/cbor/v2 v2.3.0
github.com/g07cha/defender v0.0.0-20180505193036-5665c627c814
github.com/go-git/go-git/v5 v5.3.0
github.com/go-ldap/ldap/v3 v3.1.8
github.com/go-playground/validator/v10 v10.10.1
github.com/gofrs/uuid v4.0.0+incompatible
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/go-cmp v0.5.6
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.7.3
github.com/gorilla/securecookie v1.1.1
github.com/gorilla/websocket v1.5.0
github.com/gorilla/websocket v1.4.2
github.com/hashicorp/golang-lru v0.5.4
github.com/joho/godotenv v1.3.0
github.com/jpillora/chisel v0.0.0-20190724232113-f3a8df20e389
github.com/json-iterator/go v1.1.12
github.com/json-iterator/go v1.1.11
github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c
github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6
github.com/pkg/errors v0.9.1
github.com/portainer/docker-compose-wrapper v0.0.0-20220531190153-c597b853e410
github.com/portainer/docker-compose-wrapper v0.0.0-20220113045708-6569596db840
github.com/portainer/libcrypto v0.0.0-20210422035235-c652195c5c3a
github.com/portainer/libhelm v0.0.0-20210929000907-825e93d62108
github.com/portainer/libhttp v0.0.0-20211208103139-07a5f798eb3f
github.com/portainer/libhttp v0.0.0-20211021135806-13e6c55c5fbc
github.com/rkl-/digest v0.0.0-20180419075440-8316caa4a777
github.com/robfig/cron/v3 v3.0.1
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
github.com/viney-shih/go-lock v1.1.1
go.etcd.io/bbolt v1.3.6
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
k8s.io/api v0.22.5
k8s.io/apimachinery v0.22.5
k8s.io/client-go v0.22.5
k8s.io/api v0.22.2
k8s.io/apimachinery v0.22.2
k8s.io/client-go v0.22.2
software.sslmate.com/src/go-pkcs12 v0.0.0-20210415151418-c5206de65a78
)
@@ -61,42 +57,41 @@ require (
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.0.1 // indirect
github.com/aws/smithy-go v1.9.0 // indirect
github.com/containerd/containerd v1.6.1 // indirect
github.com/containerd/containerd v1.5.7 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.8.0+incompatible // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/evanphx/json-patch v4.11.0+incompatible // indirect
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-asn1-ber/asn1-ber v1.3.1 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.1.0 // indirect
github.com/go-logr/logr v1.2.2 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-logr/logr v0.4.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jpillora/ansi v1.0.2 // indirect
github.com/jpillora/requestlog v1.0.0 // indirect
github.com/jpillora/sizestr v1.0.0 // indirect
github.com/jpillora/ansi v0.0.0-20170202005112-f496b27cd669 // indirect
github.com/jpillora/requestlog v0.0.0-20181015073026-df8817be5f82 // indirect
github.com/jpillora/sizestr v0.0.0-20160130011556-e2ea2fa42fb9 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.1.2 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
@@ -106,21 +101,21 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
google.golang.org/grpc v1.43.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
google.golang.org/appengine v1.6.5 // indirect
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect
google.golang.org/grpc v1.33.2 // indirect
google.golang.org/protobuf v1.26.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c // indirect
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect
k8s.io/klog/v2 v2.9.0 // indirect
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
)

File diff suppressed because it is too large Load Diff

View File

@@ -6,12 +6,12 @@ import (
"encoding/json"
"errors"
"fmt"
"golang.org/x/sync/errgroup"
"io/ioutil"
"net/http"
"time"
portainer "github.com/portainer/portainer/api"
"golang.org/x/sync/errgroup"
)
const (

View File

@@ -9,6 +9,4 @@ var (
ErrUnauthorized = errors.New("Unauthorized")
// ErrResourceAccessDenied Access denied to resource error
ErrResourceAccessDenied = errors.New("Access denied to resource")
// ErrNotAvailableInDemo feature is not allowed in demo
ErrNotAvailableInDemo = errors.New("This feature is not available in the demo version of Portainer")
)

View File

@@ -100,8 +100,7 @@ func (handler *Handler) authenticateInternal(w http.ResponseWriter, user *portai
return &httperror.HandlerError{http.StatusUnprocessableEntity, "Invalid credentials", httperrors.ErrUnauthorized}
}
forceChangePassword := !handler.passwordStrengthChecker.Check(password)
return handler.writeToken(w, user, forceChangePassword)
return handler.writeToken(w, user)
}
func (handler *Handler) authenticateLDAP(w http.ResponseWriter, user *portainer.User, username, password string, ldapSettings *portainer.LDAPSettings) *httperror.HandlerError {
@@ -132,11 +131,11 @@ func (handler *Handler) authenticateLDAP(w http.ResponseWriter, user *portainer.
log.Printf("Warning: unable to automatically add user into teams: %s\n", err.Error())
}
return handler.writeToken(w, user, false)
return handler.writeToken(w, user)
}
func (handler *Handler) writeToken(w http.ResponseWriter, user *portainer.User, forceChangePassword bool) *httperror.HandlerError {
tokenData := composeTokenData(user, forceChangePassword)
func (handler *Handler) writeToken(w http.ResponseWriter, user *portainer.User) *httperror.HandlerError {
tokenData := composeTokenData(user)
return handler.persistAndWriteToken(w, tokenData)
}
@@ -207,11 +206,10 @@ func teamMembershipExists(teamID portainer.TeamID, memberships []portainer.TeamM
return false
}
func composeTokenData(user *portainer.User, forceChangePassword bool) *portainer.TokenData {
func composeTokenData(user *portainer.User) *portainer.TokenData {
return &portainer.TokenData{
ID: user.ID,
Username: user.Username,
Role: user.Role,
ForceChangePassword: forceChangePassword,
ID: user.ID,
Username: user.Username,
Role: user.Role,
}
}

View File

@@ -110,5 +110,5 @@ func (handler *Handler) validateOAuth(w http.ResponseWriter, r *http.Request) *h
}
return handler.writeToken(w, user, false)
return handler.writeToken(w, user)
}

View File

@@ -22,14 +22,12 @@ type Handler struct {
OAuthService portainer.OAuthService
ProxyManager *proxy.Manager
KubernetesTokenCacheManager *kubernetes.TokenCacheManager
passwordStrengthChecker security.PasswordStrengthChecker
}
// NewHandler creates a handler to manage authentication operations.
func NewHandler(bouncer *security.RequestBouncer, rateLimiter *security.RateLimiter, passwordStrengthChecker security.PasswordStrengthChecker) *Handler {
func NewHandler(bouncer *security.RequestBouncer, rateLimiter *security.RateLimiter) *Handler {
h := &Handler{
Router: mux.NewRouter(),
passwordStrengthChecker: passwordStrengthChecker,
Router: mux.NewRouter(),
}
h.Handle("/auth/oauth/validate",

View File

@@ -18,7 +18,6 @@ import (
"github.com/docker/docker/pkg/ioutils"
"github.com/portainer/portainer/api/adminmonitor"
"github.com/portainer/portainer/api/crypto"
"github.com/portainer/portainer/api/demo"
"github.com/portainer/portainer/api/http/offlinegate"
i "github.com/portainer/portainer/api/internal/testhelpers"
"github.com/stretchr/testify/assert"
@@ -50,7 +49,7 @@ func Test_backupHandlerWithoutPassword_shouldCreateATarballArchive(t *testing.T)
gate := offlinegate.NewOfflineGate()
adminMonitor := adminmonitor.New(time.Hour, nil, context.Background())
handlerErr := NewHandler(nil, i.NewDatastore(), gate, "./test_assets/handler_test", func() {}, adminMonitor, &demo.Service{}).backup(w, r)
handlerErr := NewHandler(nil, i.NewDatastore(), gate, "./test_assets/handler_test", func() {}, adminMonitor).backup(w, r)
assert.Nil(t, handlerErr, "Handler should not fail")
response := w.Result()
@@ -87,7 +86,7 @@ func Test_backupHandlerWithPassword_shouldCreateEncryptedATarballArchive(t *test
gate := offlinegate.NewOfflineGate()
adminMonitor := adminmonitor.New(time.Hour, nil, nil)
handlerErr := NewHandler(nil, i.NewDatastore(), gate, "./test_assets/handler_test", func() {}, adminMonitor, &demo.Service{}).backup(w, r)
handlerErr := NewHandler(nil, i.NewDatastore(), gate, "./test_assets/handler_test", func() {}, adminMonitor).backup(w, r)
assert.Nil(t, handlerErr, "Handler should not fail")
response := w.Result()

View File

@@ -9,8 +9,6 @@ import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/adminmonitor"
"github.com/portainer/portainer/api/dataservices"
"github.com/portainer/portainer/api/demo"
"github.com/portainer/portainer/api/http/middlewares"
"github.com/portainer/portainer/api/http/offlinegate"
"github.com/portainer/portainer/api/http/security"
)
@@ -27,17 +25,7 @@ type Handler struct {
}
// NewHandler creates an new instance of backup handler
func NewHandler(
bouncer *security.RequestBouncer,
dataStore dataservices.DataStore,
gate *offlinegate.OfflineGate,
filestorePath string,
shutdownTrigger context.CancelFunc,
adminMonitor *adminmonitor.Monitor,
demoService *demo.Service,
) *Handler {
func NewHandler(bouncer *security.RequestBouncer, dataStore dataservices.DataStore, gate *offlinegate.OfflineGate, filestorePath string, shutdownTrigger context.CancelFunc, adminMonitor *adminmonitor.Monitor) *Handler {
h := &Handler{
Router: mux.NewRouter(),
bouncer: bouncer,
@@ -48,11 +36,8 @@ func NewHandler(
adminMonitor: adminMonitor,
}
demoRestrictedRouter := h.NewRoute().Subrouter()
demoRestrictedRouter.Use(middlewares.RestrictDemoEnv(demoService.IsDemo))
demoRestrictedRouter.Handle("/backup", bouncer.RestrictedAccess(adminAccess(httperror.LoggerHandler(h.backup)))).Methods(http.MethodPost)
demoRestrictedRouter.Handle("/restore", bouncer.PublicAccess(httperror.LoggerHandler(h.restore))).Methods(http.MethodPost)
h.Handle("/backup", bouncer.RestrictedAccess(adminAccess(httperror.LoggerHandler(h.backup)))).Methods(http.MethodPost)
h.Handle("/restore", bouncer.PublicAccess(httperror.LoggerHandler(h.restore))).Methods(http.MethodPost)
return h
}
@@ -65,7 +50,7 @@ func adminAccess(next http.Handler) http.Handler {
}
if !securityContext.IsAdmin {
httperror.WriteError(w, http.StatusUnauthorized, "User is not authorized to perform the action", nil)
httperror.WriteError(w, http.StatusUnauthorized, "User is not authorized to perfom the action", nil)
}
next.ServeHTTP(w, r)

View File

@@ -14,7 +14,6 @@ import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/adminmonitor"
"github.com/portainer/portainer/api/demo"
"github.com/portainer/portainer/api/http/offlinegate"
i "github.com/portainer/portainer/api/internal/testhelpers"
"github.com/stretchr/testify/assert"
@@ -52,7 +51,7 @@ func Test_restoreArchive_usingCombinationOfPasswords(t *testing.T) {
datastore := i.NewDatastore(i.WithUsers([]portainer.User{}), i.WithEdgeJobs([]portainer.EdgeJob{}))
adminMonitor := adminmonitor.New(time.Hour, datastore, context.Background())
h := NewHandler(nil, datastore, offlinegate.NewOfflineGate(), "./test_assets/handler_test", func() {}, adminMonitor, &demo.Service{})
h := NewHandler(nil, datastore, offlinegate.NewOfflineGate(), "./test_assets/handler_test", func() {}, adminMonitor)
//backup
archive := backup(t, h, test.backupPassword)
@@ -75,7 +74,7 @@ func Test_restoreArchive_shouldFailIfSystemWasAlreadyInitialized(t *testing.T) {
datastore := i.NewDatastore(i.WithUsers([]portainer.User{admin}), i.WithEdgeJobs([]portainer.EdgeJob{}))
adminMonitor := adminmonitor.New(time.Hour, datastore, context.Background())
h := NewHandler(nil, datastore, offlinegate.NewOfflineGate(), "./test_assets/handler_test", func() {}, adminMonitor, &demo.Service{})
h := NewHandler(nil, datastore, offlinegate.NewOfflineGate(), "./test_assets/handler_test", func() {}, adminMonitor)
//backup
archive := backup(t, h, "password")

View File

@@ -1,11 +1,9 @@
package customtemplates
import (
"encoding/json"
"errors"
"log"
"net/http"
"os"
"regexp"
"strconv"
@@ -116,8 +114,6 @@ type customTemplateFromFileContentPayload struct {
Type portainer.StackType `example:"1" enums:"1,2,3" validate:"required"`
// Content of stack file
FileContent string `validate:"required"`
// Definitions of variables in the stack file
Variables []portainer.CustomTemplateVariableDefinition
}
func (payload *customTemplateFromFileContentPayload) Validate(r *http.Request) error {
@@ -139,12 +135,6 @@ func (payload *customTemplateFromFileContentPayload) Validate(r *http.Request) e
if !isValidNote(payload.Note) {
return errors.New("Invalid note. <img> tag is not supported")
}
err := validateVariablesDefinitions(payload.Variables)
if err != nil {
return err
}
return nil
}
@@ -173,7 +163,6 @@ func (handler *Handler) createCustomTemplateFromFileContent(r *http.Request) (*p
Platform: (payload.Platform),
Type: (payload.Type),
Logo: payload.Logo,
Variables: payload.Variables,
}
templateFolder := strconv.Itoa(customTemplateID)
@@ -214,8 +203,6 @@ type customTemplateFromGitRepositoryPayload struct {
RepositoryPassword string `example:"myGitPassword"`
// Path to the Stack file inside the Git repository
ComposeFilePathInRepository string `example:"docker-compose.yml" default:"docker-compose.yml"`
// Definitions of variables in the stack file
Variables []portainer.CustomTemplateVariableDefinition
}
func (payload *customTemplateFromGitRepositoryPayload) Validate(r *http.Request) error {
@@ -248,12 +235,6 @@ func (payload *customTemplateFromGitRepositoryPayload) Validate(r *http.Request)
if !isValidNote(payload.Note) {
return errors.New("Invalid note. <img> tag is not supported")
}
err := validateVariablesDefinitions(payload.Variables)
if err != nil {
return err
}
return nil
}
@@ -274,7 +255,6 @@ func (handler *Handler) createCustomTemplateFromGitRepository(r *http.Request) (
Platform: payload.Platform,
Type: payload.Type,
Logo: payload.Logo,
Variables: payload.Variables,
}
projectPath := handler.FileService.GetCustomTemplateProjectPath(strconv.Itoa(customTemplateID))
@@ -291,19 +271,14 @@ func (handler *Handler) createCustomTemplateFromGitRepository(r *http.Request) (
if err != nil {
return nil, err
}
isValidProject := true
defer func() {
if !isValidProject {
if err := handler.FileService.RemoveDirectory(projectPath); err != nil {
log.Printf("[WARN] [http,customtemplate,git] [error: %s] [message: unable to remove git repository directory]", err)
}
}
}()
entryPath := filesystem.JoinPaths(projectPath, customTemplate.EntryPoint)
exists, err := handler.FileService.FileExists(entryPath)
if err != nil || !exists {
isValidProject = false
if err := handler.FileService.RemoveDirectory(projectPath); err != nil {
log.Printf("[WARN] [http,customtemplate,git] [error: %s] [message: unable to remove git repository directory]", err)
}
}
if err != nil {
@@ -314,16 +289,6 @@ func (handler *Handler) createCustomTemplateFromGitRepository(r *http.Request) (
return nil, errors.New("Invalid Compose file, ensure that the Compose file path is correct")
}
info, err := os.Lstat(entryPath)
if err != nil {
isValidProject = false
return nil, err
}
if info.Mode()&os.ModeSymlink != 0 { // entry is a symlink
isValidProject = false
return nil, errors.New("Invalid Compose file, ensure that the Compose file is not a symbolic link")
}
return customTemplate, nil
}
@@ -335,8 +300,6 @@ type customTemplateFromFileUploadPayload struct {
Platform portainer.CustomTemplatePlatform
Type portainer.StackType
FileContent []byte
// Definitions of variables in the stack file
Variables []portainer.CustomTemplateVariableDefinition
}
func (payload *customTemplateFromFileUploadPayload) Validate(r *http.Request) error {
@@ -382,17 +345,6 @@ func (payload *customTemplateFromFileUploadPayload) Validate(r *http.Request) er
}
payload.FileContent = composeFileContent
varsString, _ := request.RetrieveMultiPartFormValue(r, "Variables", true)
err = json.Unmarshal([]byte(varsString), &payload.Variables)
if err != nil {
return errors.New("Invalid variables. Ensure that the variables are valid JSON")
}
err = validateVariablesDefinitions(payload.Variables)
if err != nil {
return err
}
return nil
}
@@ -413,7 +365,6 @@ func (handler *Handler) createCustomTemplateFromFileUpload(r *http.Request) (*po
Type: payload.Type,
Logo: payload.Logo,
EntryPoint: filesystem.ComposeFileDefaultName,
Variables: payload.Variables,
}
templateFolder := strconv.Itoa(customTemplateID)

View File

@@ -31,8 +31,6 @@ type customTemplateUpdatePayload struct {
Type portainer.StackType `example:"1" enums:"1,2,3" validate:"required"`
// Content of stack file
FileContent string `validate:"required"`
// Definitions of variables in the stack file
Variables []portainer.CustomTemplateVariableDefinition
}
func (payload *customTemplateUpdatePayload) Validate(r *http.Request) error {
@@ -54,12 +52,6 @@ func (payload *customTemplateUpdatePayload) Validate(r *http.Request) error {
if !isValidNote(payload.Note) {
return errors.New("Invalid note. <img> tag is not supported")
}
err := validateVariablesDefinitions(payload.Variables)
if err != nil {
return err
}
return nil
}
@@ -132,7 +124,6 @@ func (handler *Handler) customTemplateUpdate(w http.ResponseWriter, r *http.Requ
customTemplate.Note = payload.Note
customTemplate.Platform = payload.Platform
customTemplate.Type = payload.Type
customTemplate.Variables = payload.Variables
err = handler.DataStore.CustomTemplate().UpdateCustomTemplate(customTemplate.ID, customTemplate)
if err != nil {

Some files were not shown because too many files have changed in this diff Show More