Compare commits

...

1036 Commits

Author SHA1 Message Date
ArrisLee
4bf951f1ee oauth auto admin mapping 2021-06-30 00:22:44 +12:00
Hui
3c64fc7786 feat(oauth): update OAuth settings for auto admin population 2021-06-23 15:45:45 +12:00
zees-dev
8902bae7a4 removed redundant swagger comments as they are not applicable 2021-06-14 16:26:38 +12:00
zees-dev
08bcfa284c updated struct to utilise pointer 2021-06-14 16:24:48 +12:00
zees-dev
1345396c8c updated oauth tests 2021-06-14 16:24:48 +12:00
zees-dev
df4da34a63 merge conflct resolution to get project back to working state 2021-06-14 16:24:48 +12:00
zees-dev
e9675400ab udpated oauth team memebrship tests based on updated test store 2021-06-14 16:24:48 +12:00
zees-dev
49691de937 feat(memberships): automatic OAuth team memberships implementation
- fixed merge conflicts
2021-06-14 16:24:48 +12:00
Hui
ef2161abe9 change to EndpointCreationType (#426) 2021-06-14 14:46:08 +12:00
cong meng
c3f8ec2380 feat(k8s): Add the ability to display realtime node metrics in Kubernetes EE-130 (#359)
* feat(k8s): Add the ability to display realtime node metrics in Kubernetes EE-130

* feat(k8s) show observation timestamp instead of real timestamp EE-130

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-06-14 12:44:30 +12:00
Maxime Bajeux
06f62825ee fix(application): fix bad commit (#337) 2021-06-14 11:07:07 +12:00
Chaim Lev-Ari
4cf8082591 fix(app): parse response with null body (#256)
* fix(images): use async await

* fix(images): show correct error when failing import

* style(docker): add comment explaining change
2021-06-11 12:06:44 +12:00
Hui
96d1230461 feat(OAuth): Add SSO support for OAuth EE-390 (#381)
* feat(oauth): add sso, hide internal auth and logout options. (#355)

* feat(DB): Add new migration func for SSO settings EE-613

* feat(publicSettings): public settings response modification for OAuth SSO EE-608 (#357)

* feat(oauth): updated logout logic with logoutUrl. (#365)

* feat(oauth): update new token expiration for OAuth EE-612

* feat(oauth): add internal-auth view. (#358)

* feat(oauth): add internal-auth view.

* feat(oauth): removed unused method.

* feat(oauth): updated oauth settings model

* feat(oauth): updated #auth view with hide internal auth option (#369)

* HideInternalAuth logic update

* feat(oauth): HideInternalAuth logic update

* feat(oauth): internal auth view updates

* feat(oauth): internal auth login issue.

* set SSO to ON by default

* update migrator unit test

* set SSO to true by default for new instance

* prevent applying the SSO logout url to the initial admin user

* set HideInternalAuth to true by default

Co-authored-by: fhanportainer <79428273+fhanportainer@users.noreply.github.com>
Co-authored-by: Felix Han <felix.han@portainer.io>
2021-06-11 10:08:38 +12:00
Richard Wei
07e83d1e6e fix(frontend):fixes the kubernetes endpoint url not saved EE-825 (#397)
Co-authored-by: richard <richard@richards-iMac-Pro.local>
2021-06-11 09:35:58 +12:00
Chaim Lev-Ari
8b01f8681c fix(registry): handle quay registry (#258)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-06-10 12:26:38 +12:00
zees-dev
9c724d4a82 feat(kubernetes/summary): summary of k8s actions upon deploying/updating resources EE-436 (#399)
* feat(kubernetes/summary): summary panel component EE-811 (#388)

* initialised summary panel component, controller and binding

* summary component html, css, expanding-state persistance

* removed redundant scope variable

* - watching for formvalues scope changes
- 1-way data binding
- method descriptions and to-do
- objects setup for configuration output
- template setup to be re-used for summary of other k8s resources

* refactored to enable parallel development

* migrated k8s resource helper functions to their own respective files

* integrated action (create, update, delete) into html template

* configuration summary implementation (#390)

* feat(kubernetes/summary): kubernetes application creation and update summary EE-802 (#396)

* added application resources types

* - added support for oldFormValues to support complex app update summary
- additional app cpu and memory limits
- introduction of summary types - for service support

* initial implementation of app creation and update summary

* comments to applicationService methods to notify future devs to keep summary in sync

* updated comments to outline modified resources in k8s app edit

* pr bugfix to increase readability

* Feat kubernetes namespaces summary EE-801 (#398)

* feat(k8s/summary): show summary for namespace creation and update EE-436/EE-801

* feat(k8s/summary): show the correct article for summary EE-436/EE-801

* feat(k8s/summary): check formValue type in generateResourceSummaryList to avoid unnecessary calculation  EE-436/EE-801

* feat(k8s/summary): cleanup code EE-436/EE-801

* feat(k8s/summary): rename helps.js to helpers.js EE-436/EE-801

* updated comment to be more readable

Co-authored-by: Simon Meng <simon.meng@portainer.io>
Co-authored-by: zees-dev <dev.786zshan@gmail.com>

* feat(k8s/summary): hide summary section if nothing has changed EE-436

* bugfix: returning created resources after update

* fixed incorrect ingress summary bug

* fixed patch based bugs - displaying updates for resources properly

Co-authored-by: cong meng <mcpacino@gmail.com>
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-06-10 10:38:13 +12:00
fhanportainer
099e58d458 fix(aci): fixed aci with persistence or networking issue. (#275) 2021-06-10 01:34:31 +12:00
Alice Groux
a67331f1d4 fix(docker/stack): prevent stack duplication if name already used (#319)
* fix(docker/stack): prevent stack duplication if name already used

* fix(docker/stack): fix parenthesis error

* fix(docker/stack): fix condition for deploy stack button

* fix(docker/stack): add missing helper

* fix(stacks): show containers only for standalone

Co-authored-by: Chaim Lev-Ari <chiptus@gmail.com>
2021-06-08 14:45:35 +12:00
Alice Groux
55e52ee79a feat(k8s): truncate image name in tables (#262)
* feat(k8s): cut image name to 64 chars with truncate filter in all applications datatables

* feat(k8s): add full name on hovering over the image name

Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>
2021-06-04 17:18:02 +12:00
yi-portainer
c42756ae23 Merge branch 'release/2.4' into develop 2021-06-04 12:09:25 +12:00
dbuduev
dbcbef0953 feat(bolt): Add test scaffolding EE-872 (#407) 2021-06-04 11:45:01 +12:00
Hui
1d7ed11462 docs(api): document apis with swagger EE-155 (#326)
* document apis with swagger

* feat(api): introduce swagger

* feat(api): anottate api

* chore(api): tag endpoints

* chore(api): remove tags

* chore(api): add docs for oauth auth

* chore(api): document create endpoint api

* chore(api): document endpoint inspect and list

* chore(api): document endpoint update and snapshots

* docs(endpointgroups): document groups api

* docs(auth): document auth api

* chore(build): introduce a yarn script to build api docs

* docs(api): document auth

* docs(customtemplates): document customtemplates api

* docs(tags): document api

* docs(api): document the use of token

* docs(dockerhub): document dockerhub api

* docs(edgegroups): document edgegroups api

* docs(edgejobs): document api

* docs(edgestacks): doc api

* docs(http/upload): add security

* docs(api): document edge templates

* docs(edge): document edge jobs

* docs(endpointgroups): change description

* docs(endpoints): document missing apis

* docs(motd): doc api

* docs(registries): doc api

* docs(resourcecontrol): api doc

* docs(role): add swagger docs

* docs(settings): add swagger docs

* docs(api/status): add swagger docs

* docs(api/teammembership): add swagger docs

* docs(api/teams): add swagger docs

* docs(api/templates): add swagger docs

* docs(api/users): add swagger docs

* docs(api/webhooks): add swagger docs

* docs(api/webscokets): add swagger docs

* docs(api/stacks): swagger

* docs(api): fix missing apis

* docs(swagger): regen

* chore(build): remove docs from build

* docs(api): update tags

* docs(api): document tags

* docs(api): add description

* docs(api): rename jwt token

* docs(api): add info about types

* docs(api): document types

* docs(api): update request types annotation

* docs(api): doc registry and resource control

* chore(docs): add snippet

* docs(api): add description to role

* docs(api): add types for settings

* docs(status): add types

* style(swagger): remove documented code

* docs(http/upload): update docs with types

* docs(http/tags): add types

* docs(api/custom_templates): add types

* docs(api/teammembership): add types

* docs(http/teams): add types

* docs(http/stacks): add types

* docs(edge): add types to edgestack

* docs(http/teammembership): remove double returns

* docs(api/user): add types

* docs(http): fixes to make file built

* chore(snippets): add scope to swagger snippet

* chore(deps): install swag

* chore(swagger): remove handler

* docs(api): add description

* docs(api): ignore docs folder

* docs(api): add contributing guidelines

* docs(api): cleanup handler

* chore(deps): require swaggo

* fix(auth): fix typo

* fix(docs): make http ids pascal case

* feat(edge): add ids to http handlers

* fix(docs): add ids

* fix(docs): show correct api version

* chore(deps): remove swaggo dependency

* chore(docs): add install script for swag

* merge examples

* go.mod update

* merge validate rules

* remove empty example tag

* swagger anotation format

* swagger annotation update

* clean up go.mod

* update docs prebuild script

* Update porImageRegistry.html

* Update yamlInspector.html

* Update porImageRegistry.html

* Update package.json

* wording change

Co-authored-by: Chaim Lev-Ari <chiptus@users.noreply.github.com>
2021-06-04 09:37:23 +12:00
Alice Groux
100e8ebec2 feat(k8s/applications): reorder placement policies and select mandatory by default (#364) 2021-06-03 13:42:47 +02:00
Chaim Lev-Ari
8e0f681dd3 fix(docker/settings): fetch correct value for allow sysctl (#343)
* fix(docker/settings): fetch correct value for allow sysctl

* fix(endpoints): set sysctl setting for new endpoints
2021-06-03 11:36:50 +02:00
fhanportainer
e9e04cb61c fix(endpoint): skip tls for kube endpoints (#284) 2021-06-03 13:52:25 +12:00
Chaim Lev-Ari
8ab58bc959 chore(dev-build): custom portainer data folder (#255) 2021-06-03 13:35:31 +12:00
Chaim Lev-Ari
aacda65d8c fix(kube): replace remaining resource pool texts (#401) 2021-06-02 11:23:24 +12:00
Dmitry Salakhov
3634b5a10f feat: update docker version to 19.03 (#285)
tested with both linux and windows agents and edge agents
2021-06-02 10:38:53 +12:00
fhanportainer
afecc263a3 fix(templates): fixed type issue in custom template. (#391) 2021-06-02 09:29:31 +12:00
Dmitry Salakhov
d52e38a323 feat: update docker version to 19.03 (#286) 2021-06-02 09:25:06 +12:00
Hui
d6fce4931d use default resource pool (#302) 2021-06-01 17:07:18 +12:00
Chaim Lev-Ari
1437f79458 chore(dev): add debug config for vscode (#4756) (#271)
* chore(dev): add debug config for vscode
* chore(ide): move vscode configs to an example folder
2021-05-31 11:51:51 +12:00
Alice Groux
2fefff0536 feat(docker/service): update the information message about default location of secrets (#293) 2021-05-28 11:06:17 +12:00
fhanportainer
d8ff5a27df fix(template): fixed disabled deploy button EE-812 (#387) 2021-05-25 18:55:37 +02:00
cong meng
29de473e0e fix(frontend) Unable to retrieve namespaces error after updating Kube endpoint EE-775/EE-789 (#380)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-05-24 20:08:54 +12:00
dbuduev
4aa004e4e7 feat(git): Git clone improvements [EE-451] (#371) 2021-05-24 17:27:20 +12:00
cong meng
a6cab5f439 fix(rbac): clean namespace access policies EE-744 (#377)
* fix(rbac) override AccessPolicies by endpint group ID correctly instead by array index  EE-744

* fix(rbac) Iterate users and teams who are existing in NAP EE-744

* fix(rbac) Rename long func name to CleanNAPWithOverridePolicies EE-744

* fix(rbac) cleanup code EE-744

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-05-20 15:06:02 +12:00
Chaim Lev-Ari
aa43d2e7e8 fix(docker/services): create a service webhook (#5052) (#374) 2021-05-18 15:54:47 +12:00
cong meng
54ddb902e4 fix(rbac) Unable to remove an endpoint role from the user when the k8s endpoint is offline EE-736 (#375)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-05-17 11:15:05 +12:00
cong meng
efd973ff63 fix(ACI): At least one team or user should be specified when creating a restricted container in Azure ACI EE-578 (#329)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-05-17 11:06:36 +12:00
Chaim Lev-Ari
d64cc63a96 feat(k8s): UI: replace resourcepool with namespace EE-445 (#333) 2021-05-14 16:03:07 +12:00
yi-portainer
6aefdadc36 * update portainer version
(cherry picked from commit 93f763db1c)
2021-05-13 18:34:48 +12:00
yi-portainer
93f763db1c * update portainer version 2021-05-13 14:59:42 +12:00
cong meng
4837ab6a60 fix(rbac) User previously given access to namespace, can see it when they shouldn't EE-717 (#363)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-05-13 04:39:24 +02:00
dbuduev
81ea206f48 Revert "feat(git): Git clone improvements [EE-451] (#360)" (#366)
This reverts commit 08e3f6ac1a.
2021-05-12 10:44:09 +12:00
Dmitry Salakhov
be4454edc2 fix(namespace): update portainer-config when delete a namespace [EE-681] (#362) 2021-05-11 20:51:07 +12:00
dbuduev
08e3f6ac1a feat(git): Git clone improvements [EE-451] (#360)
* feat(git): update git checkout [EE-630] (#348)

* feat(git): Add Azure DevOps exception [EE-631] (#356)

* feat(git): refactoring git package (#631)

* feat(git): azure parse https url (#631)

* feat(git): unit-test refactoring (#631)

* feat(git): azure parse urls (#631)

* feat(git): extract azure module (#631)

* feat(git): azure service functions (#631)

* feat(git): azure, git refactoring and tests (#631)

* feat(archive): add unzip file tests (#631)

* feat(git): PR review changes (#631)

* feat(git): error handling updates (#631)

* feat(git): error handling updates (#631)

* feat(archive): test refactoring (#631)

Co-authored-by: Dennis Buduev <dennis.b@clubware.co.nz>

* feat(git) remove .git directory (#451)

* feat(git): return git clone error (#630)

Co-authored-by: Dennis Buduev <dennis.b@clubware.co.nz>
2021-05-11 14:57:22 +12:00
Dmitry Salakhov
a748857999 Fix(k8s): user cannot access k8s namespace [EE-629] (#353)
* fix: drop token cache when user updates config map

* tmp

* tmp

* fix: use same instance of token cache aross the app
2021-05-07 14:44:11 +12:00
cong meng
f98ca82bee fix(ACI): ACI UAC breaks when redeploying container with same name asone already existing EE-645 (#346)
* add container existence check

* modify response status code and err message

* return json instead of plain text for err msg

* Update api/http/proxy/factory/azure/containergroup.go

* Update api/http/proxy/factory/azure/containergroup.go

Co-authored-by: ArrisLee <arris_li@hotmail.com>
Co-authored-by: Stéphane Busso <sbusso@users.noreply.github.com>
2021-05-05 20:11:43 +12:00
cong meng
86a7a7820f fix(log): ACI container create and delete is not logged in user activity UI EE-621 (#345)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-05-05 12:51:57 +12:00
zees-dev
432c2e7751 fix(access): homepage accessible by non-admin users (#344) 2021-05-05 11:53:14 +12:00
Alice Groux
b8c6c978b1 fix(docker/service): enable apply change button when user make changes on mounts section (#289) 2021-05-04 21:56:14 +12:00
cong meng
c7bac163c5 fix(uac): EE-173 Access control management via labels not fault tolerant (#314) 2021-05-04 12:40:44 +12:00
Hui
dc86024078 fix(stack): normalize stack name only for libcompose (#301)
* normalize stack name only for libcompose

* reformat and cleanup

Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>
2021-05-03 18:11:34 +02:00
fhanportainer
4444de1971 feat(log-viewer): add ansi color support for logs EE-558 (#331) 2021-05-03 13:56:01 +12:00
Hui
9bb90b0ff3 fix(application): can't update application with persisted data, after the storage option is disabled on cluster (#310)
* fix update application with persisted data

* revert

* revert

Co-authored-by: Maxime Bajeux <max.bajeux@gmail.com>
2021-05-03 12:26:53 +12:00
cong meng
5520585ac9 fix(k8s): Standard user & read-only user can see namespaces without access permissions EE-619 (#341)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-05-02 18:23:37 +12:00
cong meng
3ec649c6c6 feat(endpoint) Update the agent deployment command in the UI to use the new image for the agent EE-601 (#339)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-30 17:44:18 +12:00
Alice Groux
a1bdc99217 feat(docker/services): hide webhook interface (#320) 2021-04-30 15:01:41 +12:00
fhanportainer
769e885492 feat(kube/app): show image pull policy (#307) 2021-04-30 07:51:35 +12:00
Alice Groux
cb0fe58ef4 feat(app): sort environment variables (#290) 2021-04-30 07:11:56 +12:00
cong meng
4799a0a38d feat(home): EE-253 show node count on homepage (#321) 2021-04-29 16:30:34 +12:00
cong meng
7bcadb7dc8 feat(edge) Update the version of agent to 2.4.0 in agent deploy command on the adding edge screen EE-596 (#338)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-29 16:24:46 +12:00
Chaim Lev-Ari
13f921bf0d chore(deps): remove grunt-html2js and grunt-karma (#269)
fix [EE-171]
2021-04-29 15:17:30 +12:00
zees-dev
9887daaded feat(container-stats): introduce container block io stats chart (#327) 2021-04-29 14:43:45 +12:00
Hui
a57ab5ad72 #4374 feat(images): Add link to Docker Hub on container creation page (#4413) (#303)
Add a button next to the image field when creating a new container, which
takes the user to the Docker Hub search page for this image. Version
identifiers are trimmed from the image name to ensure that matching images
will be found.

Co-authored-by: knittl <knittl89+git@googlemail.com>
2021-04-29 14:08:51 +12:00
Alice Groux
341e0418e0 fix(docker/stack): update the content of code editor when switching custom template (#292) 2021-04-29 13:53:06 +12:00
Maxime Bajeux
b1d397e375 feat(k8s/container): realtime metrics (#297) 2021-04-29 13:11:18 +12:00
fhanportainer
f35979c7f5 chore(deps): install core-js@2 (#317) 2021-04-29 12:46:03 +12:00
zees-dev
27ad7d077f fix(customtemplate): Cannot create custom template from uploaded compose file EE-163 (#283) 2021-04-29 11:08:47 +12:00
Hui
5596a3bc99 feat(container): add sysctls setting in the container view EE-43 (#280) 2021-04-29 11:07:48 +12:00
fhanportainer
933177948d fix(snapshot): update snapshot interval (#309) 2021-04-29 09:54:50 +12:00
Dmitry Salakhov
ac4820da9f feat(logs): improved fatal log messages (#281) 2021-04-29 09:23:22 +12:00
cong meng
36d6df7885 fix(rbac): user in 2 teams with mix of endpoint admin and operator has perms of endpoint admin EE-587 (#335)
* fix(rbac) user in 2 teams with mix of endpoint admin and operator has perms of endpoint admin EE-587

* fix(rbac) add unit test for getKeyRole function EE-587

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-28 20:11:51 +12:00
Alice Groux
d97cd56d1f fix(app): app type button on every button with ngf-select (#291) 2021-04-28 17:44:19 +12:00
cong meng
cbc34bdd6d feat(edge): Show the status of the edge agent check-in on the home page dashboard EE-178 (#325) 2021-04-28 16:46:19 +12:00
fhanportainer
81759c4dfc fix(containers): fix layout in small screens (#313) 2021-04-28 16:10:22 +12:00
Chaim Lev-Ari
03d7246b4a fix(build): ignore chardet missing sourcemaps (#4760) (#268) 2021-04-28 13:03:00 +12:00
cong meng
9cc0d780fb fix(home): EE-83 redirect home if edge endpoint is down (#311) 2021-04-28 11:07:59 +12:00
Stéphane Busso
db15482adc fix(logging): Content is not set to [REDACTED] when creating or editing sensitive kube configs EE-580 (#330)
* fix stringData from secrets

* feat(useractivity): log secrets

Co-authored-by: Chaim Lev-Ari <chiptus@gmail.com>
2021-04-28 10:05:41 +12:00
Alice Groux
6c5ea68573 feat(docker/containers): display IP (#288) 2021-04-28 06:43:15 +12:00
Alice Groux
a0f2ab2a2d feat(k8s/ingress): create multiple ingress networks per k8s namespace with a differing config per ingress (#318) 2021-04-28 05:52:27 +12:00
fhanportainer
24d52ca395 feat(datatable): save text filters in session storage (#287) 2021-04-27 15:46:00 +02:00
Alice Groux
e66924271d feat(k8s/application): add the ability to redeploy external applications 2021-04-27 15:51:04 +12:00
fhanportainer
cb6fb3e47b fix(k8s/endpoint): update endpoint URL (#324) 2021-04-27 15:29:38 +12:00
Alice Groux
32b4b9c132 fix(k8s/application): display all environment variables in edition (#294) 2021-04-27 14:27:10 +12:00
cong meng
10a4d5a0e6 feat(k8s) EE-157 Better form validation for Configuration keys (#322)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-27 13:06:17 +12:00
Dmitry Salakhov
7d5641860a fix(docker/services): save the settings of the table for auto refresh (#282) 2021-04-27 12:51:12 +12:00
fhanportainer
e3ae899a5a fix(app/settings): EE-262 update link to template definition docs (#279) 2021-04-27 12:29:03 +12:00
Hui
53a89a173a feat(yaml-inspector): add button to expand/collapse yaml inspector 2021-04-27 12:28:28 +12:00
zees-dev
0cf9bd90c4 fix(service-details): clear volume source when changing type EE-143 (#306)
* fix(service-details): clear volume source when changing type

* fix(services): prevent adding volume without source and target

Co-authored-by: Chaim Lev-Ari <chiptus@users.noreply.github.com>
2021-04-23 20:04:32 +12:00
Hui
0295552a7a fix(stack): show correct error message 2021-04-21 14:47:45 +12:00
yi-portainer
c5488a8fc0 * update portainer version
(cherry picked from commit ef94b69718)
2021-04-16 14:03:12 +12:00
yi-portainer
ef94b69718 * update portainer version 2021-04-16 14:01:18 +12:00
Chaim Lev-Ari
8d53b5c60e fix(stacks): enable compose access to private registries (#264)
* fix(stacks): enable compose access to private registries

* chore(deps): update docker-wrapper lib

* update mod

* Update wrapper lib to rebased PR

* Update wrapper

Co-authored-by: Stéphane Busso <stephane.busso@gmail.com>
2021-04-16 13:14:20 +12:00
Chaim Lev-Ari
3d3bc9b692 fix(api): use docker-compose on windows (#273)
* feat(api): log compose initializtion

* feat(stacks): update docker-compose version

* feat(api): remove logs

* Update library

Co-authored-by: Stéphane Busso <stephane.busso@gmail.com>
2021-04-16 00:30:50 +02:00
cong meng
e6e5885fa2 Feat(rbac): Change migration for rbac operator role EE-226 (#266)
* feat(rbac): EE-226 set db version to 29 other than 30

* feat(rbac): EE-226  avoid a js warning

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-15 20:58:03 +12:00
Chaim Lev-Ari
99a372fb88 feat(useractivity): log user activity for write actions (#229)
* feat(useractivity): introduce backend for useractivity logging (#213)

* refactor(useractivity): move query and logs to base type

* feat(useractivity): cleanup user activity logs

* feat(useractivity): log an activity

* refactor(useractivity): create generic get logs function

* fix(api): hide unused function

* refactor(useractivity): create generic get logs function

* feat(useractivity): get user activity logs

* feat(http/ua): add http get logs handler

* refactor(http/ua): rename logs_list file

* feat(useractivity): fetch logs as csv

* feat(useractivity): save payload as bytes

* style(useractivity): doc the count parameter

* feat(useractivity): introduce UI for user activity logs (#220)

* feat(useractivity): add useractivity page

* feat(useractivity): get logs from server

* feat(useractivity): show logs in datatable

* fix(useractivity): save logs as csv

* feat(useractivity): show logs payload

* feat(useractivity): sort desc by default

* feat(useractivity): parse object

* fix(useractivity): expect base64 payload

* feat(useractivity): show message when missing logs

* feat(useractivity): log api (#215)

* feat(templates): log write methods

* refactor(useractivity): move middleware

* feat(dockerhub): log update docker settings

* feat(edgegroup): log write

* feat(edgejobs): log write request

* feat(useractivity): return bytes to user

* fix(customtemplates): set activity context

* feat(edgestacks): log activities

* feat(endpointgroup): log activities

* feat(endpoint): log write activities

* feat(licenses): log write activities

* feat(registries): log activitites

* feat(resource_control): log user activity

* feat(settings): log update

* feat(stacks): log activity

* feat(tags): log user activitiy

* feat(teammembership): log user activity

* feat(teams): log write activities

* feat(useractivity): get default context

* feat(http/upload): log upload tls

* feat(users): log user activities

* fix(settings): clean payload

* feat(webhook): log user activities

* feat(websocket): log activities

* feat(docker): log write activities

* refactor(useractivity): move log proxy

* feat(azure): log write activity

* refactor(kube): use basic transport for all transports

* feat(kube): log kube activity

* fix(useractivity): parse body

* refactor(kuberenetes): log requests only if success

* refactor(docker): log requests only if success

* refactor(azure): log requests only if success

* feat(gitlab): log activity

* feat(registries): log proxy request

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

* feat(activity-logs): save pagination limit

* feat(useractivity): remove config payload

* fix(docker): log request after success

* refactor(http): move copy body to utils

* feat(kuberentes): remove config values

* feat(useractivity): copy body before request

* fix(useractivity): fix column size

* feat(useractivity): filter json payloads

* refactor(useractivity): log with same logic

* fix(useractivity/csv): export same columns as datatable

* fix(useractivity): replace context with endpoint

* fix(user-activity): rename tables

* feat(endpoint): clear azure key

* feat(stacks): omit empty migrate values

* fix(stacks): add back import

* feat(endpoints): log update settings

* fix(registry): clear password value

* feat(registry): omit update empty value

* fix(registries): don't return from unauthorized azure request

* fix(useractivity): log any payload similar to json

* feat(useractivity): ignoer binary upload

* fix(useractivity): refresh user activity logs

* feat(useractivity): use [REDACTED] for cleared credential (#265)

* feat(docker/services): log force update service

* feat(useractivity): log username when available

* feat(webhooks): remove logging of execute

* refactor(http): replace redacted values

* style(kube): remove commented code

* feat(http/kube): proxy local requests

* feat(useractivity): log patch method

* fix(datatables): use unique filter id

* fix kube settings update

* fix: EE-527 set payload to [REDACTED] when update kube config

* refactor(http/k8s): rename proxy function

* EE-530: a dummy fix of exec activity log for a local kube setup

Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>
Co-authored-by: Hui <arris_li@hotmail.com>
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-15 20:37:29 +12:00
Dmitry Salakhov
37baabe134 EE-292: backup to and restore from s3 (#240)
* EE-384: add endpoint to set auto backup (#224)

* EE-383: add endpoint to fetch backup settings (#231)

* add get backup settings handler
* add api docs desc

* EE-382: restore from s3 (#233)

* EE-381: add GET backup status handler (#234)

* EE-385: Add S3 backup execute handler (#237)

* add s3 backup execute handler

* refactories inside `./api/backup/backup_scheduler.go` and `./api/backup/backup_scheduler.go`

* fix tests

* EE-375: added backup to S3 form

* EE-376: added restore from S3 form

* EE-377: Update Home screen to display last backup run status

* update backup service with back end endpoints.

* restart admin monitor during s3 restores

* use go 1.13

* go 1.13 compatibility

* EE-375: added cron-validator lib

* EE-375: using enum to compare form types

* EE-375: validate cron rule field

* try fix windows build

* EE-375 EE-376 backup and restore forms validation changes

* fix(autobackup): update autobackup settings validation rules (#260)

* fix(autobackup): automate backup to s3 fe update (#261)

* EE-292: fixed typo in property.

* EE-292: updated auto backup front end validation.

* EE-292: updated lib to validate cron rule in front end

* fix dependencies

* bumped libcompose version

Co-authored-by: Hui <arris_li@hotmail.com>
Co-authored-by: Felix Han <felix.han@portainer.io>
Co-authored-by: fhanportainer <79428273+fhanportainer@users.noreply.github.com>
2021-04-15 12:12:53 +12:00
Alice Groux
19b8117903 feat(k8s/configuration): rename add ingress button and changed information text (#139) 2021-04-15 11:00:14 +12:00
fhanportainer
2f3b64a742 fix(app): fixed browse button should not be showing for volumes in local endpoint (#232) 2021-04-15 10:59:11 +12:00
LP B
aec5356a0c fix(k8s/cluster): missing params in configureController (#270) 2021-04-15 10:51:27 +12:00
LP B
eca9e04c20 fix(k8s/resource-pool): unusable RP access management (#153)
* fix(k8s/resource-pool): unusable RP access management

* style(k8s): remove unused vars introduced by #194
2021-04-15 10:35:19 +12:00
cong meng
1b9a7d2f52 fix(registry): EE-387 can not browse proget registry (#236)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-13 15:34:59 +02:00
Hui
7666d32e97 EE-367: update liblicense version number (#248)
* update liblicense version number and minor test file fix

* revert test file fix
2021-04-13 16:12:33 +12:00
Maxime Bajeux
7d3790fc18 feat(custom-templates): switching a template to standalone makes it disappear in swarm mode (#219) 2021-04-13 13:14:50 +12:00
Chaim Lev-Ari
39a01cda29 fix(kube/config): show used key warning when needed (#254)
* feat(k8s/config): disable edit used config keys (#4754)

* feat(k8s/config): tag used data keys

* feat(k8s/config): disabled edit of used data keys

* fix(kube/config): show used key warning when needed (#4890)

fix [CE-469]
- recalculate duplcate keys when they are changed
- show used warning on duplicate keys
2021-04-13 02:18:28 +02:00
Alice Groux
915bb3ea78 feat(app) EndpointProvider fallback on URL EndpointID when no endpoint is selected (#239) 2021-04-13 12:10:56 +12:00
cong meng
aeadb5c375 fix(k8s): EE-354 Unable to use advanced deployment feature on agent and Edge agent endpoints (#194)
* fix(k8s): EE-354 Unable to use advanced deployment feature on agent and Edge agent endpoints

* fix(k8s): EE-354 enable advance deploy UI

* fix(k8s): EE-354 use the v2 version of agent api instead of v3

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-12 15:34:33 +02:00
Hui
e48b6940e7 fix(test): Use connection.DB (#253) 2021-04-12 12:49:46 +12:00
cong meng
6eb3dfd3c2 feat(ACI): EE-261 Add RBAC to ACI (#226)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-09 02:20:33 +02:00
cong meng
4682056058 Fix EE-471 Add createAdministratorFlow back and fix some typo and warnings (#242)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-09 09:11:37 +12:00
Chaim Lev-Ari
2fb60a29de style(proxy): fix function name (#243) 2021-04-09 09:02:32 +12:00
cong meng
edb05e6e00 feat(ACI): EE-273 add UAC to ACI (#222)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-08 10:46:04 +12:00
Chaim Lev-Ari
b8ecadb314 feat(useractivity): introduce auth logs (#203) 2021-04-07 16:54:07 +12:00
Dmitry Salakhov
e15b908983 Feat(backup): add the ability to backup and restore portainer from file [EE-279] (#204)
* EE-319: backup endpoint (#193)

* feat(backup):
* add an orbiter to block writes while backup
* add backup handler
* add an ability to tar.gz a dir
* add aes encryption support

* EE-320: restore endpoint (#196)

* feat(backup):
* add restore handler
* re-init system state after restore

* feat(backup): Update server to respect readonly lock (#199)

* feat(backup): EE-322 Add backup and restore screen (#198)

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

* name archive as portainer-backup_yyyy-mm-dd_hh-mm-ss

* backup custom templates and edge jobs

* restart http and proxy servers after restore to re-init internal state

* feat(backup): EE-322 hide password field if password protect toggle is off

* feat(backup): EE-322 add tooltip for password field of restore backup

* feat(backup): EE-322 wait for backend restart after restoring

* Shutdown background go-routines

* changed restore err message when cannot extract

* fix: symlinks are ignored from backups

* replace single admin check with a restartable monitor (#238)

* clean log

Co-authored-by: Maxime Bajeux <max.bajeux@gmail.com>
Co-authored-by: cong meng <mcpacino@gmail.com>
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-06 15:41:41 +12:00
cong meng
f9cf76234f feat(rbac): EE-226 Add a new RBAC "Operator" Role (#191)
* feat(rbac): EE-226 Add a new RBAC "Operator" Role

* feat(rbac): EE-226 prioritize Operator after EndpointAdmin and before Helpdesk

* feat(rbac): EE-226 access viewer shows incorrect effective role after introduce of Operator

* feat(rbac): EE-226 show roles order by priority other than name

* feat(rbac): EE-226 remove OperationK8sVolumeDetailsW authorization from operator role

* feat(rbac): EE-226 always increase bucket next sequence when create a role

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-04-06 11:34:54 +12:00
Chaim Lev-Ari
590755071f chore(deps): fix /x/sys version (#217)
closes [EE-429]
2021-04-05 23:14:11 +02:00
fhanportainer
6e8208cea8 fix(container): fixed pull latest image toggle missing on service update and container recreate modal (#235) 2021-04-01 11:01:08 +13:00
cong meng
0eec606ebe feat(authentication): EE-73 Rename all usernames to lowercase (#228)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-03-29 19:09:17 +02:00
fhanportainer
efd9c4c5e5 feat(app): EE-353 remove the version available check (#216)
* feat(app): EE-353 remove the version available check

* feat(app): EE-353 revert code indentation
2021-03-24 23:29:49 +01:00
cong meng
1c938516ee Feat(docker): relocate docker features security settings to be available per endpoint EE-131 (#209)
* feat(docker) EE-131 relocate the Docker features/security settings to be available per endpoint

* feat(docker) EE-131 allow endpoint admin role user to update endpoint settings

* feat(docker) EE-131 populate volume browsing authorizations to user endpoint authorizations when user toggle the setting of volume management for non-administrators

* feat(docker) EE-131 remove parameter volumeBrowsingAuthorizations from all DefaultEndpointAuthorizationsForxxx functions

* feat(docker) EE-131 fix a layout bug of the browse button

* feat(ACI): EE-273 move migrator of 27 into migrate_dbversion26.go

* feat(docker) EE-131 in container creation view, show the privileged mode toggle if cureent user is admin or endpoint admin

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-03-24 23:10:10 +01:00
Chaim Lev-Ari
65028ed96f feat(stacks): scope stack names to endpoint (#4520) (#212)
* refactor(stack): create unique name function

* refactor(stack): change stack resource control id

* feat(stacks): validate stack unique name in endpoint

* feat(stacks): prevent name collision with external stacks

* refactor(stacks): move resource id util

* refactor(stacks): supply resource id util with name and endpoint

* fix(docker): calculate swarm resource id

* feat(stack): prevent migration if stack name already exist

* feat(authorization): use stackutils
2021-03-24 16:40:25 +13:00
Maxime Bajeux
914476618d feat(configurations): Review UI/UX configurations (#184)
* feat(configurations): Review UI/UX configurations

* fix(configurations): remove duplicate lines

* fix(configurations): fix merge errors

* fix(configuration): parse empty configuration as empty string yaml instead of {}
2021-03-23 20:01:25 +01:00
Maxime Bajeux
ceda8b1975 fix(pods): import missing pod converter (#207) 2021-03-22 17:08:45 +01:00
Chaim Lev-Ari
78cf608990 feat(compose): add docker-compose wrapper (#161)
* 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>

* refactor(stacks): use compose library

* refactor(stacks): remove utils

* chore(deps): pin docker-compose-wrapper

* chore(build): simplify docker-compose build

* chore(build): remove ps compose script

* chore(deps): update docker-compose-wrapper

* fix(compose): close proxy after command

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>
2021-03-21 22:38:45 +01:00
cong meng
0df3909909 fix(docker/stack-details): do not display editor tab for external stack (ee-150) (#174)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-03-18 23:14:32 +01:00
Chaim Lev-Ari
55205efe44 chore(plop): use templates as in style guide (#197)
* chore(plop): use templates as in style guide

fix [CE-483]

* chore(plop): export component and add to module
2021-03-19 09:07:14 +13:00
Maxime Bajeux
fa124b4fbe feat(k8s/applications): exposed naked pods as applications (#162) 2021-03-16 22:23:57 +01:00
Maxime Bajeux
0eda4ff41d fix(configs): fix error with binary file (#164) 2021-03-12 23:26:11 +01:00
cong meng
b401ab5081 fix(registries): update password only when not empty (ee-138) (#175)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-03-12 22:27:41 +01:00
yi-portainer
0cf7e6f2eb * update version to 2.0.2 2021-03-12 10:48:50 +13:00
cong meng
0f67a71da2 fix(frontend) unable to retrieve config map error when trying to manage newly created resource pool (ee-151) (#170)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-03-08 00:13:25 +01:00
Maxime Bajeux
6767d19c2c fix(k8s): Can't create kubernetes resources with a username longer than 63 characters (#172) 2021-03-05 18:44:37 +01:00
cong meng
89af2b71e4 fix(frontend): revalidate configuration name when change resource pool (ee-85) (#158)
* fix(frontend): revalidate configuration name when change resource pool (ee-85)

* fix(front-end): EE-85 fixed the issue with the form validation in the Configuration creation view

Co-authored-by: Simon Meng <simon.meng@portainer.io>
Co-authored-by: Felix Han <felix.han@portainer.io>
2021-03-04 12:04:48 +01:00
cong meng
3809ce1546 fix(k8s/application): transform username to be dns compliant (ee#123) (#136)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-03-04 12:12:55 +13:00
cong meng
3398cbf279 fix(k8s): unable to apply a note to a pod (ee-128) (#177)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-03-03 22:37:15 +01:00
Chaim Lev-Ari
27870be241 feat(k8s/advanced-deployment): update extra information message when kubernetes type is selected (#4542) (#138)
Co-authored-by: Alice Groux <alice.grx@gmail.com>
2021-03-03 20:15:47 +01:00
Alice Groux
c4ffaa4da2 feat(applications/ports-mapping): load balancer link expand only if item length > 1 (#148) 2021-03-03 19:51:53 +01:00
Alice Groux
14550db3b5 feat(k8s/application): validate load balancer ports inputs (#152) 2021-03-03 19:26:22 +01:00
Chaim Lev-Ari
92d5eba499 feat(service): clear source volume when change type (#4627) (#171)
* feat(service): clear source volume when change type

* feat(service): init volume source to the correct value
2021-03-03 15:47:49 +01:00
cong meng
31dcf031f3 chore(webpack): add source maps (EE-37) (#167)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-03-02 21:46:13 +01:00
Alice Groux
61c7379312 feat(docker/network): rename restrict external access to the network label (#141) 2021-03-02 11:30:53 +01:00
Alice Groux
ff08fffdce feat(k8s/advanced-deployment): introduce advanced deployment panel to each resource list view (#181) 2021-03-01 18:19:11 +01:00
Maxime Bajeux
aa9cb52575 fix(frontend): add a key to existing used configuration won't throw error anymore on using-app edition (#154)
Application edit page initializes the overridenKeyType of new added configuration key to NONE so that the user can select how to load it
2021-03-01 17:57:31 +01:00
Maxime Bajeux
5bb43432b0 fix(frontend): override configuration keys disappear (#186) 2021-03-01 16:15:08 +01:00
cong meng
b17d296783 fix(frontend): Resource pool 'created' attribute is showing the time you view it at not actual creation time (EE-90) (#166)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-03-01 15:56:21 +01:00
Alice Groux
006d19cd63 feat(app/images): in advanced mode, remove tooltip and add information message (#150) 2021-03-01 15:39:27 +01:00
Alice Groux
a0001305cc feat(app/logs): add download button on logs views (#151) 2021-02-28 21:14:22 +01:00
cong meng
e71fc3bb0e fix(service): set volume source to the correct value (ee-132) (#178)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-02-28 20:19:50 +01:00
Alice Groux
766e865bd2 feat(k8s/configuration): save the owner when updating the configuration (#142) 2021-02-27 23:44:00 +01:00
Dmitry Salakhov
880755125b feat(volumes): show volume access policy (#176) 2021-02-27 11:28:52 +01:00
Alice Groux
dc19061c97 feat(k8s/sidebar): accessing cluster steup not expand endpoint sidebar (#149) 2021-02-26 23:20:26 +01:00
Alice Groux
d04cf56f37 fix(k8s/node): sort labels (#146) 2021-02-26 22:57:15 +01:00
Alice Groux
85cc619dc6 feat(k8s/configuration): add extra information panel when creating a sensitive configuration (#143) 2021-02-26 22:36:15 +01:00
Alice Groux
1b432ad1af feat(k8s/application): refreshing yaml panel doesn't change the selected panel (#147) 2021-02-26 22:05:38 +01:00
Alice Groux
62fe32fe31 feat(app/endpoint): start Portainer without endpoint (#180) 2021-02-26 18:05:30 +01:00
Alice Groux
4ee52a5062 feat(k8s/datatables): reduce size of collapse/expand column for stacks datatable and storage datatable (#145) 2021-02-26 12:14:45 +01:00
Alice Groux
1d50068003 feat(k8s/configuration): rename create entry file button (#144) 2021-02-26 11:57:37 +01:00
Maxime Bajeux
4ceae3a43c fix(frontend): cannnot access configuration details view containing binary data (#163) 2021-02-26 11:35:45 +01:00
Alice Groux
e78756ccfa feat(docker/volumes): add confirmation modal before deleting volumes (#140) 2021-02-26 03:05:57 +01:00
cong meng
d618d05ee1 fix(stack): stacks created via API are incorrectly marked as private with no owner (ee#74) (#156)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-02-26 01:16:18 +01:00
Chaim Lev-Ari
401a471748 feat(k8s/application): review application creation warning style (#4613) (#159)
Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
2021-02-25 16:54:20 +01:00
cong meng
74f3fb0ba2 feat(login): de-emphasize internal login when oauth enabled (ee-70) (#155)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-02-25 16:19:48 +01:00
cong meng
0c20e788f2 fix(style): shift button position in stack details (ee-135) (#168)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-02-25 16:10:01 +01:00
Chaim Lev-Ari
1cbda51517 feat(image-details): Show labels in images datatable (#4287) (#137)
* feat(images): show labels in images datatable

* move labels to image details view

Co-authored-by: DarkAEther <30438425+DarkAEther@users.noreply.github.com>
2021-02-25 16:04:49 +01:00
Chaim Lev-Ari
924bfdee2a feat(docker/stacks): introduce date info for stacks (#182)
* 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>
2021-02-25 15:59:38 +01:00
cong meng
7549ae2c11 fix(state): check validity of state (ee-77) (#157)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2021-02-23 20:10:01 +01:00
Chaim Lev-Ari
fd0c6ea868 #4470 fix(stack): fix a display issue with the stack editor tab. (#4543) (#160)
Co-authored-by: aravind-korada <70788131+aravind-korada@users.noreply.github.com>
2021-02-23 20:04:44 +01:00
yi-portainer
c3f82f51c9 * update version to 2.0.1
(cherry picked from commit 5a784906db76f01461430489bba19ede71aefb93)
2021-02-22 19:10:13 +13:00
Yi Chen
2d6c96a89d * revert docker linux to versioon 18.09.3 (#188)
(cherry picked from commit 37c9dc7d497b4e1a440de14f6998f6616faa417f)
2021-02-22 16:01:07 +13:00
itsconquest
86c378b561 fix(build): fix kubectl download script (#187) 2021-02-19 14:31:43 +13:00
Stéphane Busso
c8f18adfc3 Fix(build): docker compose binary download partial backport (#185) 2021-02-17 09:01:48 +13:00
Steven Kang
a761412bd9 feat(build): introduce buildx (#173)
* feat(build): introduce buildx

* feat(build): excluded compose v3

* feat(build): excluded compose v3

* feat(build): revert back the Docker binary for Windows

* * fix liblicense url override

Co-authored-by: yi-portainer <yi.chen@portainer.io>
2021-02-15 09:47:14 +13:00
Stéphane Busso
b0f7dee463 fix(license): default license server url (#135)
* fix default license server url

* Add azure scripts

* Add ldflags to crossplatform builder
2021-01-26 10:01:18 +13:00
itsconquest
7690a1c894 feat(testing): add missing docker rbac asserts (#133) 2020-12-09 14:08:53 +13:00
itsconquest
461bc9b931 Feat cypress rbac tests (#132)
* feat(testing): bump cypress version

* feat(testing): bring changes from intial PR + helpers

* feat(testing): add kubernetes rbac asserts

* feat(testing): cleanup from previous changes

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2020-12-09 12:17:07 +13:00
Chaim Lev-Ari
06fe256f40 fix(app): remove ghost pages (#131)
* fix(app): remove timeout

* style(app): remove comments

* fix(app): remove async from hook which cause blink

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2020-12-03 17:42:14 +13:00
Yi Chen
92d597608e fix(RBAC) adding/removing teams into namespace causing error (#129)
* * handle teams been added or removed in the resource pool
* do not delete role bindings but just remove the user subject

* * fix missing rolemap

* * revert the role bindings changes (not the cause of the issue)

* * fix token cache cleaning endpoint tokens
2020-12-02 20:38:09 +13:00
Stéphane Busso
5e8e6d2821 chore(license): Update liblicense (#130) 2020-12-02 14:43:31 +13:00
Stéphane Busso
d46844fa7c Override license server (#128) 2020-12-02 09:38:52 +13:00
Yi Chen
f6824ce11c - remove rbac debug statements (#126) 2020-12-01 22:37:13 +13:00
Stéphane Busso
5f9ece92ae fix(board): Set license validation every day fixes#117 (#47) 2020-12-01 22:36:35 +13:00
Anthony Lapenna
674d20bfb9 feat(docker/dashboard): wrap dashboard elements in div (#127) 2020-12-01 22:27:36 +13:00
cong meng
50bd34632d #220 fix(frontend): reenable license cache with 30s timeout and move license checking out of router hook (#124)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2020-12-01 20:40:23 +13:00
Stéphane Busso
e316a5ebe1 fix(license): Fix license expiration inconsistency with displayed date (#111)
* fix(license): Fix license expiration  inconsistency with displayed date

* Fix inconsistent expiration

* Use liblicense expiration compute

* wip

* Use db for expiresAt in license detailed view

* Fix date differences
2020-12-01 17:39:37 +13:00
Yi Chen
db9a1826e5 * fix nil user or team access in edge endpoint (#125) 2020-12-01 15:27:26 +13:00
Yi Chen
02b1ccd521 fix(RBAC) remove role/cluster role bindings when user is deleted (#120)
* * partially ignore errors during user deletion
* collect all errors during user deletion
* remove role/cluster role bindings when empty

* + update resource pool access endpoint
* remove bindings when user is removed from resource pool
* remove token cache when user is added to the resource pool

* - remove delete tokens endpoint
* use actual TriggerUserAuthUpdate

* * fix comments

* * improve error returns
2020-12-01 11:45:49 +13:00
Yi Chen
d4929f06f8 fix(RBAC) refresh user token when operating on endpoints, namespaces, users, teams and memberships (#117)
* * refresh user auth when operating endpoint, team, user and membership

* + adding delete token endpoint
* remove tokens when auth config map is changed

* feat(rbac): add warning messages in the UI

* feat(endpoint): update access warnings

* * fix delete tokens api url

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-11-30 21:15:52 +13:00
Anthony Lapenna
6a31ef1f12 feat(endpoint): update agent instructions (#119)
* feat(endpoint): update agent instructions

* feat(endpoint): update Edge script name
2020-11-30 18:51:37 +13:00
Stéphane Busso
fc5b5368f1 fix(settings): Fix portainer fail to start when missing settings (#123) 2020-11-30 18:39:29 +13:00
Anthony Lapenna
e3b38d0b0a fix(docker/resourcecontrol): fix an issue with Docker resource deletion (#121) 2020-11-30 17:07:46 +13:00
Yi Chen
05cd7094a5 fix(RBAC): authorize advanced deployment (#116)
* * removed authorization in stack deployment, will let k8s handling it

* * removed unused import

* + OperationK8sApplicationsAdvancedDeploymentRW for user
* check namespace authorization in k8s stack deployment endpoint

* - remove OperationK8sApplicationsAdvancedDeploymentRW from user
2020-11-30 13:02:05 +13:00
Maxime Bajeux
5cdcbbc604 fix(rbac): In the application details view, for a non admin user there is a link to the node details view (#118) 2020-11-27 14:34:16 +13:00
Maxime Bajeux
f717cf3eda fix(rbac): Errors thrown in cluster view for standard & readonly users (#114)
* fix(rbac): Errors thrown in cluster view for standard & readonly users

* Revert "fix(rbac): Errors thrown in cluster view for standard & readonly users"

This reverts commit 400016314c3c0f9b22880ede10e3b2d2897c0363.

* * block the loading of nodes and endpoints if not authorized with K8sClusterNodeR

Co-authored-by: yi-portainer <yi.chen@portainer.io>
2020-11-27 14:13:05 +13:00
Maxime Bajeux
7254703449 fix(rbac): Endpoint admin cannot access the cluster setup view (#112)
* fix(rbac): Endpoint admin cannot access the cluster setup view

* * allow endpoint admin to update k8s cluster setup in endpoint

* * make sure a user token is issued first

* fix(rbac): allow admin to update cluster setup

Co-authored-by: yi-portainer <yi.chen@portainer.io>
2020-11-27 14:12:46 +13:00
Maxime Bajeux
8fed4181ed fix(rbac): Error thrown in the node details view for the helpdesk user (#113) 2020-11-26 22:20:52 +13:00
Anthony Lapenna
249b8762f8 fix(k8s/resourcepool): fix missing YAML for resource pool (#109) 2020-11-26 22:16:10 +13:00
cong meng
93f112672e feat(frontend/k8s): add a confirmation modal before deleting one or more application or configuration (#104)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2020-11-26 22:15:44 +13:00
Maxime Bajeux
414e62503b fix(rbac): forbidden view access (#101)
* fix(rbac): Not enforcing on backend for resource creation, application edit and console log operations of users that this should be prevented for

* + k8s access user namespaces policy
+ debug logs
* fix multiple authorization calculation issues

* * use endpoint role rather than user role for calculating authorizations

* * fix namespace role binding

* * check user authorization in k8s pod exec

* * fix some of the logging messages

Co-authored-by: yi-portainer <yi.chen@portainer.io>
2020-11-26 11:30:36 +13:00
Chaim Lev-Ari
9a16af37af fix(router): block route if license is invalid (#90)
* feat(router): add transition guard for init route

* feat(router): check if license is valid between routes

* style(app): change order of config and run

* feat(bouncer): block non admins from using without license

* style(bouncer): add comment about license validation
2020-11-26 09:35:40 +13:00
Chaim Lev-Ari
9dbe6d9474 feat(license): count standalone nodes (#102)
* feat(license): count standalone nodes

* refactor(http/status): return maximum
2020-11-26 09:33:54 +13:00
cong meng
ec327411b7 fix(frontend): add the url for buy/renew license button (#110)
Co-authored-by: Simon Meng <simon.meng@portainer.io>
2020-11-26 09:05:38 +13:00
Stéphane Busso
ab796b6896 chore(license): update license package to manage expiration date (#108) 2020-11-25 17:42:11 +13:00
xAt0mZ
cb90635016 fix(endpoint): hide kubernetes edge/agent instructions for windows (#107)
* fix(endpoint): hide kubernetes edge/agent instructions for windows

* feat(endpoint): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-11-25 08:26:56 +13:00
xAt0mZ
2e2d635f6e fix(k8s/application): transform username to be dns compliant (#106) 2020-11-24 14:10:47 +13:00
Alice Groux
fe66252df7 fix(k8s/storageclass): hide disabled storage options for standard users and readonly users (#105) 2020-11-24 14:00:06 +13:00
Yi Chen
8f66414be9 Remove the cache of kcli with edge proxy (#103)
* * removes kube client cache when edge proxy is removed

* + added logging when failed retrieving k8s service account token

* * take out reusable code
2020-11-24 13:26:15 +13:00
cong meng
2378d4cc9d fix(frontend): show failing placement details for endpoint-admin and helpdesk users (#100)
* fix(frontend): show failing placement details for endpoint-admin and helpdesk users

* fix(frontend): add excludeAuthorization directive to determine endpoint-admin and helpdesk users

* fix(k8s/rbac): add OperationK8sApplicationErrorDetailsR authorization for endpoint-admin and helpdesk users

Co-authored-by: Simon Meng <simon.meng@portainer.io>
2020-11-23 21:51:22 +13:00
Chaim Lev-Ari
44fa68407d fix(licenses): prevent removal of last valid license (#89)
* fix(licenses): prevent removal of last valid license

* * add back the logic that prevent the last license been removed, whether valid or not.

* Revert "* add back the logic that prevent the last license been removed, whether valid or not."

This reverts commit 389b5f8985bf543821cab02ad3252d75ef46ccee.

Co-authored-by: yi-portainer <yi.chen@portainer.io>
2020-11-21 16:36:50 +13:00
Stéphane Busso
428ac54b08 fix(license): better error message when login with no valid license (#99)
* fix(license): better error message when login with no valid license

* add authenticateOAuth
2020-11-21 08:37:48 +13:00
xAt0mZ
911898371b feat(k8s/applications): disable advanced deployment on agent / edge agent endpoints (#95) 2020-11-20 15:57:57 +13:00
Stéphane Busso
d41676ec02 fix(license): update liblicense with invalid message when login 2020-11-20 15:50:56 +13:00
Stéphane Busso
0dacb828b8 fix(license): License Expire Message (#98) 2020-11-20 15:37:23 +13:00
Stéphane Busso
4897f3a87c fix(portainer): Remove the version update notifier on the sidebar in BE (#96) 2020-11-20 15:36:55 +13:00
Alice Groux
9dcc76b218 fix(k8s/application): improve ux for instance count input (#93)
* fix(k8s/application): improve ux for instance count input in creation/edition application

* fix(k8s/application): improve validation on persisted folder size and instance count for isolated applications

* feat(k8s/application): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-11-20 15:27:40 +13:00
Stéphane Busso
faa04c188b feat(bolt/backup): backup and restore db for migration and edition upgrades (#87)
* refactor backup

Update upgrade texts

* Restore Failed Upgrade to EE to initial CE version

* Store version before upgrading

* Check rollback command line

* Fix version display

* Update template url only for CE 1.xx

* Fix comments

* revert go modules

* remove duplicate migration

* remove unused files
2020-11-20 12:40:01 +13:00
Stéphane Busso
7da5336158 fix(license): remove license cache (#94) 2020-11-20 12:18:37 +13:00
Alice Groux
563c1405d5 fix(k8s/node): hide taints section for helpdesk users if no taints available (#92) 2020-11-20 09:26:21 +13:00
Maxime Bajeux
597397abfc fix(resource-pool): Invalid resource pool display for a resource pool with a load balancer quota set to 0 (#91) 2020-11-20 09:25:53 +13:00
Chaim Lev-Ari
febc77933f fix(datatable): remove width from company column (#88)
* fix(datatable): remove width from company column

* fix(licenses): limit size of small cols
2020-11-20 09:20:26 +13:00
Maxime Bajeux
2460dfe6dc fix(team): deleting a team throws error object not found in database (#85) 2020-11-19 19:34:04 +13:00
Chaim Lev-Ari
58f8b2aaef feat(licenses): show nodes count in license info (#77)
* feat(licenses): show nodes count in license info

* add bold to node count

* add red color to node when over usage

Co-authored-by: Stéphane Busso <stephane.busso@gmail.com>
2020-11-19 19:32:35 +13:00
Yi Chen
5829da5560 * update license check url (#86) 2020-11-19 13:35:31 +13:00
Stéphane Busso
60e7875889 feat(bolt): add log packaget (#82) 2020-11-19 11:17:57 +13:00
Yi Chen
7d9454eed5 Revert "Setup rollbar (#53)" (#75)
This reverts commit aeeee84530.
2020-11-19 11:17:37 +13:00
Alice Groux
0e489aa898 fix(k8s/cluster): update right access to cluster resource panel (#81) 2020-11-19 11:16:20 +13:00
Maxime Bajeux
98c0d53541 fix(application): Publishing over load balancer should be prevented when editing an application in an exhausted resource pool (#74)
* fix(application): Publishing over load balancer should be prevented when editing an application in an exhausted resource pool

* fix(application): can't edit the load balancer ports associated to an application that was deployed whilst the quota was not exhausted
2020-11-19 11:14:53 +13:00
Stéphane Busso
3a6b6cc7a3 feat(bolt): extract services to new file (#83) 2020-11-19 11:09:21 +13:00
Stéphane Busso
59446e1853 fix(portainer): fix couple of comments (#84) 2020-11-19 11:08:37 +13:00
Alice Groux
4971e8ce14 fix(k8s/resource-pool): endpoint admin can edit quota (#80) 2020-11-19 11:03:13 +13:00
Chaim Lev-Ari
0e7577b696 feat(kube/resourcepools): show load balancer usage (#79) 2020-11-19 10:59:58 +13:00
Chaim Lev-Ari
ff480aa226 feat(license): update license exp warning message (#78) 2020-11-19 09:11:09 +13:00
Chaim Lev-Ari
32c3467c18 fix(licenses): use clipboard library (#76)
* fix(licenses): use clipboard library

* Fix copy text

Co-authored-by: Stéphane Busso <stephane.busso@gmail.com>
2020-11-19 08:40:22 +13:00
Stéphane Busso
be46cc52f2 Adding no-cache headers to GET requests (#73) 2020-11-18 13:27:01 +13:00
xAt0mZ
bbcb6b29c1 fix(registry): disable browse for non browsable urls (#72) 2020-11-18 11:33:41 +13:00
Maxime Bajeux
1b2f3ded58 fix(resource-reservation): Invalid total CPU count in multiple places (#59)
* fix(resource-reservation): Invalid total CPU count in multiple places

* fix(ldap): apply default filters on search (#60)

* fix(k8s/resourcepool): fix CPU count in resource pool creation

* fix(k8s/resourcepool): round CPU count to one decimal

* fix(app): possibly unhandled rejections

* chorse(deps): update liblicense (#62)

* fix(licenses): show message when license is invalid (#66)

* fix(licenses): show message when license is invalid

* fix(licenses): align icon

* feat(license): prevent removal of all licenses (#65)

* feat(license): prevent removal of all licenses

* fix(license): skip caching of info if all licenses failed

* fix(ldap): clear settings when moving from custom to openldap (#64)

* fix(ldap): parse both lower and upper case domain (#63)

* fix(ldap): use a specific openldap settings (#67)

* feat(ldap): disable anonymous mode in openldap (#68)

* fix(k8s/application): persisted folders restriction (#69)

* fix(build/kompose): bump Kompose version (#70)

* fix(resource-reservation): Invalid total CPU count in multiple places

* fix(resource-reservation): Invalid total CPU count in multiple places

Co-authored-by: Chaim Lev-Ari <chiptus@users.noreply.github.com>
Co-authored-by: alice groux <alice.grx@gmail.com>
Co-authored-by: xAt0mZ <baron_l@epitech.eu>
Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
Co-authored-by: xAt0mZ <xAt0mZ@users.noreply.github.com>
2020-11-18 10:34:55 +13:00
Stéphane Busso
d8e9849bb2 Revert "Adding no-cache headers to GET requests"
This reverts commit 8a8c38ef91.
2020-11-18 09:58:12 +13:00
Stéphane Busso
8a8c38ef91 Adding no-cache headers to GET requests 2020-11-18 09:54:49 +13:00
Maxime Bajeux
16c0838124 fix(quota): Assigning a LB quota on RP without quota is not working (#71) 2020-11-18 08:54:19 +13:00
Anthony Lapenna
b7ed564108 fix(build/kompose): bump Kompose version (#70) 2020-11-17 11:40:13 +13:00
xAt0mZ
a549b7408a fix(k8s/application): persisted folders restriction (#69) 2020-11-17 08:12:35 +13:00
Chaim Lev-Ari
51f15603da feat(ldap): disable anonymous mode in openldap (#68) 2020-11-16 22:05:10 +13:00
Chaim Lev-Ari
b11499dee1 fix(ldap): use a specific openldap settings (#67) 2020-11-16 20:49:32 +13:00
Chaim Lev-Ari
b405cbedf5 fix(ldap): parse both lower and upper case domain (#63) 2020-11-16 10:39:25 +13:00
Chaim Lev-Ari
65c51eef3c fix(ldap): clear settings when moving from custom to openldap (#64) 2020-11-16 10:39:05 +13:00
Chaim Lev-Ari
513a5a7f8c feat(license): prevent removal of all licenses (#65)
* feat(license): prevent removal of all licenses

* fix(license): skip caching of info if all licenses failed
2020-11-16 10:38:17 +13:00
Chaim Lev-Ari
a6f80eb246 fix(licenses): show message when license is invalid (#66)
* fix(licenses): show message when license is invalid

* fix(licenses): align icon
2020-11-16 10:35:04 +13:00
Chaim Lev-Ari
856922f25c chorse(deps): update liblicense (#62) 2020-11-15 22:16:22 +13:00
Anthony Lapenna
10b853b699 Merge pull request #61 from portainer/fix/AB/146-non-catched-errors
fix(app): possibly unhandled rejections
2020-11-13 11:57:33 +13:00
Anthony Lapenna
c140ea3451 Merge pull request #58 from portainer/fix/AB/132-invalid-cpu-count-resource-pool
fix(k8s/resourcepool): fix CPU count in resource pool creation
2020-11-13 09:18:12 +13:00
xAt0mZ
01e2442409 fix(app): possibly unhandled rejections 2020-11-12 17:46:24 +01:00
alice groux
62808822c6 fix(k8s/resourcepool): round CPU count to one decimal 2020-11-12 14:56:30 +01:00
alice groux
9df9a645b0 fix(k8s/resourcepool): fix CPU count in resource pool creation 2020-11-12 09:57:01 +01:00
Chaim Lev-Ari
e9d5f44c85 fix(ldap): apply default filters on search (#60) 2020-11-12 17:31:12 +13:00
xAt0mZ
9a83f19a4e fix(k8s/resource-pool): restricted LB quota edit visibiliy to the same as other quotas (#56) 2020-11-12 09:34:04 +13:00
Chaim Lev-Ari
dc437084f2 feat(ldap): show groups in a better format (#55)
* feat(ldap): show list of groups

* feat(ldap): show only the cn part of the username

* fix(ldap): rename group search button
2020-11-12 09:33:24 +13:00
Anthony Lapenna
085ee043d9 Merge pull request #57 from portainer/fix/AB/143-resource-assignment-no-quota
style(k8s): rename to resourceOverCommitEnabled
2020-11-12 09:33:14 +13:00
xAt0mZ
ac7e7b015b style(k8s): rename to resourceOverCommitEnabled 2020-11-11 19:21:19 +01:00
Stéphane Busso
aeeee84530 Setup rollbar (#53) 2020-11-11 22:28:21 +13:00
Chaim Lev-Ari
0de11465d0 fix(containers): allow bind mounts and privileged mode for admins (#50)
* fix(containers): allow bind mounts for admins

* fix(container-create): allow priviliged mode for endpoint admin
2020-11-11 18:39:56 +13:00
Chaim Lev-Ari
99adb8a3d6 feat(ldap/search): return unique users (#52) 2020-11-11 18:37:52 +13:00
Chaim Lev-Ari
da36dbd37b fix(licenses-datatable): allow copy of license key (#51) 2020-11-11 12:06:54 +13:00
yi-portainer
707f1b9041 * support flattening in webpack 2020-11-10 14:38:59 +13:00
yi-portainer
097674ebca - remove CI download progress report 2020-11-06 21:55:08 +00:00
Yi Chen
6d446dbafd (fix) unable to delete endpoint && endpoint table cannot select all (#48)
* * fix selected items in generic datatable

* * fix _.union issue
2020-11-07 09:30:38 +13:00
yi-portainer
4cbadb5ed1 - remove debugging statements 2020-11-06 09:32:03 +00:00
yi-portainer
117290e960 + debug build environment 2020-11-05 23:43:13 +00:00
portainer-ci
1d4c2c9078 Merge branch 'ce-develop' into develop 2020-11-05 08:23:41 +00:00
Alice Groux
0d20988bef fix(rest): remove timeouts for all REST services (#4385) 2020-11-05 20:49:37 +13:00
yi-portainer
3c0b33265b * fix missing injections 2020-11-05 01:08:24 +00:00
Anthony Lapenna
ceb6cfb83e Merge pull request #46 from portainer/fixAB120-edge-windows
fix(endpoint): fix invalid Edge agent deployment command for Windows
2020-11-05 09:45:50 +13:00
Anthony Lapenna
819db2dbc0 Merge pull request #45 from portainer/fixAB119-agent-windows
fix(endpoint): fix invalid Windows agent deployment command
2020-11-05 09:45:40 +13:00
Anthony Lapenna
81483aeec1 fix(endpoint): fix invalid Edge agent deployment command for Windows 2020-11-05 07:35:26 +13:00
Anthony Lapenna
5f9e342960 feat(endpoint): fix invalid Windows agent deployment command 2020-11-05 07:17:55 +13:00
Anthony Lapenna
c158c52837 fix(endpoint): fix invalid Windows agent deployment command 2020-11-05 07:15:28 +13:00
Anthony Lapenna
9e2e1810ce fix(endpoint): fix invalid Windows agent deployment command 2020-11-05 07:12:52 +13:00
Anthony Lapenna
72cf5d8ede feat(css): update sidebar color and dashboard items color (#44) 2020-11-04 21:30:43 +13:00
Chaim Lev-Ari
cec0ef17e0 feat(licenses): sync between portainer and license-server (#41)
* feat(license): add sync service

* feat(licenses): check license server

* chore(deps): update liblicense

* feat(license): revoke license if invalid

* feat(license): log revokation

* - removed retry logics
- removed license sync logging
* revert liblicense version

* - remove not used field

Co-authored-by: yi-portainer <yi.chen@portainer.io>
2020-11-04 14:07:45 +13:00
xAt0mZ
7e768a54d5 feat(k8s/resource-pool): storage quotas (#26)
* feat(k8s/resource-pool): add storage quota create/edit

* feat(kubernetes): persistent volume claim size validation on app create/edit

* feat(k8s/volume): quota validation on volume expansion

* fix(k8s/application): remove resource limitation message when then is no resource limitation but volume quota

* style(k8s/application): remove HTML layout debug string

* feat(k8s/resource-pool): remove warning message on storage quota reduction

* fix(k8s/application): available size on storage quota is now properly computed on init

* fix(k8s/application): 'flagged for removal' bindings are not considered free space anymore

* feat(k8s/application): allow users to use existing available volumes when quotas are exhausted

* feat(k8s/resource-pool): storage quota usage bar in edit view

* fix(k8s/resource-pool): create RP enable quota by default

* refactor(k8s): move all volume related units to base 10 instead of base 2 (remive i suffix)

* fix(k8s/application): visual issues caused by latency in computation

* feat(k8s/resource-pool): allow standard users to see storage quota usage

* feat(k8s/volume): show max available size on volume expand

* style(k8s/application): exhausted storage quota message

* fix(k8s/application): remove persisted folders entries when selecting RP with all exhausted storage quotas and no available volumes

* style(k8s/application): file format after rebase

* fix(k8s/application): evaluate quota onInit for app edit

* chore(grunt): add prod watch grunt rule and config

* fix(k8s/application): display 'no storages' message on all restricted quotas

* refactor(k8s/volumes): unify volume parsing

* refactor(app): proper prod watch + enforce parseInt radix
2020-11-04 14:07:21 +13:00
Alice Groux
c302364dd7 feat(app/endpoint): edge deployment for windows (#43)
* feat(app/endpoint): edge deployment for windows
* feat(endpoint-details): update Edge deployment commands

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-11-04 11:20:03 +13:00
Alice Groux
3376f730a2 feat(app/endpoint): add deployment instructions for windows (#42)
* feat(app/endpoint): add deployment instructions for windows
* feat(endpoint-creation): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-11-04 11:16:52 +13:00
Yi Chen
2247d8c3a2 (feat)k8s/RBAC: Provide Portainer RBAC functionality for Kubernetes endpoints (#35)
* + endpoint and namespace level authorizations
+ user namespace authorization API
+ k8s client setup service account with k8s roles and policies by portainer role
* User authorization changes refresh token cache
* rbac authorizes k8s requests
* CE to EE migrator to include new authorizations

* code clean up
* comments

* * merge in the RestrictDefaultNamespace changes

* - remove unnecessary check for default namespace

* + updates namespace access policies when generating token

* * updates namespace access policies when querying the user namespace endpoint

* + k8s rule in rbac.go for endpoint access test
+ missing k8s cluster rules for different roles

* feat(rbac): update kube rbac

* feat(rbac): use the authorization directive

* feat(rbac): Update namespace access policies when user/team is deleted

* refactor(app): use new angular-multi-select capabilities

* feat(rbac): fix authorizations

* feat(rbac): fix userAccessPolicies update bug

* feat(rbac): add W applications authorizations

* feat(rbac): add application details W authorizations

* feat(rbac): add configurations W autohorizations

* feat(rbac): add configuration details W authorizations

* feat(rbac): add volumes W authorizations

* feat(rbac): add volume details W authorizations

* feat(rbac): add componentstatus to portainer-view role and add cluster/node authorizations

* fix(rbac): disable application note for non authorized user

* fix(rbac): add endpoints list and components status to portainer-basic

* fix(rbac): allow user to access default namespace when restrict default namespace isn't activated

* fix(rbac): remove default namespace from useraccesspolicies when restrict default namespace isn't activated

* fix(rbac): change some things

* fix(rbac): allow standard user to access container console

* - removed unused parameter

* fix(rbac): fix team authorizations

Co-authored-by: Maxime Bajeux <max.bajeux@gmail.com>
Co-authored-by: xAt0mZ <baron_l@epitech.eu>
2020-11-03 22:08:09 +13:00
Chaim Lev-Ari
0e7cb4cb42 feat(stacks): prevent name collision with external stacks (#16)
* feat(stacks): check for name collision within external stacks

* feat(stacks): check for name collisions

* feat(stacks): check for running stacks

* feat(stacks): change name collision message

* feat(stack): check for existing services only on swarm

* fix(http): supply docker factory to handler

* feat(stacks): look at all containers
2020-11-03 15:50:18 +13:00
Chaim Lev-Ari
812c0b34ea feat(ldap): simplify ldap configuration (#15)
* feat(ldap): simplify ldap configuration

refactor(auth): move ldap settings to a component

feat(ldap): add username style autofill

feat(ldap): customs for ad

feat(app): introduce box selector

refactor(auth-settings): use box selector

feat(ldap): style changes

refactor(ldap): move connectivity check button to a component

refactor(settings): move ldap security settings to a component

refactor(ldap): move user search to component

refactor(ldap): move group search to component

style(ldap): remove comment

refactor(auth-settings): move auto-user-toggle to component

feat(ldap): provide methods to search for users and groups

refactor(ldap): move group/user settings into component

refactor(ldap): provide labels for components

refactor(ldap): separate custom and ad settings

fix(ldap): search for users

feat(ldap): search users

feat(ldap): complete password if missing

feat(ldap): search for users

feat(ldap): show a list of users

feat(ldap): get user uid

feat(ldap): search groups without password

feat(groups): show group results

feat(ldap): add display types

feat(ldap): search for groups

refactor(ldap): clean code

fix(ldap): sort users table

fix(ldap): show settings by type

feat(ldap): parse values from basedn

feat(ldap): parse values

feat(app): emit on change event from box-selector

feat(ldap): user search filter

feat(ldap): search username attribute

feat(ldap): remove format around search filter

feat(ldap): ad group search

refactor(ldap): move dn builder to component

feat(ldap): use base dn builder for group search

feat(ldap): search for ad groups

refactor(ldap): replace domain root object

feat(ldap): openldap settings

refactor(ldap): delete empty controllers

feat(ldap): remove warning on wrong group filter

feat(ldap): clear username and pass if not AD

feat(ldap): clear basedn when switch from openldap to ad

feat(ldap): clear ldap settings when switich from ldap to ad

feat(ldap): set dn only if there are values

feat(ldap): support more cases of domains

feat(ldap): parse openldap domain correctly

refactor(ldap): move server type check

feat(ldap): move entries

feat(ldap): show username format

style(ldap): remove comments

feat(ldap): clear group filter when no groups

refactor(ldap): replace generic payload

feat(ldap): allow the user to test login

feat(ldap): add test login to custom and open ldap settings

feat(ldap): style fixes

fix(ldap): style fix

fix(ldap): style fixes

refactor(ldap): move components to module

feat(ldap): add group entries

feat(ldap): add borders around each group entry

feat(ldap): parse user filter

feat(ldap): add/remove group

feat(ldap): set ad anonymous mode to false

feat(ldap): add group name

feat(ldap): fix parentheses

feat(ldap): separate between each search config

fix(ldap): fix parsing of group dn

feat(ldap): style fixes

feat(ldap): remove of change of filter

refactor(ldap): remove user display style

feat(ldap): rename group entries field

refactor(auth): move auto user provision

refactor(ldap): refactor box selector

feat(ldap): move ad settings to be a global setting

style(ldap): remove comments

feat(ldap): add auto user toggle

refactor(auth/ad): rename ad component

fix(auth/ad): fix the use of a certificate

refactor(ldap): rename components

fix(ldap): show user and group search

fix(ldap): design group settings

feat(ldap): search users and groups

feat(ldap): add margins

refactor(ldap): separate ldap and ad settings

refactor(auth): use central check for auth method

feat(ldap): clear margins

feat(ldap): add port if missing

feat(ldap): fix ad name

fix(ldap): rename fields

feat(ldap): add domain root field

feat(auth/ad): remove domain root field

feat(ldap): rename base dn to root domain

feat(ldap/openldap): get suffix

feat(ldap/open): change base filter

fix(ldap): align

feat(db): introduce migration for ldap server type

refactor(ldap): move service to ldap module

refactor(ldap): sync between client and server constants

fix(ldap): use post for check

style(ldap): fix handler comments

fix(ldap): check for errors

style(ldap): fix tyop

fix(ldap): check equality

style(ldap): add comments

fix(ldap): allow anonymous mode

fix(ldap): show errors on search users

feat(lasp): use custom settings for each server

fix(ldap): supply default group filter

fix(ldap): show domain suffix in new settings

fix(ldap): replace icon with text

refactor(components): remove box-selector-wrapper

* fix(ldap): enable test when form is valid

* fix(ldap): add port if missing
2020-11-03 15:26:28 +13:00
Maxime Bajeux
162b32a47b feat(namespace): Set quota for Load Balancer usage per Resource Pool (#27)
* feat(namespace): Set quota for Load Balancer usage per Resource Pool

* feat(namespace): UX changes

* feat(namespace): add load balancers usage progress bar

* feat(namespace): minor changes

* feat(resource pool): Minor ux changes

* feat(resource-pool): wording changes

* feat(applications): set correct publishing type when ingresses are refresh

* feat(applications): fix load balancers quota overflow bug

* feat(applications): fix load balancers quota overflow bug
2020-11-03 15:23:51 +13:00
Chaim Lev-Ari
3b670c1f54 feat(db): add flag to rollback to ce edition (#39)
* feat(db): add flag to rollback to ce edition

* refactor(db): make backup of db

* style(api): remove comments

* refactor(db): export backup function

Co-authored-by: yi-portainer <yi.chen@portainer.io>
2020-11-03 14:05:42 +13:00
portainer-ci
3448a23033 Merge branch 'ce-develop' into develop 2020-11-02 23:59:35 +00:00
Maxime Bajeux
82297ba990 feat(resource-pool): Provide a means for an admin to allow/disallow resource over-commit (#33)
* feat(resource-pool): change resource over commit implementation

* fix(resource-pool): hide resource reservation gauges when resources are set to unlimited both

* feat(resource-pool): renaming and hide switch when resource over commit is disabled

* feat(k8s/resource-pools): minor UI update

* fix(resource-pool): fix resource quota validation on resource pool details

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-11-03 10:52:44 +13:00
Alice Groux
a23daeb5cf Feat/ab/106 business theme (#36)
* feat(app): change sidebar background color and font color for business edition

* feat(app/sidebar): add edition version

* feat(app/sidebar): get the edition version

* feat(app/sidebar): change color of selected item for business edition
2020-11-03 10:51:15 +13:00
Anthony Lapenna
1545a42f08 chore(github): update bug report template
Update documentation URLs
2020-11-03 06:16:18 +13:00
Chaim Lev-Ari
15ce12e7b7 feat(license): introduce license management (#31)
* feat(license): add liblicense dep

* feat(license): add bolt license service

* feat(license): introduce license service

* feat(license): validate license before adding

* feat(license): aggregate info after changing of licenses

* feat(http): implement http handlers

* feat(license-management): introduce license service

* feat(licenses): introduce empty view

* feat(license-management): add datatable

* feat(licenses): show license info

* fix(license): inject services

* feat(licenses): add buttons to buy/renew license

* feat(licenses): introduce add license route

* feat(licenses): add license form

* feat(license): datatable

* feat(license): show more details about license

* refactor(license): rename components name

* feat(licenses): show expiration date

* feat(license): introduce init license route

* feat(license): validate license

* feat(license): save licenses

* feat(bouncer): check if license is valid on restricted

* feat(bouncer): remove license check on api

* feat(home): add node warning

* feat(licenses): remove license

* feat(licenses): listen to info changes

* feat(license): show license expiration message

* feat(license): block regular users from licenses view

* feat(license): prevent removing of last license

* fix(license): show message when failed delete

* feat(license): remove trial license when applying oneoff

* feat(license): hide the number of nodes for trial

* feat(auth): disable login if license is invalid

* feat(licenses): add confirmation before removal of license

* feat(nodes): count nodes in env

* feat(license): show message if nodes exceed allowed

* feat(deps): update liblicense

* feat(licenses): show validation errors

* feat(license): use information panel for node info

* fix(license): reload license data on remove

* fix(license): always send list of failed keys

* fix(license): rename buttons

* feat(license): replace icon

* feat(license): add link to licenses page in add license

* fix(licenses): show green valid icon

* fix(licenses): rename expires at

* fix(licenses): rename Attach to add

* fix(licenses): show license type label

* feat(license): aggregate revoked info

* chore(deps): update liblicense

* fix(license): remove space

* fix(sidebar): align icon

* fix(license): change info layout

* feat(license): aggregate only valid licenses

* fix(licenses): move add license to a new line

* style(license): remove console

* refactor(license): move license line to component

* feat(license): check server validation

* fix(licenses): check form validation before submit

* feat(licenses): send only invalid licenses

* fix(license):  hide panels when not needed

* feat(licnese): receive a single license on init

* refactor(header): move header to module

* feat(license): move license panel to header

* fix(header): set min height

* fix(home): show node warning only if subscription

* feat(licenses): minor UI updates

* feat(licenses): minor UI update

* feat(licenses-datatable): add copy button

* fix(licenses-datatable): show date without hours

* feat(license): show expiration message

* fix(users): get user info only on restriced access

* fix(license): clear check for single license

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-11-02 19:10:57 +13:00
Chaim Lev-Ari
9591e1012c feat(auth): support a list of LDAP urls (#9)
* feat(ldap): move urls to url

* feat(ldap): test a few connections

* feat(ldap): update urls

* feat(settings-auth): support array of ldap urls

* feat(settings-auth): support list of urls

* feat(auth): add explanation about server urls

* feat(bolt): add url to urls only if needed

* fix(settings): add nil guards

* fix(settings): set inital value for ldap urls

* feat(settings): prevent the deletion of the first url

* feat(core/settings): minor UI update

* feat(authentication): check that ldap settings are valid

* feat(bolt): create migration for settings

* fix(settings): add wrapping

* feat(ldap): disable submit button only on ldap

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-11-02 11:39:25 +13:00
Chaim Lev-Ari
b357cb54f0 fix(kuberentes): disable rbac check for kuberentes (#38) 2020-10-28 23:13:51 +13:00
Chaim Lev-Ari
d645b4ce6d fix(rbac): add user portainer authorization from ce (#37)
* fix(rbac): add user portainer authorization from ce

* fix(bolt): remove unneeded property
2020-10-28 16:49:30 +13:00
portainer-ci
7b576bcd1d Merge branch 'ce-develop' into develop 2020-10-27 23:59:36 +00:00
Mulia Nasution
a12f2ee893 Fix typo, change Matamo to Matomo (#4409) 2020-10-28 11:33:23 +13:00
Chaim Lev-Ari
c23d2a33da feat(rbac): protect templates deployment (#34)
* feat(templates): show templates link

* feat(templates): protect deploying of templates

* feat(templates): allow fetching of templates to any user

* feat(rbac): allow template file fetching
2020-10-27 20:33:49 +13:00
Chaim Lev-Ari
41eb89cdb1 fix(docker): check for endpoint access auth (#32)
* fix(docker): check for endpoint access auth

* fix(rbac): load user authorizations

* fix(volumes): hide browse button when not agent
2020-10-22 16:07:43 +13:00
portainer-ci
fe9964a405 Merge branch 'ce-develop' into develop 2020-10-20 23:59:58 +00:00
Alice Groux
ccea7cca3d fix(endpoint): remove TLS settings for kubernetes (#4388) 2020-10-21 09:22:42 +13:00
portainer-ci
211def5b51 Merge branch 'ce-develop' into develop 2020-10-19 23:59:32 +00:00
Tim van den Eijnden
43891703c2 fix(endpoints): broken datatable sorting (#4373) 2020-10-20 12:07:24 +13:00
portainer-ci
454a39f83d Merge branch 'ce-develop' into develop 2020-10-16 23:59:34 +00:00
Tim van den Eijnden
74429d6d46 feat(frontend): show endpoint.name in page title (#4363)
* feat(frontend): show endpoint.name in page title

* feat(frontend): show endpoint.name in page title - use rootscope for defaultTitle
2020-10-16 22:28:46 +13:00
S.Hale
bb5c2c2875 fix(readme): fix grammar errors in readme (#4376) 2020-10-16 22:12:06 +13:00
Maxime Bajeux
1f26bc6e8b feat(namespace): Hide Default Namespace for non-admins (#25)
* feat(namespace): Hide Default Namespace for non-admins

* feat(namespace): fix expected behavior when turning on the setting

* feat(resourcePool): Handle when user doesn't have access to any resource pool

* Update app/kubernetes/views/applications/create/createApplication.html

* Update app/kubernetes/views/configurations/create/createConfiguration.html

* Update app/kubernetes/views/applications/create/createApplication.html

* Update app/kubernetes/views/configurations/create/createConfiguration.html

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
2020-10-15 14:02:29 +13:00
portainer-ci
96c6fbf1ed Merge branch 'ce-develop' into develop 2020-10-12 23:59:33 +00:00
itsconquest
3e82d01894 chore(project): update stalebot message (#4364) 2020-10-12 17:28:41 +13:00
Chaim Lev-Ari
336399d482 fix(db): set edition on first run (#30) 2020-10-09 09:29:48 +13:00
Chaim Lev-Ari
8dba19694a feat(roles-management): integrate rbac extension (#6)
* refactor(rbac): move client extension code

* feat(app): remove checks for extension

* feat(rbac): remove checks for extensions

* feat(extensions): remove reference to rbac extensions

* feat(roles): add changes from codebase before removal of rbac

* refactor(security): remove rbac service

* refactor(security): use AdminAccess as an alias

* fix(access): rename policies type

* style(security): add comment about Aliasing AdminAccess to RestrictedAccess

* feat(bolt): add auth migration from ce to ee

* feat(stacks): use authorized access to stop/start stacks

* fix(bolt): supply right params to migrator

* feat(rbac): get authorization on client side
2020-10-07 23:21:14 +13:00
portainer-ci
1a57f656e8 Merge branch 'ce-develop' into develop 2020-10-04 23:59:29 +00:00
Chaim Lev-Ari
6fa16ff49b fix(registry): inject services (#29)
* fix(registry): inject services

* chore(app): add angularjs strict mode
2020-10-05 11:00:59 +13:00
Ranjan Purbey
9e80037e72 style(containers): fix word-break on container details table (#4359)
Co-authored-by: Rajesh Swarna <rajeshswarna123@gmail.com>
Co-authored-by: naveenrayudu <naveenkumar.rayudu@gmail.com>
Co-authored-by: Ranjan Purbey <ranjan.purbey@gmail.com>

Co-authored-by: Rajesh Swarna <rajeshswarna123@gmail.com>
Co-authored-by: naveenrayudu <naveenkumar.rayudu@gmail.com>
2020-10-05 11:00:13 +13:00
panchbhai1969
da29c2b6a5 #3741 fix(datatables): fixes datatable selection count on text filter (#4358) 2020-10-05 10:58:53 +13:00
portainer-ci
d84dd8643f Merge branch 'ce-develop' into develop 2020-09-30 23:59:30 +00:00
Neil Cresswell
0ed4d443ee Update README.md 2020-09-30 15:40:20 +13:00
portainer-ci
4a5bb7c761 Merge branch 'ce-develop' into develop 2020-09-28 23:59:31 +00:00
itsconquest
a4fa44f831 chore(testing): cleanup e2e for CE (#4349) 2020-09-29 11:01:49 +13:00
portainer-ci
4c6f10fc41 Merge branch 'ce-develop' into develop 2020-09-24 23:59:35 +00:00
itsconquest
e479e41aee feat(ci): add missing powershell scripts & fix related grunt code (#4345)
* feat(ci): add missing powershell scripts & fix related grunt code

* feat(ci): download binaries direct to dist directory

* feat(ci): correctly pass in binary versions

* feat(ci): fix powershell errors

* feat(ci): fix cmdlet syntax

* feat(ci): fix typo

* feat(ci): fix additonal typo
2020-09-24 19:19:41 +12:00
portainer-ci
ce7400fa9d Merge branch 'ce-develop' into develop 2020-09-23 23:59:46 +00:00
itsconquest
d4c4c4e895 feat(project): refactor e2e testing (#4341)
* feat(project): refactor e2e testing

* feat(project): remove example text

* feat(project): add missing newlines

Co-authored-by: owner <owner@pop-os.localdomain>
2020-09-23 12:31:19 +12:00
portainer-ci
2271aed31f Merge branch 'ce-develop' into develop 2020-09-21 23:59:33 +00:00
Chaim Lev-Ari
66375454a7 feat(edition): change from BE to EE (#24) 2020-09-15 19:37:43 +12:00
xAt0mZ
c6a8eba1e8 fix(rest): remove timeouts for all REST services (#23) 2020-09-10 16:04:56 +12:00
Chaim Lev-Ari
92872435c4 feat(registry): integrate RM extension (#4)
* refactor(registries): move to portainer

* feat(registries): show browse link

* feat(registry): move registry extension code

* fix(registry): revert files

* refactor(registry): use component

* refactor(registry): replace $scope with this

* refactor(registry): use async await

* refactor(registry): rename and extract

* refactor(registry): rename progression-modal files

* refactor(registry): replace view with component

* refactor(registry): replace with component

* style(regirstries): sort handler keys

* feat(registry): force the recreation of a proxy client

* fix(registry): ignore 404 tags
2020-09-08 19:35:29 +12:00
Chaim Lev-Ari
5459c5cc5b feat(bolt): handle migrations from ce to ee (#22)
* feat(db): add edition value to db

* feat(bolt): handle migrations from ce to ee

* refactor(bolt): merge if branches

* refactor(bolt): rename migration function

* feat(bolt): change migration message

* feat(bolt): add edition to migration messages

* feat(bolt): add log tags

* feat(portainer): add edition

* feat(db): set initial db version

* feat(bolt): cache current version

* refactor(portainer): remove current edition const
2020-09-07 22:15:38 +12:00
Anthony Lapenna
81703dfd0b feat(resource-pools): Provide a means for an admin to allow/disallow resource over-commit 2020-09-01 10:18:15 +12:00
Anthony Lapenna
8b3119cf83 feat(k8s/resource-pool): minor UI update 2020-09-01 10:17:26 +12:00
Anthony Lapenna
466bd24648 feat(test/e2e): update image in cypress compose file 2020-09-01 09:28:45 +12:00
Anthony Lapenna
e87f2f12ec feat(oauth): add oauth providers 2020-09-01 08:59:21 +12:00
Anthony Lapenna
49730157d8 fix(k8s/applications): fix an issue with daemonset in 0/0 state 2020-09-01 08:45:49 +12:00
Anthony Lapenna
c2075fee29 fix(k8s/volumes): fix an issue with the system volume filter not working 2020-09-01 08:45:29 +12:00
Anthony Lapenna
7f329bb484 feat(analytics): change matomo site id and url 2020-09-01 08:44:51 +12:00
Anthony Lapenna
65bdc2ed6f feat(portainer-ee): Use a different source for MOTD 2020-09-01 08:42:58 +12:00
itsconquest
2fc60f14e1 docs(README): add privacy info (#4289) 2020-08-31 22:17:03 +12:00
Anthony Lapenna
9300603777 fix(k8s/applications): fix an issue with daemonset in 0/0 state (#4288) 2020-08-31 17:21:25 +12:00
Anthony Lapenna
8dac2df7bf fix(k8s/volumes): fix an issue with the system volume filter not working (#4284) 2020-08-31 17:21:15 +12:00
Anthony Lapenna
38c1c72d38 fix(k8s/applications): fix an issue with daemonset in 0/0 state 2020-08-31 16:59:10 +12:00
Anthony Lapenna
8eb432b0b0 fix(k8s/volumes): fix an issue with the system volume filter not working 2020-08-31 12:54:22 +12:00
Maxime Bajeux
5437d9db7c feat(resource-pools): Provide a means for an admin to allow/disallow resource over-commit 2020-08-30 23:22:28 +02:00
Chaim Lev-Ari
8850bc3dcd feat(analytics): change matomo site id and url 2020-08-30 15:27:31 +03:00
Anthony Lapenna
3b02596704 Merge pull request #10 from portainer/ee-pulldog
feat(build/pulldog): review pulldog configuration
2020-08-28 15:25:59 +12:00
Anthony Lapenna
90fd5af4b9 fix(core/home): fix a display issue with Edge endpoints 2020-08-28 12:05:22 +12:00
Anthony Lapenna
3ec05accbc Merge tag '2.0.0' into develop
Release 2.0.0
2020-08-27 17:48:21 +12:00
Anthony Lapenna
1bc0c1baa9 Merge branch 'release/2.0.0' 2020-08-27 17:48:15 +12:00
Anthony Lapenna
ce8e245759 chore(version): bump version number 2020-08-27 17:48:02 +12:00
Anthony Lapenna
b91895d618 feat(core/endpoint): minor UI update for Kubernetes Edge endpoints 2020-08-27 17:28:41 +12:00
Anthony Lapenna
0019b22be5 fix(core/home): fix an issue when connecting to an Edge kubernetes endpoint (#4274) 2020-08-27 00:26:21 +12:00
Chaim Lev-Ari
eb0278d230 feat(core/cli): change analytics flag message (#4273)
* feat(cli): remove no-analytics flag default value

* feat(cli): hide no-analytics deprecation message when it's false
2020-08-26 23:58:19 +12:00
Anthony Lapenna
787cf41ee3 feat(k8s/configure): rename metrics server 2020-08-25 22:53:12 +12:00
Chaim Lev-Ari
0ebf0ab199 fix(auth): prevent double transition to logout (#4266)
* fix(auth): prevent double transition to logout

* fix(app): revert

* feat(state-manager): reinitalize on login
2020-08-25 20:08:47 +12:00
Chaim Lev-Ari
6fa450a981 feat(aci): introduce basic form validation (#4268)
* feat(aci): introduce basic form validation

* feat(aci): check every port bindings

* fix(aci): remove name and image warnings
2020-08-25 19:45:06 +12:00
Chaim Lev-Ari
b4f97efb85 fix(rbac): clean leftovers (#4265) 2020-08-25 11:04:51 +12:00
Maxime Bajeux
18c1425b8e feat(portainer-ee): Use a different source for MOTD 2020-08-24 18:34:29 +02:00
Chaim Lev-Ari
45cada05d5 feat(custom-templates): validate unique template name (#4264)
* feat(custom-template): check for name uniqueness

* feat(custom-templates): check unique name on edit
2020-08-24 14:54:02 +12:00
Chaim Lev-Ari
d5d7b17dc4 feat(stacks): disable creation when editor or template is empty (#4262) 2020-08-24 14:53:27 +12:00
Chaim Lev-Ari
859d26aef6 fix(templates): show error when failing to create stack (#4251) 2020-08-21 19:34:40 +12:00
Anthony Lapenna
fc248c31c7 fix(api/stacks): add authorization checks for start/stop operations (#4248)
* fix(api/stacks): add authorization checks for start/stop operations

* feat(api/stacks): re-order validation checks

* fix(api/stacks): add missing endpoint validation check
2020-08-21 15:16:38 +12:00
Anthony Lapenna
383e19077f feat(core/about): remove about view and add link to website (#4256) 2020-08-21 13:11:34 +12:00
Chaim Lev-Ari
a3b54e1981 fix(api/custom-templates): prevent name collisions on update (#4250) 2020-08-21 10:17:30 +12:00
xAt0mZ
403dbb1245 fix(docker/templates): save custom template filters (#4249) 2020-08-21 10:15:26 +12:00
Chaim Lev-Ari
c48d05449c fix(volumes): set right resource id for volume (#4247) 2020-08-21 00:48:53 +12:00
Chaim Lev-Ari
9fd38a0543 fix(volumes): enable volume browsing (#4233)
* fix(docker): browse an agent volume

* refactor(volumes): get resource id from endpoint
2020-08-21 00:29:46 +12:00
Anthony Lapenna
f8be9bb57a feat(k8s/resource-pool): set ingress hostname as mandatory and remove… (#4244)
* feat(k8s/resource-pool): set ingress hostname as mandatory and remove default backend

* refactor(k8s/resource-pool): use constants

* feat(k8s/configure): add experimental note about traefik
2020-08-20 21:24:12 +12:00
Chaim Lev-Ari
7329ea91ca fix(app): set defaults for select boxes (#4235)
* fix(container): select runtime by default

* fix(network): set default network config

* fix(container): set default network container placeholder

* fix(services): default service mount
2020-08-20 13:02:25 +12:00
xAt0mZ
d850e18ff0 feat(k8s/ingresses): add more granularity to ingress configuration (#4220)
* feat(k8s/configure): separate ingress class name and ingress class type

* feat(k8s/resource-pool): ability to add custom annotations to ingress classes on RP create/edit

* feat(k8s/ingresses): remove 'allow users to use ingress' switch

* feat(k8s/configure): minor UI update

* feat(k8s/resource-pool): minor UI update

* feat(k8s/application): update ingress route form validation

* refactor(k8s/resource-pool): remove console.log statement

* feat(k8s/resource-pool): update ingress annotation placeholders

* feat(k8s/configure): add pattern form validation on ingress class

* fix(k8s/resource-pool): automatically associate ingress class to ingress

* fix(k8s/resource-pool): fix invalid ingress when updating a resource pool

* fix(k8s/resource-pool): update ingress rewrite target annotation value

* feat(k8s/application): ingress form validation

* fix(k8s/application): squash ingress rules with empty host inside a single one

* feat(k8s/resource-pool): ingress host validation

* fix(k8s/resource-pool): rewrite rewrite option and only display it for ingress of type nginx

* feat(k8s/application): do not expose ingress applications over node port

* feat(k8s/application): add specific notice for ingress

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-08-20 12:51:14 +12:00
Chaim Lev-Ari
68851aada4 fix(containers): persist column settings (#4234)
* feat(containers): remove ip column

* fix(containers): persist column settings
2020-08-19 11:50:16 +12:00
Chaim Lev-Ari
aeb3bf535f fix(aci): create aci endpoint (#4231) 2020-08-19 00:40:02 +12:00
Chaim Lev-Ari
7b77a92a2d fix(endpoints): load endpoints and tags together (#4230) 2020-08-19 00:39:32 +12:00
Chaim Lev-Ari
35fa9d6981 fix(oauth): if username is empty, fail to login (#4232)
* fix(oauth): if username is empty, fail to login

* fix(oauth): return err when failing to find username

* fix(oauth): disable autofill
2020-08-19 00:38:58 +12:00
Chaim Lev-Ari
b3b706d88d fix(core/oauth): select no-team by default (#4227) 2020-08-18 20:59:52 +12:00
Chaim Lev-Ari
957dd43aa3 feat(oauth): add oauth providers 2020-08-18 11:24:33 +03:00
Anthony Lapenna
2972dbeafb feat(build/pulldog): review pulldog configuration 2020-08-18 12:36:01 +12:00
Chaim Lev-Ari
297eea5da6 fix(frontend): add missing @ngInject (#4217) 2020-08-17 12:33:57 +12:00
Chaim Lev-Ari
b6fc434291 fix(dashboard): show endpoint tags (#4216)
* fix(dashboard): show endpoint tags

* fix(dashboard): use ctrl
2020-08-17 12:30:02 +12:00
Anthony Lapenna
5c6147c9b9 feat(k8s/configure): review ingress UI/UX 2020-08-17 12:27:06 +12:00
Anthony Lapenna
8c3160d061 feat(core/endpoints): review endpoint creation instructions 2020-08-17 12:13:29 +12:00
Anthony Lapenna
1ef78c0fdf refactor(core/db): refactor instance ID init 2020-08-16 10:54:50 +12:00
Anthony Lapenna
9733d32551 feat(core/support): remove support related API route 2020-08-16 10:45:04 +12:00
Anthony Lapenna
bd0d1c25fa feat(core/support): remove support related views 2020-08-16 10:41:09 +12:00
Anthony Lapenna
b77e39c065 feat(k8s/application): minor UI update 2020-08-16 10:31:43 +12:00
xAt0mZ
8d6f6e306a feat(k8s/application): add placement constraints validation (#4214)
* feat(k8s/application): add constraints validation

* feat(k8s/application): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-08-16 10:11:56 +12:00
Anthony Lapenna
36bf9c24b9 feat(k8s/resource-pool): review ingress rollup panel UI 2020-08-15 13:39:43 +12:00
Anthony Lapenna
e10cf3e59b feat(core/registries): add information message about registry usage 2020-08-15 13:34:44 +12:00
Anthony Lapenna
46762f3e67 fix(k8s/configurations): fix an issue with configuration ownership 2020-08-15 12:42:04 +12:00
Anthony Lapenna
7ad06b3be5 refactor(k8s/configurations): add refactor note 2020-08-15 12:12:56 +12:00
Anthony Lapenna
877e2baf59 feat(k8s/application): update placement style 2020-08-15 12:09:43 +12:00
Anthony Lapenna
9f0ff5181b feat(k8s/application): update placement rule policy style 2020-08-15 12:05:50 +12:00
Anthony Lapenna
56cda7f260 feat(k8s/application): re-order pod/container columns in application containers table 2020-08-14 17:11:26 +12:00
Anthony Lapenna
449b7888d3 fix(k8s/backend): update stander user cluster roles permissions 2020-08-14 17:08:51 +12:00
Anthony Lapenna
83c3f9ed06 fix(k8s/application): fix an issue with the auto-scaler section 2020-08-14 16:56:56 +12:00
xAt0mZ
52bdcf2e2b feat(k8s/application): add/edit placement preferences/constraints (#4210)
* feat(k8s/application): create application with placement preferences/constraints

* feat(k8s/application): edit application placement preferences/constraints
2020-08-14 11:56:53 +12:00
Chaim Lev-Ari
32bac9ffcc fix(main): terminate server if err returned by instanceId check is not nil (#4209) 2020-08-14 11:41:39 +12:00
Maxime Bajeux
00389a7da9 feat(k8s/application): Support multi-container pods applications (#4208)
* feat(application): Support multi-container pods applications

* feat(application): Support multi-container pods applications

* fix(application): use only one pod in app details and fix logs and console links

* fix(application): show all containers in containers datatable

* fix(application): fix order by pod name

* feat(k8s/application): minor UI update

* feat(k8s/application): minor UI update

* feat(k8s/application): minor UI update

* feat(k8s/application): minor UI update

* feat(k8s/application): minor UI update

* fix(application): fix persisted folders in application details

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-08-14 11:27:10 +12:00
Anthony Lapenna
fe4a80c7bd feat(k8s/ingress): display unused routes 2020-08-13 18:19:16 +12:00
Anthony Lapenna
6615e354c4 feat(k8s/resource-pool): change default behavior for resource assignment (#4207) 2020-08-13 11:49:34 +12:00
Anthony Lapenna
69e9e566c5 feat(k8s/dashboard): remove the RC banner (#4205) 2020-08-13 11:41:14 +12:00
xAt0mZ
f91d3f1ca3 feat(k8s/applications): expose applications via ingress (#4136)
* feat(k8s/endpoint): expose ingress controllers on endpoints

* feat(k8s/applications): add ability to expose applications over ingress - missing RP and app edits

* feat(k8s/application): add validation for ingress routes

* feat(k8s/resource-pools): edit available ingress classes

* fix(k8s/ingress): var name refactor was partially applied

* feat(kubernetes): double validation on RP edit

* feat(k8s/application): app edit ingress update + formvalidation + UI rework

* feat(k8s/ingress): dictionary for default annotations on ingress creation

* fix(k8s/application): temporary fix + TODO dev notice

* feat(k8s/application): select default ingress of selected resource pool

* feat(k8s/ingress): revert ingressClassName removal

* feat(k8s/ingress): admins can now add an host to ingress in a resource pool

* feat(k8s/resource-pool): list applications using RP ingresses

* feat(k8s/configure): minor UI update

* feat(k8s/configure): minor UI update

* feat(k8s/configure): minor UI update

* feat(k8s/configure): minor UI update

* feat(k8s/configure): minor UI update

* fix(k8s/ingresses): remove host if undefined

* feat(k8s/resource-pool): remove the activate ingresses switch

* fix(k8s/resource-pool): edditing an ingress host was deleting all the routes of the ingress

* feat(k8s/application): prevent app deploy if no ports to publish and publishing type not internal

* feat(k8s/ingress): minor UI update

* fix(k8s/ingress): allow routes without prepending /

* feat(k8s/application): add form validation on ingress route

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-08-13 11:30:23 +12:00
Chaim Lev-Ari
201c3ac143 fix(auth): don't redirect if route is unauthenticated (#4203)
* fix(auth): don't redirect if route is unauthenticated

* refactor(auth): replace resolve with onEnter

* fix(auth): throw error on init
2020-08-12 20:29:08 +12:00
Anthony Lapenna
2c15dcd1f2 feat(k8s): use instance ID to create unique k8s resources (#4196) 2020-08-12 17:10:28 +12:00
Maxime Bajeux
1bf97426bf feat(k8s/node): Add the ability to apply taints and labels to nodes (#4176)
* feat(node): Add the ability to apply taints and labels to nodes

* feat(k8s/node): minor UI update

* feat(k8s/node): UI update and disable system labels

* feat(k8s/node): minor UI update

* fix(node): fix add first taint

* refacto(node): add KubernetesNodeHelper

* feat(node): add used label to labels

* feat(node): add node update modals

* fix(node): modal when used label changes

* feat(k8s/node): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-08-12 11:42:55 +12:00
Anthony Lapenna
1f614ee95a feat(core/settings): rename settings sections (#4199) 2020-08-11 22:08:44 +12:00
Chaim Lev-Ari
b4c2e5d235 fix(auth): reject main route if logged out (#4197) 2020-08-11 20:23:14 +12:00
Chaim Lev-Ari
9d18d47194 feat(extensions): remove rbac extension (#4157)
* feat(extensions): remove rbac extension client code

* feat(extensions): remove server rbac code

* remove extensions code

* fix(notifications): remove error

* feat(extensions): remove authorizations service

* feat(rbac): deprecate fields

* fix(portainer): revert change

* fix(bouncer): remove rbac authorization check

* feat(sidebar): remove roles link

* fix(portainer): remove portainer module
2020-08-11 17:41:37 +12:00
Chaim Lev-Ari
8629738e34 fix(auth): switch to log-in when user is not logged in (#4162)
* fix(auth): switch to log-in when user is not logged in

* fix(app): remove analytics injection
2020-08-11 14:46:41 +12:00
Anthony Lapenna
a3925c3371 feat(k8s/sidebar): relocate setup entry as a sub-entry (#4192) 2020-08-11 12:39:01 +12:00
Anthony Lapenna
6720c31aa9 fix(k8s/volume): only show resize modal for used volumes (#4194) 2020-08-11 12:38:41 +12:00
Anthony Lapenna
01d414b578 fix(k8s/node): only show API address field for nodes tagged as API (#4193) 2020-08-11 12:38:19 +12:00
Maxime Bajeux
6d069cc8d6 feat(k8s/volumes): Enhance the used by column for volumes (#4191)
* feat(volumes): Enhance the used by column for volumes

* feat(k8s/volumes): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-08-11 12:22:13 +12:00
Chaim Lev-Ari
a1e3ed7f78 feat(k8s/application): add default values for auto scaler (#4190) 2020-08-11 10:57:20 +12:00
Maxime Bajeux
baaa96f34f feat(k8s/application): Update form validation for environment variables when deploying an application (#4177) 2020-08-11 10:56:54 +12:00
Chaim Lev-Ari
56524ca7d5 fix(nodes): add ngInject to node-select (#4187) 2020-08-11 09:52:29 +12:00
Chaim Lev-Ari
c439bc56ff fix(edge): fix edge views (#4184)
* fix(edge): add ngInject

* feat(edge): init edge job model
2020-08-11 09:51:21 +12:00
Chaim Lev-Ari
134f2f1532 feat(docker/routes): add /docker parent route (#4185) 2020-08-10 23:37:49 +12:00
Anthony Lapenna
b4aca3822d feat(k8s/sidebar): add a setup sidebar entry (#4186) 2020-08-10 22:31:55 +12:00
itsconquest
59cc02137d fix(ux): fix checkbox sizing (#4172)
* fix(UX): scale and align checkboxes

* fix(UX): scale to default browser zoom

* fix(UX): use different browser scale properties

* fix(UX): css rule with fixed height/width
2020-08-10 18:21:03 +12:00
itsconquest
8408484f8b feat(docker/node): change table to div and fix styling (#4173) 2020-08-10 10:59:00 +12:00
itsconquest
c5731e237e fix(docker/container): handle multiple ips with the same port (#4121)
* fix(containers): handle multiple ips with the same port

* fix(containers): fix parsing
2020-08-10 10:27:27 +12:00
Maxime Bajeux
cb1a1e7be5 feat(k8s/resource-pool): add a modal when reducing the quota of an in use RP (#4170)
* feat(resourcepool): Reducing the Quota assigned to a RP

* fix(k8s/resource-pool): fix an issue with hasResourceQuotaBeenReduce condition

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-08-08 10:46:11 +12:00
Maxime Bajeux
e7a33347c6 fix(k8s/storage): missing endpoint id in storage patch request (#4174) 2020-08-08 10:43:34 +12:00
itsconquest
26ee78e1e7 refactor(UX): fix improper grammar (#4161) 2020-08-07 16:50:56 +12:00
Maxime Bajeux
61f97469ab feat(application): Add the ability to use existing volumes when creating an application (#4044)
* feat(applications): update UI to use existing volumes

* feat(application): Add the ability to use existing volumes when creating an application

* feat(application): Existing persisted folders should default to associated volumes

* feat(application): add form validation to existing volume

* feat(application): remove the ability to use an existing volume with statefulset application

* feat(k8s/applications): minor UI update

* feat(k8s/application): minor UI update

* feat(volume): allow to increase volume size and few other things

* feat(volumes): add the ability to allow volume expansion

* fix(storage): fix the storage patch request

* fix(k8s/applications): remove conflict leftover

* feat(k8s/configure): minor UI update

* feat(k8s/volume): minor UI update

* fix(storage): change few things

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-08-07 16:40:24 +12:00
itsconquest
b9c2bf487b fix(container-creation): add default/override options (#4119)
* fix(container-creation): add default/override options

* fix(container-creation): allow override with empty string on creation

* fix(container-creation): add tooltip & update placeholder

* fix(container-creation): add warning on duplicate
2020-08-07 14:10:40 +12:00
itsconquest
1b88ca2285 fix(container-creation): handle extraHosts correctly (#4139)
* fix(container-creation): handle extraHosts correctly

* fix(container-creation): refactor for readability
2020-08-07 14:10:08 +12:00
Anthony Lapenna
747fdae269 fix(agent/console): fix an issue with the agent console on Docker environments (#4169) 2020-08-07 14:08:57 +12:00
Maxime Bajeux
b8f8c75380 feat(k8s/resource-pool): prevent admins from making changes to "system" namespaces (#4167) 2020-08-07 12:03:00 +12:00
Maxime Bajeux
d85708f6ea feat(docker/services): Add the ability to edit a service networks (#3957)
* feat(services): update services details view

* feat(services): Add the ability to edit a service networks

* feat(services): show ingress network

* refactor(services): use lodash

* feat(networks): disable sending when updating

* feat(networks): limit size of select

* feat(services): update networks only when network is new

* feat(services): prevent submitting of empty networks

* feat(services): show unique networks

* fix(service): use empty array default for networks

* feat(service): show only swarm networks

* feat(services): show placeholder for network

* feat(services): show spaced select box

* feat(services): show macvlan ip

* feat(service): fetch the network subnet

* feat(services): show empty ip when network is not connected

Co-authored-by: Chaim Lev-Ari <chiptus@gmail.com>
2020-08-07 11:11:47 +12:00
Maxime Bajeux
e4ca58a042 fix(application): hpa breaks application edit (#4166) 2020-08-07 10:55:36 +12:00
Chaim Lev-Ari
2158cc5157 feat(telemetry): replace GA with matomo (#4140)
* feat(core/telemetry): add posthog

* feat(core/telemetry): add posthog

* feat(core/telemetry): add matomo

* feat(core/telemetry): update matomo

* feat(core/telemetry): update matomo

* feat(core/telemetry): update matomo

* feat(telemetry): remove google analytics code

* refactor(telemetry): move matomo code to bundle

* refactor(telemetry): move matomo lib to assets

* refactor(telemetry): depreciate --no-analytics

* feat(settings): introduce a setting to enable telemetry

* fix(cli): fix typo

* feat(settings): allow toggle telemetry from settings

* fix(settings): handle case where AuthenticationMethod is missing

* feat(admin): set telemetry on admin init

* refactor(app); revert file

* refactor(state-manager): move optout to state manager

* feat(telemetry): set matomo url

* feat(core/settings): minor UI update

* feat(core/telemetry): update custom URL

* feat(core/telemetry): add placeholder for privacy policy

* feat(core/telemetry): add privacy policy link

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-08-07 10:46:25 +12:00
DarkAEther
7aaf9d0eb7 fix(registries): remove trailing slash and protocol in registry URLs (#4131)
* feat(registries) prevent trailing slash

* fix(registries) avoid trailing slash in update registry

* fix(registries) include trailing slash removal notice in tooltips

* fix(registries) remove protocol when updating existing registry

* fix(registries) uniform usage of string replace function for registry update
2020-08-06 09:58:44 +12:00
Chaim Lev-Ari
82064152ec feat(registries): remove registry extension (#4155)
* feat(registries): remove client extension code

* feat(registry): remove server registry code

* refactor(registry): remove extension related code

* feat(extensions): remove registry extension type
2020-08-05 22:23:19 +12:00
Chaim Lev-Ari
7e90bf11b7 fix(datatables): deselect row (#4122)
* fix(datatables): deselect row

* fix(datatables): enable batch select

* fix(registry): select registry items
2020-08-05 22:14:28 +12:00
Chaim Lev-Ari
ff250a202a feat(extensions): remove oauth extension (#4156)
* feat(oauth): remove oauth providers

* feat(extensions): remove references to oauth extension
2020-08-05 22:13:23 +12:00
Chaim Lev-Ari
00f4fe0039 feat(auth): integrate oauth extension (#4152)
* refactor(oauth): move oauth client code

* feat(oauth): move extension code into server code

* feat(oauth): enable oauth without extension

* refactor(oauth): make it easier to remove providers
2020-08-05 20:36:46 +12:00
Maxime Bajeux
148ccd1bc4 feat(node): Show which IP address / port the cluster API is listening on (#4134)
* feat(cluster): add kubernetes endpoint resource

* feat(cluster): add kubernetes endpoint service

* feat(node): Show which IP address / port the cluster API is listening on

* fix(cluster): support multi-master clusters

* fix(cluster): support multi-master clusters

* feat(k8s/cluster): minor UI update

* refactor(k8s/cluster): rename variable

* refactor(k8s/endpoints): refactor KubernetesEndpointsFactory

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-08-05 12:15:17 +12:00
Maxime Bajeux
6756b04b67 feat(k8s/application): add the ability to set the auto-scale policy of an application (#4118)
* feat(application): add horizontalpodautoscaler creation

* feat(application): Add the ability to set the auto-scale policy of an application

* feat(k8s/application): minor UI update

* fix(application): set api version and prevent to use hpa with global deployment type

* feat(settings): add a switch to enable features based on server metrics

* feat(k8s/applications): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-08-05 10:08:11 +12:00
Anthony Lapenna
909e1ef02c fix(k8s/user): remove username part from service account (#4147) 2020-08-04 16:01:15 +12:00
Chaim Lev-Ari
bd7d7dcef5 feat(agent): add auto agent platform detection (#4132)
* feat(endpoint): check endpoint type on creation

* feat(edge): check edge endpoint type

* feat(endpoint): send endpoint creation type

* feat(endpoint): pass tls config

* feat(endpoint): show connect errors

* fix(endpoint): set correct endpoint type

* feat(endpoint): support endpoint creation

* style(endpoint): remove todo comment

* feat(endpoint): set protocol for endpoint url

* feat(endpoint): change scheme of url

* fix(endpoint): toggle code block

* feat(edge): report missing agent platform header

* fix(api/endpoints): fix an issue with agent on kubernetes endpoint

* feat(core/endpoints): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-08-04 12:44:17 +12:00
itsconquest
490b7ad26f fix(container-creation): allow resetting to unlimited (#4138)
* fix(container-creation): allow resetting to unlimited

* fix(container-creation): refactor for readability
2020-08-04 11:14:59 +12:00
Chaim Lev-Ari
4d5836138b feat(stacks): add the ability to stop a stack (#4042)
* feat(stacks): add stack status

* feat(stacks): add empty start/stop handlers

* feat(stacks): show start/stop button

* feat(stacks): implement stack stop

* feat(stacks): implement start stack

* feat(stacks): filter by active/inactive stacks

* fix(stacks): update authorizations for stack start/stop

* feat(stacks): assign default status on create

* fix(bolt): fix import

* fix(stacks): show external stacks

* fix(stacks): reload on stop/start

* feat(stacks): confirm before stop
2020-08-04 10:18:53 +12:00
Chaim Lev-Ari
da143a7a22 fix(docker/images): ignore pull image rejection (#4128) 2020-07-31 06:24:34 +12:00
xAt0mZ
4431d748c2 feat(k8s/application): expose tolerations and affinities (#4063)
* feat(k8s/application): expose placement conditions

* feat(k8s/applications): minor UI update

* feat(k8s/application): update message for admin and non admin users

* feat(kubernetes/applications): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-07-30 10:25:59 +12:00
Chaim Lev-Ari
63bf654d8d fix(serverless/ACI): show container instance title (#4126) 2020-07-30 09:53:57 +12:00
Chaim Lev-Ari
93d8c179f1 feat(containers): enforce disable bind mounts (#4110)
* feat(containers): enforce disable bind mounts

* refactor(docker): move check for endpoint admin to a function

* feat(docker): check if service has bind mounts

* feat(services): allow bind mounts for endpoint admin

* feat(container): enable bind mounts for endpoint admin

* fix(services): fix typo
2020-07-29 21:10:46 +12:00
Chaim Lev-Ari
7539f09f98 feat(containers): disable edit container on security setting restricting regular users (#4111)
* feat(settings): add info about container edit disable

* feat(settings): set security settings

* feat(containers): hide recreate button when setting is enabled

* feat(settings): rephrase security notice

* fix(settings): save allowHostNamespaceForRegularUsers to state
2020-07-29 14:52:23 +12:00
Chaim Lev-Ari
1a3f77137a feat(settings): introduce setting to disable container caps for non-admins (#4109)
* feat(settings): introduce settings to allow/disable

* feat(settings): update the setting

* feat(docker): prevent user from using caps if disabled

* refactor(stacks): revert file

* style(api): remove portainer ns
2020-07-28 19:08:15 +12:00
Chaim Lev-Ari
fec85c77d6 fix(extensions): load extensions file (#4115) 2020-07-28 09:54:12 +12:00
Chaim Lev-Ari
1ff5708183 fix(datatables): select table items (#4116) 2020-07-28 09:53:21 +12:00
Chaim Lev-Ari
1edf981330 fix(container-creation): preselect network (#4117) 2020-07-28 09:52:54 +12:00
Chaim Lev-Ari
fa9eeaf3b1 feat(settings): introduce disable stack management setting (#4100)
* feat(stacks): add a setting to disable the creation of stacks for non-admin users

* feat(settings): introduce a setting to prevent non-admin from stack creation

* feat(settings): update stack creation setting

* feat(settings): fail stack creation if user is non admin

* fix(settings): save preventStackCreation setting to state

* feat(stacks): disable add button when settings is enabled

* format(stacks): remove line

* feat(stacks): setting to hide stacks from users

* feat(settings): rename disable stacks setting

* refactor(settings): rename setting to disableStackManagementForRegularUsers

* feat(settings): hide stacks for non admin when settings is set

* refactor(settings): replace disableDeviceMapping with allow

* feat(dashboard): hide stacks if settings disabled and non admin

* refactor(sidebar): check if user is endpoint admin

* feat(settings): set the default value for stack management

* feat(settings): rename field label

* fix(sidebar): refresh show stacks state

* fix(docker): hide stacks when not admin
2020-07-27 19:11:32 +12:00
Chaim Lev-Ari
07efd4bdda feat(settings): add setting to disable device mapping for regular users (#4099)
* feat(settings): add setting to disable device mapping for regular users

* feat(settings): introduce device mapping service

* feat(containers): hide devices field when setting is on

* feat(containers): prevent passing of devices when not allowed

* feat(stacks): prevent non admin from device mapping

* feat(stacks): disallow swarm stack creation for user

* refactor(settings): replace disableDeviceMapping with allow

* fix(stacks): remove check for disable device mappings from swarm

* feat(settings): rename field to disable

* feat(settings): supply default value for disableDeviceMapping

* feat(container): check for endpoint admin

* style(server): sort imports
2020-07-27 09:31:14 +12:00
DarkAEther
2bc6b2dff7 feat(docker/container-creation): sort volumes in container creation view (#4078)
* #3635 fix(containers) sort volumes in container creation view

* fix(3635) sort volumes in container creation view
2020-07-27 09:28:33 +12:00
Anthony Lapenna
0cebe6588a chore(github/stalebot): update stalebot config 2020-07-27 09:24:41 +12:00
Anthony Lapenna
990f3cad88 chore(github/stalebot): update stalebot config 2020-07-27 09:19:33 +12:00
Anthony Lapenna
7e7a8e521b feat(app/package): remove angular-cookies dependency 2020-07-25 11:32:31 +12:00
Chaim Lev-Ari
43bbc14c58 feat(app/package): upgrade angularjs to 1.8 (#4073)
* chore(yarn): upgrade angularjs

* refactor(app): use $onInit instead of initComponent

* feat(app/package): remove angular-cookies dependency

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-07-25 11:23:44 +12:00
Chaim Lev-Ari
adf33385ce feat(containers): Prevent non-admin users from running containers using the host namespace pid (#4098)
* feat(containers): prevent non-admin users from running containers using the host namespace pid (#3970)

* feat(containers): Prevent non-admin users from running containers using the host namespace pid

* feat(containers): add rbac check for swarm stack too

* feat(containers): remove forgotten conflict

* feat(containers): init EnableHostNamespaceUse to true and return 403 on forbidden action

* feat(containers): change enableHostNamespaceUse to restrictHostNamespaceUse in html

* feat(settings): rename EnableHostNamespaceUse to AllowHostNamespaceForRegularUsers

* feat(database): trigger migration for AllowHostNamespace

* feat(containers): check container creation authorization

Co-authored-by: Maxime Bajeux <max.bajeux@gmail.com>
2020-07-25 11:14:46 +12:00
Anthony Lapenna
e78aaec558 feat(api/bolt): update DBVersion to 25 2020-07-25 11:10:46 +12:00
xAt0mZ
3953acf110 feat(k8s/volumes): introduce storage rollup panel (#4055)
* feat(k8s/applications): storages rollup panel

* feat(k8s/volumes): move storages table to volumes view

* feat(k8s/volumes): minor UI update

* feat(k8s/volumes): remember the selected tab

* feat(api/k8s): update user default policies

* feat(k8s/ui): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-07-24 14:45:02 +12:00
Chaim Lev-Ari
99db41f96e feat(agent): refactor volumeBrowserService to es6 (#4094) 2020-07-23 19:46:29 +12:00
Chaim Lev-Ari
822c4e117c refactor(agent): refactor hostBrowserService to es6 (#4092)
related to #4071
2020-07-23 19:46:02 +12:00
Chaim Lev-Ari
f761e65167 refactor(agent): refactor agentService to es6 (#4091) 2020-07-23 19:45:47 +12:00
Chaim Lev-Ari
1ef7347f19 refactor(agent): refactor host-broswer to es6 (#4088)
* refactor(host): replace host-browser with es6 class

* refactor(host): replace promises with async

* refactor(hosts): replace delete promise with async

* refactor(host): replace upload file with async

* refactor(host): replace template strings

* fix(host): replace host root

* feat(agent): rename main file
2020-07-23 19:45:23 +12:00
Chaim Lev-Ari
a473d738be refactor(agent): refactor volume browser to es6 (#4086)
* refactor(agent): replace root with index

* refactor(agent): use simple export

* refactor(agent): replace function with class

* refactor(agent): replace promise with async
2020-07-23 19:45:12 +12:00
Chaim Lev-Ari
7eb8d5449a refactor(agent): refactor rest factories to es6 (#4090)
* refactor(agent): replace v1 browse with es6 module

* refactor(agent): refactor agentv1 to es6

* refactor(agent): replace agent factory with es6

* refactor(agent): refactor browse response to es6

* refactor(agent): refactor browse to es6

* refactor(agent): import angular

* refactor(agent): refactor host to es6

* refactor(agent): refactor ping to es6
2020-07-23 19:45:01 +12:00
Chaim Lev-Ari
435f15ec6a refactor(agent): refactor file-uploader to es6 (#4087)
* refactor(host): convert fileUploader to es6

* refactor(agent): rename main file
2020-07-23 19:44:32 +12:00
Chaim Lev-Ari
5abd35d4c1 refactor(agent): refactor pingService to es6 (#4093)
related to #4071
2020-07-23 19:43:37 +12:00
Chaim Lev-Ari
b50497301d refactor(agent): refactor files-datatable to es6 (#4085)
* refactor(host): rename files datatable

* feat(agent): rename main file
2020-07-23 19:43:12 +12:00
Chaim Lev-Ari
4534ccb499 fix(templates): replace templates links (#4083) 2020-07-23 06:41:07 +12:00
Chaim Lev-Ari
6f6bc24efd feat(containers): Ensure users cannot create privileged containers via the API (#3969) (#4077)
* feat(containers): Ensure users cannot create privileged containers via the API

* feat(containers): add rbac check in stack creation

Co-authored-by: Maxime Bajeux <max.bajeux@gmail.com>
2020-07-23 06:38:45 +12:00
Chaim Lev-Ari
4346bf95a7 feat(settings): replace cookies with local storage (#4075)
* fix(datatables): persist state changes

* fix(datatables): persist order

* feat(sidebar): use local storage to store toggle toolbar

* feat(config): use local storage instead of cookies
2020-07-23 06:36:22 +12:00
Chaim Lev-Ari
c9dd6e3851 refactor(agent): replace model with class (#4089) 2020-07-23 06:35:15 +12:00
Chaim Lev-Ari
3a33365133 refactor(agent): node selector (#4084)
* refactor(agent): rename files

* refactor(agent): replace controller with regular export

* refactor(agent): replace function with class

* refactor(agent): replace promise with async

* refactor(agent): rename main file
2020-07-23 06:30:42 +12:00
Chaim Lev-Ari
67069547b8 refactor(agent): replace root file with index (#4096) 2020-07-23 06:29:27 +12:00
Chaim Lev-Ari
6fc923b05b refactor(app): move @babel/polyfill to entry (#4031) 2020-07-22 20:02:39 +12:00
Chaim Lev-Ari
8e7aaa23d5 feat(server): support minimum tls v1.2 (#4076) 2020-07-22 12:16:00 +12:00
Anthony Lapenna
227fbeb1b7 feat(build/windows): update windows dockerfile (#4060)
* feat(build/windows): update windows dockerfile

* feat(build/windows): update windows dockerfile

* feat(build/windows): update windows dockerfile

* feat(build/windows): update windows dockerfile

* feat(build/windows): update windows dockerfile

* feat(build/windows): update Dockerfile
2020-07-21 18:04:55 +12:00
Chaim Lev-Ari
53cddeb283 feat(aci): provide container details page (#4037)
* feat(aci): show basic details

* feat(aci): style container details page

* fix(aci): fix container ip

* feat(aci): provide functions to get single aci resource

* feat(aci): show readable data

* feat(aci): style container instance
2020-07-21 09:08:20 +12:00
Chaim Lev-Ari
4b97cf738e fix(app): use deps injection in router correctly (#4049)
* fix(app): use deps injection in router correctly

* feat(app): guard against using wrong endpoint type

* feat(sidebar): supply endpoint id

* feat(templates): move custom templates to docker
2020-07-21 09:06:37 +12:00
Anthony Lapenna
66a3104805 chore(ci/pull-dog): update pulldog configuration 2020-07-21 08:27:53 +12:00
Chaim Lev-Ari
5a4a10859d feat(aci): remove private network deployment (#4056)
* fix(aci): show error failing container creation

* feat(aci): load network profile list

* feat(aci): allow selection of network profile

* feat(aci): remove public ip toggle

* feat(aci): auto deploy container with public ip

* fix(aci): revert changes
2020-07-20 12:42:30 +12:00
Maxime Bajeux
94676df329 feat(k8s/cluster): Show the cluster leader (#4027)
* feat(cluster): Show the cluster leader

* feat(cluster): Restrict leader label only to admin users

* feat(kubernetes): minor UI update

* feat(endpoint):  move all KubernetesEndpoint related code to a single endpoint sub-folder and change few things

* fix(k8s/cluster): fix conflict leftover

* feat(k8s/cluster): review component leader UX

* refactor(k8s/node): remove useless call to endpoints

* refactor(k8s/endpoint): relocate variable declaration

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-07-20 10:49:49 +12:00
Maxime Bajeux
f765c63c74 feat(cluster): Show the cluster health by showing the status of the underlying cluster components (#4022)
* feat(cluster): add tabs

* feat(cluster): add cluster status informations to cluster detail view

* feat(cluster): change data display

* feat(cluster): prevent regular users to see cluster health

* feat(kubernetes): reviewed ComponentStatus handling

* refactor(kubernetes): review apiToModel for KubernetesComponentStatus

* refactor(kubernetes): remove unused variable

* refactor(kubernetes): clean hasUnhealthyComponentStatus code

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-07-17 11:39:16 +12:00
Maxime Bajeux
833abb24cb feat(k8s/applications): Expose application workload type (#4029)
* feat(applications): Expose application workload type

* feat(application): support daemonSet workload type and add default value
2020-07-17 10:00:15 +12:00
Maxime Bajeux
c9e8021fe8 feat(k8s/logs): Add the ability to download application/stack logs (#4046)
* feat(logs): Add the ability to download application/stack logs

* feat(kubernetes): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-07-17 09:59:27 +12:00
Anthony Lapenna
a452599829 Merge branch 'develop' of github.com:portainer/portainer into develop 2020-07-15 14:08:15 +12:00
Anthony Lapenna
b7e1abf89f feat(kubernetes): rename node value Manager to Master 2020-07-15 13:48:16 +12:00
Maxime Bajeux
f71abb5669 feat(volumes): Expose the provisioner associated to a volume (#4030)
* feat(volumes): Expose the provisioner associated to a volume

* feat(volumes): fix import and add default value to provisioner
2020-07-15 10:55:29 +12:00
Chaim Lev-Ari
3c34fbd8f2 refactor(router): show endpoint id in url (#3966)
* refactor(module): provide basic endpoint id url

* fix(stacks): fix route to include endpointId

* fix(stacks): fix stacks urls

* fix(sidebar): fix urls to docker routes

* refactor(app): set endpoint id on change view

* refactor(dashboard): revert to old version

* refactor(sidebar): revert file

* feat(app): wip load endpoint on route change

* feat(home): show error

* feat(app): load endpoint route

* feat(sidebar): show endpoint per provider

* refactor(app): revert

* refactor(app): clean endpoint startup

* feat(edge): check for edge k8s

* refactor(endpoints): move all modules under endpoint route

* refactor(stacks): move stacks route to docker

* refactor(templates): move templates route to docker

* refactor(app): check endpoint when entering docker module

* fix(app): load endpoint when entering endpoints modules

* feat(azure): check endpoint

* feat(kubernetes): check endpoint

* feat(home): show loading state when loading edge

* style(app): revert small changes

* refactor(sidebar): remove refernce to endpointId

* fix(stacks): fix stacks route

* style(docker): sort routes

* feat(app): change route to home if endpoint failed

* fix(services): guard against empty snapshots

* feat(app): show error when failed to load endpoint

* feat(app): reload home route when failing

* refactor(router): replace resolvers with onEnter
2020-07-15 08:46:38 +12:00
xAt0mZ
1b3e2c8f69 feat(kubernetes): add ingress details (#4013)
* feat(kubernetes): add ingress details

* fix(kubernetes): fix broken ingress generated links + ignore IP retrieval/display info on missing LB ingress ip

* refactor(kubernetes): each ingress rule in apps port mappings has now its own row

* feat(kubernetes): remove protocol column and concat it to container port

* feat(kubernetes): edit display of ingress rules in application details

* feat(kubernetes): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-07-15 08:45:19 +12:00
Chaim Lev-Ari
b09b1b1691 feat(aci): show container ip (#4034) 2020-07-14 21:24:29 +12:00
Maxime Bajeux
8b79f2524d feat(kubernetes): Prevent deployment/edition of resources inside a system namespace (#4039)
* feat(kubernetes): Prevent deployment/edition of resources inside a system namespace

* feat(kubernetes): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-07-14 17:39:13 +12:00
itsconquest
181a6f4553 fix(container-creation): always rebuild exposed ports (#4024) 2020-07-09 17:08:52 +12:00
Anthony Lapenna
cd475a5338 feat(docker): expose port 8000 in Dockerfile (#4016) 2020-07-08 14:13:35 +12:00
Maxime Bajeux
c778ef6404 feat(networks): Support multiple excluded IPs for MACVLAN networks (#3962)
* feat(networks): Support multiple excluded IPs for MACVLAN networks

* feat(networks): add a generated name

* feat(networks): prevent create macvlan network where exclude ip is the same as gateway

* feat(networks): remove auxaddresses validation on submit

* feat(networks): check exclude ip validation on change

* feat(networks): check form validation on change

* feat(networks): clean checkAuxiliaryAddress function
2020-07-08 13:35:52 +12:00
Anthony Lapenna
08095913a6 fix(api): fix issues with old error declaration 2020-07-08 12:25:37 +12:00
Chaim Lev-Ari
db4a5292be refactor(errors): reorganize errors (#3938)
* refactor(bolt): move ErrObjectNotFound to bolt

* refactor(http): move ErrUnauthorized to http package

* refactor(http): move ErrResourceAccessDenied to http errors

* refactor(http): move security errors to package

* refactor(users): move user errors to users package

* refactor(errors): move single errors to their package

* refactor(schedules): move schedule error to package

* refactor(http): move endpoint error to http package

* refactor(docker): move docker errors to package

* refactor(filesystem): move filesystem errors to package

* refactor(errors): remove portainer.Error

* style(chisel): reorder imports

* fix(stacks): remove portainer.Error
2020-07-08 09:57:52 +12:00
Anthony Lapenna
e82833a363 chore(README): update README 2020-07-08 09:53:10 +12:00
Anthony Lapenna
d4456f81ec feat(endpoint-init): remove Azure ACI and remote Docker options (#4015) 2020-07-07 16:55:02 +12:00
Maxime Bajeux
91981c815c feat(volumes): Ensure a unique identifier for volumes (#3879)
* feat(volumes): Ensure a unique identifier for volumes

* feat(volumes): change few things
2020-07-07 12:01:18 +12:00
Chaim Lev-Ari
53b37ab8c8 feat(custom-templates): introduce custom templates (#3906)
* feat(custom-templates): introduce types

* feat(custom-templates): introduce data layer service

* feat(custom-templates): introduce http handler

* feat(custom-templates): create routes and view stubs

* feat(custom-templates): add create custom template ui

* feat(custom-templates): add json keys

* feat(custom-templates): introduce custom templates list page

* feat(custom-templates): introduce update page

* feat(stack): create template from stack

* feat(stacks): create stack from custom template

* feat(custom-templates): disable edit/delete of templates

* fix(custom-templates): fail update on non admin/owner

* fix(custom-templates): add ng-inject decorator

* chore(plop): revert template

* feat(stacks): remove actions column

* feat(stack): add button to create template from stack

* feat(stacks): add empty state for templates

* feat(custom-templates): show templates in a list

* feat(custom-template): replace table with list

* feat(custom-templates): move create template button

* refactor(custom-templates): introduce more fields

* feat(custom-templates): use stack type when creating template

* feat(custom-templates): use same type as stack

* feat(custom-templates): add edit and delete buttons to template item

* feat(custom-templates): customize stack before deploy

* feat(stack): show template details

* feat(custom-templates): move customize

* feat(custom-templates): create description required

* fix(template): show platform icon

* fix(custom-templates): show spinner when creating stack

* feat(custom-templates): prevent user from edit templates

* feat(custom-templates): use resource control for custom templates

* feat(custom-templates): show created templates

* feat(custom-templates): filter templates by stack type

* fix(custom-templates): create swarm or standalone stack

* feat(stacks): filter templates by type

* feat(resource-control): disable resource control on public

* feat(custom-template): apply access control on edit

* feat(custom-template): add form validation

* feat(stack): disable create custom template from external task

* refactor(custom-templates): create template from file and type

* feat(templates): introduce a file handler that returns template docker file

* feat(template): introduce template duplication

* feat(custom-template): enforce unique template name

* fix(template): rename copy button

* fix(custom-template): clear access control selection between templates

* fix(custom-templates): show required fields

* refactor(filesystem): use a constant for temp path
2020-07-07 11:18:39 +12:00
Chaim Lev-Ari
42aa8ceb00 refactor(edge-compute): enforce es6 good practices (#3961)
* refactor(edge-groups): use es6 imports

* refactor(edge-jobs): es6 imports

* refactor(edge-stacks): use es6 imports

* refactor(edge-compute): use es6 imports in components

* refactor(edge-compute): use named imports
2020-07-06 19:35:13 +12:00
Anthony Lapenna
af6bea5acc feat(kubernetes): introduce kubernetes support (#3987)
* feat(kubernetes): fix duplicate published mode

* feat(kubernetes): group port mappings by applications

* feat(kubernetes): updated UX

* feat(kubernetes): updated UX

* feat(kubernetes): new applications list view

* fix(kubernetes): applications - expand ports on row click

* refactor(kubernetes): applications - replace old view with new

* fix(kubernetes): disable access management for default resource pool

* feat(kubernetes): app creation - limit stacks suggestion to selected resource pool

* feat(kubernetes): do not allow access management on system resource pools

* refactor(kubernetes): refactor services

* create view node detail

* compute node status

* compute resource reservations

* resource reservation progress bar

* create applications node datatable

* fix(kubernetes): fix invalid method name

* feat(kubernetes): minor UI changes

* feat(kubernetes): update application inspect UI

* feat(kubernetes): add the ability to copy load balancer IP

* fix(kubernetes): minor fixes on applications view

* feat(kubernetes): set usage level info on progress bars

* fix(kubernetes): fix an issue with duplicate pagination controls

* fix(kubernetes): fix an issue with unexpandable items

* refacto(kubernetes): clean status and resource computation

* fix(kubernetes): remove a bad line

* feat(kubernetes): update application detail view

* feat(kubernetes): change few things on view

* refacto(kubernetes): Corrections relative to PR #13

* refacto(kubernetes): remove old functions

* feat(kubernetes): add application pod logs

* fix(kubernetes): PR #13

* feat(kubernetes): Enable quotas by default

* feat(kubernetes): allow non admin to have access to ressource pool list/detail view

* feat(kubernetes): UI changes

* fix(kubernetes): fix resource reservation computation in node view

* fix(kubernetes): pods are correctly filter by app name

* fix(kubernetes): nodeapplicationsdatatable is correctly reorder by cpu and memory

* fix(kubernetes): nodeapplications datatable is correctly reorder on reload

* feat(kubernetes): update podService

* refacto(kubernetes): rename nodeInspect as node

* refaceto(kubernetes): use colspan 6 instead of colspan 3

* refacto(kubernetes): use genericdatatablecontroller and make isadmin a binding

* refacto(kubernetes): remove not needed lines

* refacto(kubernetes) extract usageLevelInfo as html filter

* refacto(kubernetes): no line break for params

* refacto(kubernetes): change on node converter and filters

* refacto(kubernetes): remove bad indentations

* feat(kubernetes): add plain text informations about resources limits for non admibn user

* refacto(kubernetes): ES6 format

* refacto(kubernetes): format

* refacto(kubernetes): format

* refacto(kubernetes): add refresh callback for nodeapplicationsdatatable

* refacto(kubernetes): change if else structure

* refactor(kubernetes): files naming and format

* fix(kubernetes): remove checkbox and actions on resourcespools view for non admin

* feat(kubernetes): minor UI update

* fix(kubernetes): bind this on getPodsApplications to allow it to access $async

* fix(kubernetes): bind this on getEvents to allow it to access $async

* fix(kubernetes): format

* feat(kubernetes): minor UI update

* feat(kubernetes): add support for container console

* fix(kubernetes): fix a merge issue

* feat(kubernetes): update container console UI

* fix(api): fix typo

* feat(api): proxy pod websocket to agent

* fix(api): fix websocket pod proxy

* refactor(kubernetes): uniformize k8s merge comments

* refactor(kubernetes): update consoleController

* feat(kubernetes): prevent the removal of the default resource pool (#38)

* feat(kubernetes): show all applications running inside the resource pool (#35)

* add new datatable

* feat(kubernetes): add resource pool applications datatable to resource pool detail view

* refacto(kubernetes): factorise computeResourceReservation

* fix(kubernetes): colspan 6 to colspan 5

* fix(kubernetes): rename resourceReservationHelper into kubernetesResourceReservationHelper

* fix(kubernetes): add await to avoid double diggest cycles

* feat(kubernetes): add link to application name

* fix(kubernetes): change kubernetes-resource-pool-applications-datatable table key

* fix(kubernetes): change wording

* feat(kubernetes): add proper support for persisted folders (#36)

* feat(kubernetes): persistent volume mockups

* feat(kubernetes): persistent volume mockups

* feat(kubernetes): update persisted folders mockups

* feat(kubernetes): endpoint configure storage access policies

* fix(kubernetes): restrict advanced deployment to admin

* refactor(kubernetes): storageclass service / rest / model

* refactor(kubernetes): params/payload/converter pattern for deployments and daemonsets

* feat(kubernetes): statefulset management for applications

* fix(kubernets): associate application and pods

* feat(kubernetes): statefulset support for applications

* refactor(kubernetes): rebase on pportainer/k8s

* fix(kubernetes): app create - invalid targetPort on loadbalancer

* fix(kubernetes): internal services showed as loadbalancer

* fix(kubernetes): service ports creation / parsing

* fix(kubernetes): remove ports on headless services + ensure nodePort is used only for Cluster publishing

* fix(kubernetes): delete headless service on statefulset delete

* fix(kubernetes): statefulset replicas count display

* refactor(kubernetes): rebase on pportainer/k8s

* refactor(kubernetes): cleanup

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* fix(kubernetes): remove mockup routes

* feat(kubernetes): only display applications running on node/in resource pool when there are any

* feat(kubernetes): review resource reservations and leverage requests instead of limits (#40)

* fix(kubernetes): filter resource reservation by app in node view (#48)

* refactor(kubernetes): remove review comment

* chore(version): bump version number

* refactor(kubernetes): remove unused stacks view and components

* feat(kubernetes): update CPU slider step to 0.1 for resource pools (#60)

* feat(kubernetes): round up application CPU values (#61)

* feat(kubernetes): add information about application resource reservat… (#62)

* feat(kubernetes): add information about application resource reservations

* feat(kubernetes): apply kubernetesApplicationCPUValue to application CPU reservation

* refactor(kubernetes): services layer with models/converter/payloads (#64)

* refactor(kubernetes): services layer with models/converter/payloads

* refactor(kubernetes): file rename and comment update

* style(kubernetes): replace strings double quotes with simple quotes

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* fix(kubernetes): filter application by node in node detail view (#69)

* fix(kubernetes): filter applications by node

* fix(kubernetes): remove js error

* refactor(kubernetes): delete resource quota deletion process when deleting a resource pool (#68)

* feat(kubernetes): enforce valid resource reservations and clarify its… (#70)

* feat(kubernetes): enforce valid resource reservations and clarify its usage

* feat(kubernetes): update instance count input behavior

* feat(kubernetes): resource pools labels (#71)

* feat(kubernetes): resource pools labels

* fix(kubernetes): RP/RQ/LR owner label

* feat(kubernetes): confirmation popup on RP delete (#76)

* feat(kubernetes): application labels (#72)

* feat(kubernetes): application labels

* feat(kubernetes): display application owner in details when available

* style(kubernetes): revert StackName column labels

* fix(kubernetes): default displayed StackName

* feat(kubernetes): remove RQ query across cluster (#73)

* refactor(kubernetes): routes as components (#75)

* refactor(kubernetes): routes as components

* refactor(kubernetes): use component  lifecycle hook

* refactor(kubernetes): files naming consistency

* fix(kubernetes): fix invalid component name for cluster view

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* feat(kubernetes): update portaineruser cluster role policy rules (#78)

* refactor(kubernetes): remove unused helper

* fix(kubernetes): fix invalid reload link in cluster view

* feat(kubernetes): add cluster resource reservation (#77)

* feat(kubernetes): add cluster resource reservation

* fix(kubernetes): filter resource reservation with applications

* fix(kubernetes): fix indent

* refacto(kubernetes): extract megabytes value calc as resourceReservationHelper method

* fix(kubernetes): remove unused import

* refacto(kubernetes): add resourcereservation model

* fix(kubernetes): add parenthesis on arrow functions parameters

* refacto(kubernetes): getpods in applicationService getAll

* fix(kubernetes): let to const

* fix(kubernetes): remove unused podservice

* fix(kubernetes): fix computeResourceReservation

* fix(kubernetes): app.pods to app.Pods everywhere and camelcase of this.ResourceReservation

* feat(kubernetes): configurations list view (#74)

* feat(kubernetes): add configuration list view

* feat(kubernetes): add configurations datatable

* feat(kubernetes): add item selection

* feat(kubernetes): allow to remove configuration

* feat(kubernetes): allow non admin user to see configurations

* fix(kubernetes): configurations view as component

* feat(kubernetes): remove stack property for secret and configurations

* fix(kubernetes): update import

* fix(kubernetes): remove secret delete payload

* fix(kubernetes): rename configuration model

* fix(kubernetes): remove configmap delete payload

* fix(Kubernetes): fix configuration getAsync

* fix(kubernetes): extract params as variables

* refacto(kubernetes): extract configurations used lines as helper

* fix(kubernetes): add verification of _.find return value

* fix(kubernetes): fix kubernetes configurations datatable callback

* refacto(Kubernetes): extract find before if

* fix(kubernetes): replace this by KubernetesConfigurationHelper in static method

* fix(Kubernetes): fix getASync

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* review(kubernetes): todo comments (#80)

* feat(kubernetes): minor UI update

* feat(kubernetes): round max cpu value in application creation

* feat(kubernetes): minor UI update

* fix(kubernetes): no-wrap resource reservation bar text (#89)

* docs(kubernetes): add review for formValues to resource conversion (#91)

* feat(kubernetes): configuration creation view (#82)

* feat(kubernetes): create configuration view

* feat(kubernetes): add advanced mode and create entry from file

* fix(kubernetes): fix validation issues

* fix(kubernetes): fix wording

* fix(kubernetes): replace data by stringdata in secret payloads

* fix(kubernetes): rename KubernetesConfigurationEntry to KubernetesConfigurationFormValuesDataEntry

* refacto(kubernetes): add isSimple to formValues and change configuration creation pattern

* fix(kubernetes): fix some bugs

* refacto(kubernetes): renaming

* fix(kubernetes): fix few bugs

* fix(kubernetes): fix few bugs

* review(kubernetes): refactor notices

Co-authored-by: xAt0mZ <baron_l@epitech.eu>

* feat(kubernetes): rename codeclimate file

* feat(kubernetes): re-enable codeclimate

* feat(project): update codeclimate configuration

* feat(project): update codeclimate configuration

* feat(project): update codeclimate configuration

* feat(kubernetes): minor UI update

* feat(project): update codeclimate

* feat(project): update codeclimate configuration

* feat(project): update codeclimate configuration

* feat(kubernetes): configuration details view (#93)

* feat(kubernetes): configuration details view

* fix(kubernetes): fix wording

* fix(kubernetes): fix update button

* fix(kubernetes): line indent

* refacto(kubernetes): remove conversion

* refacto(kubernetes): remove useless line

* refacto(kubernetes): remove useless lines

* fix(kubernetes): revert error handling

* fix(kubernetes): fix wording

* fix(kubernetes): revert line deletion

* refacto(kubernetes): change data mapping

* fix(kubernetes): create before delete

* fix(kubernetes): fix duplicate bug

* feat(kubernetes): configurations in application creation (#92)

* feat(kubernetes): application configuration mockups

* feat(kubernetes): update mockup

* feat(kubernetes): app create - dynamic view for configurations

* feat(kubernetes): app create - configuration support

* refactor(kubernetes): more generic configuration conversion function

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* feat(kubernetes): automatically display first entry in configuration creation

* feat(kubernetes): minor UI update regarding applications and configurations

* feat(kubernetes): update Cluster icon in sidebar

* feat(kubernetes): volumes list view (#112)

* feat(kubernetes): add a feedback panel on main views (#111)

* feat(kubernetes): add a feedback panel on main views

* feat(kubernetes): add feedback panel to volumes view

* fix(kubernetes): isolated volumes showed as unused even when used (#116)

* feat(kubernetes): remove limit range from Portainer (#119)

* limits instead of requests (#121)

* feat(kubernetes): volume details (#117)

* feat(kubernetes): volume details

* fix(kubernetes): yaml not showed

* feat(kubernetes): expandable stacks list (#122)

* feat(kubernetes): expandable stacks list

* feat(kubernetes): minor UI update to stacks datatable

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* feat(kubernetes): uibprogress font color (#129)

* feat(kubernetes): minor UI update to resource reservation component

* feat(kubernetes): automatically select a configuration

* refactor(kubernetes): remove comment

* feat(kubernetes): minor UI update

* feat(kubernetes): add resource links and uniformize view headers (#133)

* feat(kubernetes): prevent removal of system configurations (#128)

* feat(kubernetes): prevent removal of system configurations

* fix(kubernetes): KubernetesNamespaceHelper is not a function

* refacto(kubernetes): change prevent removal pattern

* fix(kubernetes): remove unused dependencies

* fix(kubernetes): fix configuration used label (#123)

* fix(kubernetes): fix used configurations

* fix(kubernetes): remove console log

* feat(kubernetes): rename configuration types (#127)

* refacto(kubernetes): fix wording and use configMap instead of Basic in the code

* feat(kubernetes): prevent the removal of system configuration

* fix(kubernetes): remove feat on bad branch

* fix(kubernetes): rename configuration types

* refacto(kubernetes): use a numeric enum and add a filter to display the text type

* refacto(kubernetes): fix wording and use configMap instead of Basic in the code

* feat(kubernetes): prevent the removal of system configuration

* fix(kubernetes): remove feat on bad branch

* fix(kubernetes): rename configuration types

* refacto(kubernetes): use a numeric enum and add a filter to display the text type

* fix(kubernetes): rename file and not use default in switch case

* feat(kubernetes): update advanced deployment UI/UX (#130)

* feat(kubernetes): update advanced deployment UI/UX

* feat(kubernetes): review HTML tags indentation

* feat(kubernetes): applications stacks delete (#135)

* fix(kubernetes): multinode resources reservations (#118)

* fix(kubernetes): filter pods by node

* fix(kubernetes): fix applications by node filter

* fix(kubernetes): filter pods by node

* Update app/kubernetes/views/cluster/node/nodeController.js

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* feat(kubernetes): limit usage of pod console view (#136)

* feat(kubernetes): add yaml and events to configuration details (#126)

* feat(kubernetes): add yaml and events to configuration details

* fix(kubernetes): fix errors on secret details view

* fix(kubernetes): display only events related to configuration

* fix(kubernetes): fix applications by node filter

* fix(kubernetes): revert commit on bad branch

* refacto(kubernetes): refacto configmap get yaml function

* refacto(kubernetes): add yaml into converter

* feat(kubernetes): improve application details (#141)

* refactor(kubernetes): remove applications retrieval from volume service

* feat(kubernetes): improve application details view

* feat(kubernetes): update kompose binary version (#143)

* feat(kubernetes): update kubectl version (#144)

* refactor(kubernetes): rename portainer system namespace (#145)

* feat(kubernetes): add a loading view indicator (#140)

* feat(kubernetes): add an example of view loading indicator

* refactor(css): remove comment

* feat(kubernetes): updated loading pattern

* feat(kubernetes): add loading indicator for resource pool views

* feat(kubernetes): add loading indicator for deploy view

* feat(kubernetes): add loading view indicator to dashboard

* feat(kubernetes): add loading view indicator to configure view

* feat(kubernetes): add loading indicator to configuration views

* feat(kubernetes): add loading indicator to cluster views

* feat(kubernetes): rebase on k8s branch

* feat(kubernetes): update icon size

* refactor(kubernetes): update indentation and tag format

* feat(kubernetes): backend role validation for stack deployment (#147)

* feat(kubernetes): show applications when volume is used

* feat(kubernetes): set empty value when node is not set

* feat(kubernetes): update configuration UI/UX

* feat(kubernetes): update configuration UX

* fix(kubernetes): Invalid value for a configuration (#139)

* fix(kubernetes): Invalid value for a configuration

* fix(kubernetes): remove auto JSON convertion for configMap ; apply it for RPool Accesses only

* refactor(kubernetes): remove unneeded line

* fix(kubernetes): remove default JSON parsing on configMap API retrieval

Co-authored-by: xAt0mZ <baron_l@epitech.eu>

* feat(kubernetes): applications table in configuration details (#154)

* feat(kubernetes): Add the ability to filter system resources (#142)

* feat(kubernetes): hide system configurations

* feat(kubernetes): Add the ability to filter system resources

* feat(kubernetes): add the ability to hide system resources on volumes

* fix(kubernetes): fix few issue in volumesDatatableController

* fix(kubernetes): fix applications / ports / stacks labels

* feat(kubernetes): add volumes and configurations to dashboard (#152)

* feat(kubernetes): event warning indicator (#150)

* feat(kubernetes): event warning indicator for applications

* refactor(kubernetes): refactor events indicator logic

* feat(kubernetes): add event warning indicator to all resources

* feat(kubernetes): fix missing YAML panel for node (#157)

* feat(kubernetes): revised application details view (#159)

* feat(kubernetes): revised application details view

* refactor(kubernetes): remove comment

* feat(kubernetes): rebase on k8s

* refactor(kubernetes): remove extra line

* feat(kubernetes): update kubernetes beta feedback panel locations (#161)

* feat(kubernetes): stack logs (#160)

* feat(kubernetes): stack logs

* fix(kubernetes): ignore starting pods

* fix(kubernetes): colspan on expandable stack applications table

* feat(kubernetes): add an information message about system resources (#163)

* fix(kubernetes): fix empty panel being display in cluster view (#165)

* fix(kubernetes): Invalid CPU unit for node (#156)

* fix(kubernetes): Invalid CPU unit for node

* fix(kubernetes): Invalid CPU unit for node

* refacto(kubernetes): extract parseCPU function in helper

* refacto(kubernetes): rewrite parseCPU function

* feat(kubernetes): add the kube-node-lease namespace to system namespaces (#177)

* feat(kubernetes): tag system applications on node details view (#175)

* feat(kubernetes): tag system applications on node details view

* fix(kubernetes): remove system resources filter

* feat(kubernetes): review UI/UX around volume size unit (#178)

* feat(kubernetes): updates after review (#174)

* feat(kubernetes): update access user message

* feat(kubernetes): relocate resource pool to a specific form section

* feat(kubernetes): review responsiveness of port mappings

* feat(kubernetes): clarify table settings

* feat(kubernetes): add resource reservation summary message

* feat(kubernetes): review wording (#182)

* feat(kubernetes): application stack edit (#179)

* feat(kubernetes): update UI -- update action missing

* feat(kubernetes): application stack update

* feat(kubernetes): change services stacks

* feat(kubernetes): hide default-tokens + prevent remove (#183)

* feat(kubernetes): hide default-tokens + prevent remove

* feat(kubernetes): do not display unused label for system configurations

* fix(kubernetes): minor fix around showing system configurations

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* feat(kubernetes): rebase on k8s branch (#180)

* fix(kubernetes): prevent the display of system resources in dashboard (#186)

* fix(kubernetes): prevent the display of system resources in dashboard

* fix(kubernetes): prevent the display of frontend filtered resource pools

* feat(kubernetes): support downward API for env vars in application details (#181)

* feat(kubernetes): support downward API for env vars in application details

* refactor(kubernetes): remove comment

* feat(kubernetes): minor UI update

* feat(kubernetes): remove Docker features (#189)

* chore(version): bump version number (#187)

* chore(version): bump version number

* feat(kubernetes): disable update notice

* feat(kubernetes): minor UI update

* feat(kubernetes): minor UI update

* feat(kubernetes): form validation (#170)

* feat(kubernetes): add published node port value check

* feat(kubernetes): add a dns compliant validation

* fix(kubernetes): fix port range validation

* feat(kubernetes): lot of form validation

* feat(kubernetes): add lot of form validation

* feat(kubernetes): persisted folders size validation

* feat(kubernetes): persisted folder path should be unique

* fix(kubernetes): fix createResourcePool button

* fix(kubernetes): change few things

* fix(kubernetes): fix slider memory

* fix(kubernetes): fix duplicates on dynamic field list

* fix(kubernetes): remove bad validation on keys

* feat(kubernetes): minor UI enhancements and validation updates

* feat(kubernetes): minor UI update

* fix(kubernetes):  revert on slider fix

* review(kubernetes): add future changes to do

* fix(kubernetes): add form validation on create application memory slider

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
Co-authored-by: xAt0mZ <baron_l@epitech.eu>

* feat(kubernetes): remove Docker related content

* feat(kubernetes): update build system to remove docker binary install

* fix(kubernetes): fix an issue with missing user settings

* feat(kubernetes): created column for apps and resource pools (#184)

* feat(kubernetes): created column for apps and resource pools

* feat(kubernetes): configurations and volumes owner

* feat(kubernetes): rename datatables columns

* fix(kubernetes): auto detect statefulset headless service name (#196)

* fix(applications): display used configurations (#198)

* feat(kubernetes): app details - display data access policy (#199)

* feat(kubernetes): app details - display data access policy

* feat(kubernetes): tooltip on data access info

* feat(kubernetes): move DAP tooltip to end of line

* feat(kubernetes): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* fix(kubernetes): fix an issue when updating the local endpoint (#204)

* fix(kubernetes): add unique key to configuration overriden key path field (#207)

* feat(kubernetes): tag applications as external (#221)

* feat(kubernetes): tag applications as external first approach

* feat(kubernetes): tag applications as external

* feat(kubernetes): Use ibytes as the default volume size unit sent to the Kubernetes API (#222)

* feat(kubernetes): Use ibytes as the default volume size unit sent to the Kubernetes API

* fix(kubernetes): only display b units in list and details views

* feat(kubernetes): add note to application details (#212)

* feat(kubernetes): add note to application details

* fix(kubernetes): remove eslintcache

* feat(kubernetes): update application note UI

* feat(kubernetes): add an update button to the note form when a note is already associated to an app

* feat(kubernetes): fix with UI changes

* fix(kubernetes): change few things

* fix(kubernetes): remove duplicate button

* fix(kubernetes): just use a ternary

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* feat(kubernetes): fix data persistence display for isolated DAP (#223)

* feat(kubernetes): add a quick action to copy application name to clipboard (#225)

* feat(kubernetes): revert useless converter changes (#228)

* feat(kubernetes): edit application view (#200)

* feat(kubernetes): application to formValues conversion

* feat(kubernetes): extract applicationFormValues conversion as converter function

* feat(kubernetes): draft app patch

* feat(kubernetes): patch on all apps services + service service + pvc service

* feat(kubernetes): move name to labels and use UUID as kubernetes Name + patch recreate if necessary

* feat(kubernetes): move user app name to label and use UUID for Kubernetes Name field

* feat(kubernetes): kubernetes service patch mechanism

* feat(kubernetes): application edit

* feat(kubernetes): remove stack edit on app details

* feat(kubernetes): revert app name saving in label - now reuse kubernetes Name field

* feat(kubernetes): remove the ability to edit the DAP

* feat(kubernetes): cancel button on edit view

* feat(kubernetes): remove ability to add/remove persisted folders for SFS edition

* feat(kubernetes): minor UI update and action changes

* feat(kubernetes): minor UI update

* feat(kubernetes): remove ability to edit app volumes sizes + disable update button if no changes are made + codeclimate

* fix(kubernetes): resource reservation sliders in app edit

* fix(kubernetes): patch returned with 422 when trying to create nested objects

* fix(kubernetes): changing app deployment type wasn't working (delete failure)

* style(kubernetes): codeclimate

* fix(kubernetes): app edit - limits sliders max value

* feat(kubernetes): remove prefix on service name as we enforce DNS compliant app names

* fix(kubernetes): edit app formvalues replica based on target replica count and not total pods count

* fix(kubernetes): disable update for RWO on multi replica + delete service when changing app type

* fix(kubernetes): app details running / target pods display

* feat(kubernetes): add partial patch for app details view

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* feat(kubernetes): disable edit capability for external and system apps (#233)

* feat(kubernetes): minor UI update

* fix(kubernetes): edit application issues (#235)

* feat(kubernetes): disable edition of load balancer if it's in pending state

* fix(kubernetes): now able to change from LB to other publishing types

* feat(kuberntes): modal on edit click to inform on potential service interruption

* feat(kubernetes): hide note when empty + add capability to collapse it

* fix(kubernetes): UI/API desync + app update button enabled in some cases where it shouldn't be

* fix(kubernetes): all apps are now using rolling updates with specific conditions

* style(kubernetes): code indent

* fix(kubernetes): disable sync process on endpoint init as current endpoint is not saved in client state

* fix(kubernetes): sliders refresh on app create + app details bad display for sfs running pods

* feat(kubernetes): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* feat(kubernetes): bump up kubectl version to v1.18.0

* feat(kubernetes): when refreshing a view, remember currently opened tabs (#226)

* feat(kubernetes): When refreshing a view, remember currently opened tabs

* fix(kubernetes): only persist the current tab inside the actual view

* fix(kubernetes): not working with refresh in view header

* fix(kubernetes): skip error on 404 headless service retrieval if missconfigured in sfs (#242)

* refactor(kubernetes): use KubernetesResourcePoolService instead of KubernetesNamespaceService (#243)

* fix(kubernetes): create service before app to enforce port availability (#239)

* fix(kubernetes): external flag on application ports mappings datatable (#245)

* refactor(kubernetes): remove unused KubernetesResourcePoolHelper (#246)

* refactor(kubernetes): make all *service.getAllAsync functions consistent (#249)

* feat(kubernetes): Tag external applications in the application table of the resource pool details view (#251)

* feat(kubernetes): add ability to redeploy application (#240)

* feat(kubernetes): add ability to redeploy application

* feat(kubernetes): allow redeploy for external apps

* Revert "feat(kubernetes): allow redeploy for external apps"

This reverts commit 093375a7e93c1a07b845ebca1618da034a97fbcd.

* refactor(kubernetes): use KubernetesPodService instead of REST KubernetesPods (#247)

* feat(kubernetes): prevent configuration properties edition (#248)

* feat(kubernetes): prevent configuration properties edition

* feat(kubernetes): Relocate the Data/Actions to a separate panel

* feat(kubernetes): remove unused functions

* feat(kubernetes): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* refactor(kubernetes): Simplify the FileReader usage (#254)

* refactor(kubernetes): simplify FileReader usage

* refactor(kubernetes): Simplify FileReader usage

* refactor(kubernetes): rename e as event for readability

* feat(kubernetes): Tag system Configs in the Config details view (#257)

* refactor(kubernetes): Refactor the isFormValid function of multiple controllers (#253)

* refactor(kubernetes): refactor isFormValid functions in configurations

* refactor(kubernetes): refactor isformValid functions in create application

* refactor(kubernetes): remove duplicate lines

* refactor(kubernetes): remove commented line

* feat(kubernetes): Tag external volumes and configs (#250)

* feat(kubernetes): Tag external volumes and configs

* feat(kubernetes): remove .eslintcache

* feat(kubernetes): change few things

* feat(kubernetes): don't tag system configuration as external

* feat(kubernetes): minor UI update

* feat(kubernetes): extract inline css and clean all tags

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* fix(kubernetes): daemon set edit (#258)

* fix(kubernetes): persistent folder unit parsing

* fix(kubernetes): edit daemonset on RWO storage

* fix(kubernetes): external SFS had unlinked volumes (#264)

* feat(kubernetes): prevent to override two different configs on the same filesystem path (#259)

* feat(kubernetes): prevent to override two different configs on the same filesystem path

* feat(kubernetes): The validation should only be triggered across Configurations.

* feat(kubernetes): fix validations issues

* feat(kubernetes): fix form validation

* feat(kubernetes): fix few things

* refactor(kubernetes): Review the code mirror component update for configurations (#260)

* refactor(kubernetes): extract duplicate configuration code into a component

* refactor(kubernetes): fix form validation issues

* refactor(kubernetes): fix missing value

* refactor(kubernetes): remove useless await

* feat(kubernetes): Update the shared access policy configuration for Storage (#263)

* feat(kubernetes): Update the shared access policy configuration for Storage

* Update app/kubernetes/models/storage-class/models.js

* feat(kubernetes): remove ROX references and checks

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
Co-authored-by: xAt0mZ <baron_l@epitech.eu>

* feat(kubernetes): provide the remove/restore UX for environment variables when editing an application (#261)

* feat(kubernetes): Provide the remove/restore UX for environment variables when editing an application

* feat(kubernetes): fix ui issue

* feat(kubernetes): change few things

* fix(kubernetes): Invalid display for exposed ports in accessing the application section (#267)

* feat(kubernetes): application rollback (#269)

* feat(kubernetes): retrieve all versions of a deployment

* feat(kubernetes): application history for all types

* feat(kubernetes): deployment rollback

* feat(kubernetes): daemonset / statefulset rollback

* feat(kubernetes): remove the revision selector and rollback on previous version everytime

* feat(kubernetes): minor UI changes

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* feat(kubernetes): reservations should be computed based on requests instead of limits (#268)

* feat(kubernetes): Reservations should be computed based on requests instead of limits

* feat(kubernetes): use requests instead of limits in application details

* feat(kubernetes): removes unused limits

* feat(kubernetes): Not so useless

* feat(kubernetes): use service selectors to bind apps and services (#270)

* feat(kubernetes): use service selectors to bind apps and services

* Update app/kubernetes/services/statefulSetService.js

* style(kubernetes): remove comment block

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* chore(version): bump version number

* feat(kubernetes): update feedback panel text

* chore(app): add prettier to k8s

* style(app): apply prettier to k8s codebase

* fix(kubernetes): Cannot read property 'port' of undefined (#272)

* fix(kubernetes): Cannot read property 'port' of undefined

* fix(kubernetes): concat app ports outside publishedports loop

* fix(application): fix broken display of the persistence layer (#274)

* chore(kubernetes): fix conflicts

* chore(kubernetes): fix issues related to conflict resolution

* refactor(kubernetes): refactor code related to conflict resolution

* fix(kubernetes): fix a minor issue with assets import

* chore(app): update yarn.lock

* fix(application): ports mapping are now correctly detected (#300)

* fix(build-system): fix missing docker binary download step

* feat(kubernetes): application auto scaling details (#301)

* feat(kubernetes): application auto scaling details

* feat(kubernetes): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* feat(kubernetes): Introduce a "used by" column in the volume list view (#303)

Co-authored-by: xAt0mZ <baron_l@epitech.eu>
Co-authored-by: Maxime Bajeux <max.bajeux@gmail.com>
Co-authored-by: xAt0mZ <xAt0mZ@users.noreply.github.com>
2020-07-06 11:21:03 +12:00
Chaim Lev-Ari
24528ecea8 feat(edge-compute): move host jobs to edge (#3840)
* feat(endpoints): create an associated endpoints selector

* feat(schedules): remove edge specific explanations

* refactor(schedule): replace multi-endpoint-selector

* refactor(schedule): move controller to single file

* refactor(endpoints): remove multi-endpoint-selector

* feat(edge): rename host jobs to edge jobs

* feat(edge-jobs): remove edge warning

* refactor(edge-jobs): move schedule pages to edge

* refactor(edge-jobs): mv views to edgeJobs

* refactor(edge-jobs): rename edge jobs

* refactor(edge-jobs): move services to edge

* refactor(edge-jobs): move tasks datatable

* fix(edge-jobs): fix import

* fix(edge-jobs): use right services

* feat(settings): adjust host management description

* feat(edge-jobs): introduce interfaces and types

* feat(edge-jobs): implement bolt service

* refactor(edge-jobs): replace schedule routes

* refactor(edge-job): replace Schedule service

* refactor(edge-jobs): remove job_script_exec

* refactor(host): remove jobs table

* feat(edge-jobs): replace schedule

* feat(edge-jobs): load file on inspect

* fix(edge-job): parse cron correctly

* feat(edge-jobs): show tasks

* feat(host): rename tooltip

* refactor(host): remove old components

* refactor(main): remove schedule types

* refactor(snapshot): replace job service with snapshot service

* refactor(jobs): remove jobs form and datatable

* feat(edge-jobs): create db migration

* fix(main): start snapshot service with correct interval

* feat(settings): change host tooltip

* feat(edge-jobs): load endpoints

* fix(edge-job): disable form submit when form is invalid

* refactor(edge-compute): use const

* refactor(edge-jobs): use generic controller

* refactor(edge-jobs): replace $scope with controllerAs

* refactor(edge-jobs): replace routes with components

* refactor(edge-jobs): replace functions with classes

* refactor(edge-jobs): use async/await

* refactor(edge-jobs): rename functions

* feat(edge-jobs): introduce beta panel

* feat(edge-jobs): allow single character names

* fix(snapshot): run snapshot in coroutine

* feat(edge-jobs): add logs status

* feat(filesystem): add edge job logs methods

* feat(edge-jobs): intoduce edge jobs tasks api

* feat(edge-jobs): remove schedule task model

* fix(fs): build edge job task file path

* fix(edge-jobs): update task meta

* fix(edge-jobs): return a list of endpoints

* feat(edge-jobs): update logs from agent

* feat(edge-jobs): collect logs

* feat(edge-jobs): rename url

* feat(edge-jobs): refresh to same tab

* feat(edge-jobs): remove old info

* refactor(edge-jobs): rename script path json

* fix(edge-job): save file before adding job

* feat(edge-job): show retrieving logs label

* feat(edge-job): replace cron with 5 places

* refactor(edge-jobs): replace tasks with results

* feat(edge-jobs): add auto refresh until logs are collected

* feat(edge-jobs): fix column size

* feat(edge-job): display editor

* feat(edge-job): add name validation

* feat(edge-job): set default time for 1 hour from now

* feat(edge-job): add validation for cron format

* feat(edge-job): add a note about timezone

* fix(edge-job): replace regex

* fix(edge-job): check for every minute cron

* style(edge-jobs): add reference for cron regex

* refactor(edge-jobs): rename migration name

* refactor(edge-job): rename edge job response

* refactor(snapshot): rename snapshot endpoint method

* refactor(edge-jobs): move tasks handler to edgejobs

* feat(security): introduce a middleware for edge compute operations

* feat(edge-job): use edge compute middleware

* feat(edge-groups): filter http actions based on edge setting

* fix(security): return from edge bouncer if failed

* feat(edge-stacks): filter http actions based on edge setting

* feat(edge-groups): show error when failed to load groups

* refactor(db): remove edge-jobs migration

* refactor(migrator): remove unused dependency

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-06-25 15:25:51 +12:00
xAt0mZ
b6f5d8f90e fix(auth): autofocus on login field (#3955) 2020-06-25 10:24:45 +12:00
Chaim Lev-Ari
ec9055f0e6 fix(endpoints): hide edge endpoint url (#3949) 2020-06-23 17:06:53 +12:00
Chaim Lev-Ari
40f9078d80 style(docker): replace icons for containers and volumes (#3950)
* fix(sidebar): replace icons for containers and volumes

* fix(icons): replace icons for containers and volumes
2020-06-23 11:46:56 +12:00
Chaim Lev-Ari
5760648970 chore(plop): fix controller import in template (#3948) 2020-06-22 19:38:22 +12:00
itsconquest
7bd3d6e44a feat(project): introduce toolkit for containerized dev (#3863)
* feat(project): introduce toolkit for containerized dev

* feat(project): clean up localserver shell cmd

* feat(project): add install of yarn deps to grunt

* feat(project): update gruntfile.js

* Introduce an ARG statement for the GO_VERSION

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-06-17 13:36:11 +12:00
Chaim Lev-Ari
0b6dbec305 refactor(auth): remove login retry with $sanitize (#3923)
* refactor(auth): remove update-password view

* refactor(auth): remove auth retry with $sanitize
2020-06-17 11:41:39 +12:00
Chaim Lev-Ari
7c3b83f6e5 refactor(portainer): introduce internal package (#3924)
* refactor(auth): move auth helpers to internal package

* refactor(edge-compute): move edge helpers to internal package

* refactor(tags): move tags helper to internal package

* style(portainer): sort imports
2020-06-16 19:58:16 +12:00
Chaim Lev-Ari
5d7ba0baba feat(edge-compute): add flag to auto enable Edge compute features (#3922) 2020-06-16 19:55:45 +12:00
Anthony Lapenna
89fb3c8dae feat(pulldog): configure expiry 2020-06-15 13:31:28 +12:00
Chaim Lev-Ari
24888fbbae feat(users): prevent the removal of initial admin account (#3912)
* feat(users): prevent the removal of initial admin account

* feat(users): disabled init admin delete button
2020-06-15 11:48:58 +12:00
xAt0mZ
381e372c4c chore(app): clean and update dependencies (#3917) 2020-06-12 09:06:41 +12:00
Anthony Lapenna
e0c47b644e feat(pulldog): update configuration 2020-06-11 10:51:49 +12:00
xAt0mZ
06911ad2c6 refactor(app): remove all VMWARE_VIC related code (#3914) 2020-06-11 07:59:11 +12:00
Chaim Lev-Ari
b02749f877 feat(auth): add custom user timeout (#3871)
* feat(auth): introduce new timeout constant

* feat(auth): pass timeout from handler

* feat(auth): add timeout selector to auth settings view

* feat(settings): add user session timeout property

* feat(auth): load user session timeout from settings

* fix(settings): use correct time format

* feat(auth): remove no-auth flag

* refactor(auth): move timeout mgmt to jwt service

* refactor(client): remove no-auth checks from client

* refactor(cli): remove defaultNoAuth

* feat(settings): create settings with default user timeout value

* refactor(db): save user session timeout always

* refactor(jwt): return error

* feat(auth): set session timeout in jwt service on update

* feat(auth): add description and time settings

* feat(auth): parse duration

* feat(settings): validate user timeout format

* refactor(settings): remove unneccesary import
2020-06-09 21:55:36 +12:00
Chaim Lev-Ari
b58c2facfe revert(azure): revert removal (#3890)
* Revert "fix(sidebar): show docker sidebar when needed (#3852)"

This reverts commit 59da17dde4.

* Revert "refactor(azure): remove Azure ACI endpoint support (#3803)"

This reverts commit 493de20540.
2020-06-09 14:43:32 +12:00
Chaim Lev-Ari
25ca036070 feat(users): add the ability to rename a user (#3884)
* feat(users): update username in server

* feat(users): add username text field

* fix(users): rename label and change buttons size

* feat(users): change update message

* feat(users): disable submit when not changed

* feat(users): confirm updating username

* feat(users): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-06-09 14:42:40 +12:00
yunfan
7325407f5f fix(endpoint): fix invalid Edge deployment command (#3908) 2020-06-08 16:57:34 +12:00
Anthony Lapenna
f0fafd7537 chore(project): update pull-dog.json 2020-06-06 05:26:10 +12:00
Chaim Lev-Ari
d8d3baf18e refactor(client): move assets folder into app and remove rdash-ui dep (#3883)
* refactor(assets): use rdash css

* chore(build): remove rdash dep

* refactor(client): move assets folder into app
2020-06-05 11:03:13 +12:00
Chaim Lev-Ari
a0ba531fed fix(registries): check same url for gitlab (#3870) 2020-06-04 18:50:02 +12:00
Chaim Lev-Ari
9f4631bb6d feat(edge-compute): add specific edge endpoint checkin interval (#3855)
* feat(endpoint): send custom checkin interval

* feat(endpoint): update edge checkin interval

* feat(endpoint): save checkin interval

* feat(endpoints): create endpoint with checkin interval

* feat(endpoints): change tooltip

* fix(edge-compute): fix typos

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* fix(endpoints): show default interval

* fix(endpoint): rename checkin property

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
2020-06-04 17:35:09 +12:00
Chaim Lev-Ari
766ced7cb1 chore(project): add angular components code snippets (#3649)
* chore(project): add angular components code snippets

* chore(project): add plopjs templates

* feat(project): use class in controller template

* chore(client): rename generators

* chore(vscode): fix controller snippets

* chore(git): ignore only specific files in .vscode

* chore(plop): move generators to app

* chore(plop): fix portainer module

* fix(git): fix gitignore vscode

* chore(vscode): remove symling to code-snippets

* refactor(build): move plop templates to root

* feat(build): add readme for plop
2020-06-04 17:01:31 +12:00
Anthony Lapenna
38066ece33 feat(project): re-introduce pull-dog 2020-06-03 11:50:39 +12:00
Anthony Lapenna
334c015f81 fix(bolt): migrate empty templates URL settings (#3856) 2020-06-03 11:40:04 +12:00
Chaim Lev-Ari
01d8c90348 fix(sidebar): show docker sidebar when needed (#3852) 2020-06-03 11:40:04 +12:00
Anthony Lapenna
c5f78f663a feat(settings): update templates documentation link 2020-06-03 11:40:04 +12:00
Anthony Lapenna
25103f08f9 feat(api): introduce new datastore interface (#3802)
* feat(api): introduce new datastore interface

* refactor(api): refactor http and main layers

* refactor(api): refactor http and bolt layers
2020-06-03 11:40:04 +12:00
Anthony Lapenna
493de20540 refactor(azure): remove Azure ACI endpoint support (#3803)
* feat(templates): remove template management features (#3719)

* feat(api): remove template management features

* feat(templates): remove template management features

* refactor(azure): remove Azure ACI endpoint support
2020-06-03 11:40:04 +12:00
Anthony Lapenna
6b41b5ec5d refactor(api): remove unused error constant 2020-06-03 11:40:04 +12:00
Chaim Lev-Ari
c074a714cf feat(server): remove external endpoint feature (#3837)
* fix(prettier): auto format html files (#3836)

* refactor(main): remove reference to external endpoints

* refactor(cli): remove parsing of external endpoints param

* refactor(portainer): remove types for external endpoints

* refactor(endpoints): remove warning for external endpoints

* refactor(endpoints): remove endpoint management setting

* refactor(endpoints): remove ref to endpoint management

* fix(main): remove endpoint management
2020-06-03 11:40:04 +12:00
Anthony Lapenna
d9665bc939 fix(api): update to template file format for Edge templates 2020-06-03 11:40:04 +12:00
Anthony Lapenna
4fdb0934cb feat(cli): remove the --no-snapshot CLI flag (#3814) 2020-06-03 11:40:04 +12:00
Anthony Lapenna
d202660bb8 feat(project): remove pulldog 2020-06-03 11:40:04 +12:00
Anthony Lapenna
8986e284fd feat(api): bump ldap library version (#3772)
* feat(api): bump ldap library version

* feat(api): fix ldap v3 import
2020-06-03 11:40:04 +12:00
Anthony Lapenna
070be46352 feat(templates): leftovers cleanup (#3762)
* feat(templates): leftovers cleanup

* feat(templates): update CLIFlags structure
2020-06-03 11:40:04 +12:00
Simone Cattaneo
800b357041 fix(api): updated LDAP library to v3 (portainer#3244) (#3386)
Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
2020-06-03 11:40:04 +12:00
Anthony Lapenna
4c4cec73d7 chore(version): bump version number 2020-06-03 11:40:03 +12:00
Maxime Bajeux
54621ced9e feat(templates): support templates versioning (#3729)
* feat(templates): Support templates versioning format

* Update app/portainer/models/template.js

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
2020-06-03 11:38:39 +12:00
Anthony Lapenna
f371dc5402 feat(templates): fix an issue with templates initialization and update settings view 2020-06-03 11:38:39 +12:00
Anthony Lapenna
5563ff60fc feat(templates): remove template management features (#3719)
* feat(api): remove template management features

* feat(templates): remove template management features
2020-06-03 11:38:39 +12:00
Anthony Lapenna
45f93882d0 Merge tag '1.24.0' into develop
Release 1.24.0
2020-05-29 14:34:45 +12:00
Anthony Lapenna
13f712d06d Merge branch 'release/1.24.0' 2020-05-29 14:34:39 +12:00
Anthony Lapenna
bfcdeecac9 chore(version): bump version number 2020-05-29 14:34:32 +12:00
Chaim Lev-Ari
babc509115 fix(yarn): downgrade router version (#3857) 2020-05-25 20:00:33 +12:00
Maxime Bajeux
ecbee3ee3d fix(templates): replace volume input with a select (#3853)
* prevent non admins to create volume which they do not have access

* fix(volumes): replace volume input by a select
2020-05-22 11:35:34 +12:00
Maxime Bajeux
10772a3ecd fix(networks): network without ipv6 should not be expand (#3844) 2020-05-21 12:40:23 +12:00
Chaim Lev-Ari
2260107811 feat(edge-stacks): add refresh to edit stack page (#3835) 2020-05-18 20:05:00 +12:00
Chaim Lev-Ari
42e7db0ae7 fix(prettier): auto format html files (#3836) 2020-05-18 19:08:45 +12:00
Maxime Bajeux
ebac85b462 feat(volumes): add a switch to use CIFS volumes (#3823)
* feat(volumes): add a switch to use CIFS volumes

* feat(volumes): switch between nfs and cifs

* feat(volumes): autofix sharepoint, hide driveroptions and allow to create unnammed volume

* feat(volumes): change cifs version select options

* feat(volumes): change few things
2020-05-15 13:28:51 +12:00
Chaim Lev-Ari
8eac1d2221 feat(edge-compute): add support for Edge stacks (#3827)
* feat(api): introduce Edge group API (#3639)

* feat(edge-groups): add object definition and service definition

* feat(edge-groups): implement bolt layer

* feat(edge-groups): bind service to server

* feat(edge-group): add edge-group create http handler

* feat(edge-groups): add list method to edge group handler

* feat(edge-group): add inspect http handler

* feat(edge-groups): add delete edge-group handler

* feat(edge-groups): add update group handler

* style(db): order by alphabetical order

* fix(edge-groups): rewrite http error messages

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* fix(main): order by alphabetical order

* refactor(edge-group): relocate fetch group

* fix(edge-group): reset tagids/endpoints if dynamic

* refactor(server): order by alphabetical order

* refactor(server): order by alphabetical order

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* Introduce a new setting to enable Edge compute features (#3654)

* feat(edge-compute): add edge compute setting

* feat(edge-compute): add edge compute group to sidebar

* fix(settings): rename settings form group

* fix(settings): align form control

* Edge group associated endpoints (#3659)

* chore(version): bump version number

* chore(version): bump version number

* feat(endpoints): filter by endpoint type (#3646)

* refactor(tags): migrate tags to have association objects

* refactor(tags): refactor tag management (#3628)

* refactor(tags): replace tags with tag ids

* refactor(tags): revert tags to be strings and add tagids

* refactor(tags): enable search by tag in home view

* refactor(tags): show endpoint tags

* refactor(endpoints): expect tagIds on create payload

* refactor(endpoints): expect tagIds on update payload

* refactor(endpoints): replace TagIds to TagIDs

* refactor(endpoints): set endpoint group to get TagIDs

* refactor(endpoints): refactor tag-selector to receive tag-ids

* refactor(endpoints): show tags in multi-endpoint-selector

* chore(tags): revert reformat

* refactor(endpoints): remove unneeded bind

* refactor(endpoints): change param tags to tagids in endpoint create

* refactor(endpoints): remove console.log

* refactor(tags): remove deleted tag from endpoint and endpoint group

* fix(endpoints): show loading label while loading tags

* chore(go): remove obsolete import labels

* chore(db): add db version comment

* fix(db): add tag service to migrator

* refactor(db): add error checks in migrator

* style(db): sort props in alphabetical order

* style(tags): fix typo

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* refactor(endpoints): replace tagsMap with tag string representation

* refactor(tags): rewrite tag delete to be more readable

* refactor(home): rearange code to match former style

* refactor(tags): guard against missing model in tag-selector

* refactor(tags): rename vars in tag_delete

* refactor(tags): allow any authenticated user to fetch tag list

* refactor(endpoints): replace controller function with class

* refactor(endpoints): replace function with helper

* refactor(endpoints): replace controller with class

* refactor(tags): revert tags-selector to use 1 way bindings

* refactor(endpoints): load empty tag array instead of nil

* refactor(endpoints): revert default tag ids

* refactor(endpoints): use function in place

* refactor(tags): use lodash

* style(tags): use parens in arrow functions

* fix(tags): remove tag from tag model

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* refactor(tags): create tag association when creating tag

* refactor(tags): delete tag association when deleting tag

* refactor(db): handle error in tag association create

* feat(endpoint-group): update tag assoc when creating endpoint group

* feat(endpoint-group): update tag association when updating group

* feat(endpoint-groups): remove group from tag associations

* feat(endpoints): associate endpoint with tag on create

* feat(endpoints): edit tag association when updating endpoint

* fix(tags): fix merge problems

* refactor(tags): remove tag association resource

* fix(db): use regular tags map

* style(tags): reorder props and imports

* refactor(endpoint-groups): replace tag-association with tag

* feat(edge-group): get associated endpoints when fetching

* refactor(tags): refactor algo to update endpoint and group tags

* refactor(edge-group): rename variable

* refactor(tags): move calc of tags to remove to global function

* fix(tags): update tag after adding association

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* fix(edge-groups): associate groups only with edge endpoints (#3667)

* fix(edge-groups): check endpoint type when adding to edge-group

* fix(edge-groups): return only edge endpoints for dynamic groups

* fix(edge-compute): load edge compute setting on public setting (#3665)

* Edge group list (#3644)

* feat(edge-groups): add edge module

* feat(edge-groups):  add edge-group service

* feat(edge-group): add groups list view

* feat(edge-groups): add link to groups in the sidebar

* feat(edge-group): show endpoints count and group type

* feat(edge-group): enable removal of edge groups

* refactor(edge-groups): replace datatable controller with class

* refactor(edge-groups): replace function with class

* fix(edge-groups): sort items by endpoints count and group type

* refactor(edge-groups): use generic datatable-header component

* feat(app): add trace for ui router

* fix(edge-compute): add ng injection to onEnter guard

* fix(edge-compute): add ng injection to onEnter guard

* style(edge-compute): remove space

* refactor(edge-compute): import angular

* fix(app): remove ui router trace

* refactor(product): revert app.js

* fix(edge-compute): remove admin guard from edge routes

* fix(edge-groups): change label of empty datatable

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* refactor(edge-groups): rename service

* fix(edge-groups): replace icon in sidebar

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* refactor(edge-groups): remove datatable controller

* refactor(edge-groups): move datatable icon to binding

* refactor(edge-groups): use vanilla datatable header

* refactor(datatable): remove datatable header

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* refactor(edge): rename edge group to Edge group

* feat(edge-groups): edge group creation view (#3671)

* feat(edge-groups): add create group view

* feat(edge-groups): allow to choose group type

* feat(edge-groups): implement create service handler

* feat(edge-group): filter by edge endpoints

* refactor(edge-groups): rename to camel case

* refactor(edge-groups): replace controller with class

* feat(endpoints): filter endpoints by type

* refactor(edge-groups): remove comments and unneccesary async keyword

* refactor(edge-group): use $async service

* fix(edge-groups): replace view title

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* fix(edge-groups): change icon

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* fix(edge-groups): change icon

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* refactor(edge-groups): remove obsolete function

* feat(edge-groups): add empty list messages

* feat(edge-group): add description to group types

* refactor(edge-groups): add finally block

* feat(endpoints): search server in multi-endpoint-selector

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* feat(edge-group) edit view (#3672)

* feat(edge-groups): add edit group view

* refactor(edge-group): replace edit controller with class

* refactor(edge-groups): remove async keyword

* refactor(edge-groups): use $async service

* refactor(edge-group): remove unnecessary functions

* fix(endpoints): group by groups in endpoint-selector

* feat(edge-groups): minor UI update

* fix(edge-groups): provide defaults for edge group (#3682)

* feat(edge-stacks): add basic views and sidebar link (#3689)

* feat(edge-stacks): add mock routes

* feat(edge-stacks): add link to stacks on sidebar

* feat(edge-stacks): add edge stacks view

* feat(edge-stacks): add create view

* feat(edge-stacks): add edit view

* fix(edge-stacks): use class in controller

* feat(edge-stacks): add edge-stacks api (#3688)

* feat(edge-stack): add edge stack types

* feat(edge-stacks): add edge stack service interface

* feat(edge-stacks): implement store

* feat(edge-stacks): bind service to datastore

* feat(edge-stacks): bind service to server

* feat(edge-stack): create basic api

* feat(edge-stack): create stack api

* feat(edge-stacks): update api

* refacotor(edge-stack): rename files

* feat(edge-stack): update endpoint status

* style(edge-stacks): remove comments

* feat(edge-stacks): use edge stacks folder for files

* fix(edge-stacks): replace bucket name

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* fix(edge-stacks): replace unmarshal function

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* fix(edge-stacks): replace edge stacks path

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* chore(git): merge develop to edge compute (#3692)

* feat(support): make support type dynamic (#3621)

* chore(version): bump version number

* chore(version): bump version number

* feat(endpoints): filter by endpoint type (#3646)

* chore(assets): double UI image resolutions for HiDPI displays (#3648)

Fixes #3069

Prevents users seeing blurry logos and other images when using a hidpi
display (like scaled 4k, or a Retina display).

These images have been recreated manually with 2x the original
resolution but should resemble the originals as much as possible.

They have also been run through pngcrush for compression.

* fix(services): enforce minimum replica count of 0 (#3653)

* fix(services): enforce minimum replica count of 0

Fixes #3652

Prevents replica count from being set below zero and causing an error.

* fix(services): enforce replica count is an integer

Prevents users entering decimals in the replica count

* refactor(tags): refactor tag management (#3628)

* refactor(tags): replace tags with tag ids

* refactor(tags): revert tags to be strings and add tagids

* refactor(tags): enable search by tag in home view

* refactor(tags): show endpoint tags

* refactor(endpoints): expect tagIds on create payload

* refactor(endpoints): expect tagIds on update payload

* refactor(endpoints): replace TagIds to TagIDs

* refactor(endpoints): set endpoint group to get TagIDs

* refactor(endpoints): refactor tag-selector to receive tag-ids

* refactor(endpoints): show tags in multi-endpoint-selector

* chore(tags): revert reformat

* refactor(endpoints): remove unneeded bind

* refactor(endpoints): change param tags to tagids in endpoint create

* refactor(endpoints): remove console.log

* refactor(tags): remove deleted tag from endpoint and endpoint group

* fix(endpoints): show loading label while loading tags

* chore(go): remove obsolete import labels

* chore(db): add db version comment

* fix(db): add tag service to migrator

* refactor(db): add error checks in migrator

* style(db): sort props in alphabetical order

* style(tags): fix typo

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* refactor(endpoints): replace tagsMap with tag string representation

* refactor(tags): rewrite tag delete to be more readable

* refactor(home): rearange code to match former style

* refactor(tags): guard against missing model in tag-selector

* refactor(tags): rename vars in tag_delete

* refactor(tags): allow any authenticated user to fetch tag list

* refactor(endpoints): replace controller function with class

* refactor(endpoints): replace function with helper

* refactor(endpoints): replace controller with class

* refactor(tags): revert tags-selector to use 1 way bindings

* refactor(endpoints): load empty tag array instead of nil

* refactor(endpoints): revert default tag ids

* refactor(endpoints): use function in place

* refactor(tags): use lodash

* style(tags): use parens in arrow functions

* fix(tags): remove tag from tag model

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* chore(yarn): change start:client to start webpack dev server (#3595)

* chore(yarn): change start:client to start webpack dev server

* Update package.json

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* create tag from tag selector (#3640)

* feat(tags): add button to save tag when doesn't exist

* feat(endpoints): allow the creating of tags in endpoint edit

* feat(groups): allow user to create tags in create group

* feat(groups): allow user to create tags in edit group

* feat(endpoint): allow user to create tags from endpoint create

* feat(tags): allow the creation of a new tag from dropdown

* feat(tag): replace "add" with "create"

* feat(tags): show tags input when not tags

* feat(tags): hide create message when not allowed

* refactor(tags): replace component controller with class

* refactor(tags): replace native methods with lodash

* refactor(tags): remove unused onChangeTags function

* refactor(tags): remove on-change binding

* style(tags): remove white space

* refactor(endpoint-groups): move controller to separate file

* fix(groups): allow admin to create tag in group form

* refactor(endpoints): wrap async function with try catch and $async

* style(tags): wrap arrow function args with parenthesis

* refactor(endpoints): return $async functions

* refactor(tags): throw error in the format Notification expects

* chore(yarn): add start:client script back (#3691)

* feat(endpoints): filter by ids and/or tag ids (#3690)

* feat(endpoints): add filter by tagIds

* refactor(endpoints): change endpoints service to query by tagIds

* fix(endpoints): filter by tags

* feat(endpoints): filter by endpoint groups tags

* feat(endpoints): filter by ids

Co-authored-by: itsconquest <william.conquest@portainer.io>
Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
Co-authored-by: Ben Brooks <ben@bbrks.me>
Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* Chore merge develop to edge compute (#3702)

* feat(support): make support type dynamic (#3621)

* chore(version): bump version number

* chore(version): bump version number

* feat(endpoints): filter by endpoint type (#3646)

* chore(assets): double UI image resolutions for HiDPI displays (#3648)

Fixes #3069

Prevents users seeing blurry logos and other images when using a hidpi
display (like scaled 4k, or a Retina display).

These images have been recreated manually with 2x the original
resolution but should resemble the originals as much as possible.

They have also been run through pngcrush for compression.

* fix(services): enforce minimum replica count of 0 (#3653)

* fix(services): enforce minimum replica count of 0

Fixes #3652

Prevents replica count from being set below zero and causing an error.

* fix(services): enforce replica count is an integer

Prevents users entering decimals in the replica count

* refactor(tags): refactor tag management (#3628)

* refactor(tags): replace tags with tag ids

* refactor(tags): revert tags to be strings and add tagids

* refactor(tags): enable search by tag in home view

* refactor(tags): show endpoint tags

* refactor(endpoints): expect tagIds on create payload

* refactor(endpoints): expect tagIds on update payload

* refactor(endpoints): replace TagIds to TagIDs

* refactor(endpoints): set endpoint group to get TagIDs

* refactor(endpoints): refactor tag-selector to receive tag-ids

* refactor(endpoints): show tags in multi-endpoint-selector

* chore(tags): revert reformat

* refactor(endpoints): remove unneeded bind

* refactor(endpoints): change param tags to tagids in endpoint create

* refactor(endpoints): remove console.log

* refactor(tags): remove deleted tag from endpoint and endpoint group

* fix(endpoints): show loading label while loading tags

* chore(go): remove obsolete import labels

* chore(db): add db version comment

* fix(db): add tag service to migrator

* refactor(db): add error checks in migrator

* style(db): sort props in alphabetical order

* style(tags): fix typo

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* refactor(endpoints): replace tagsMap with tag string representation

* refactor(tags): rewrite tag delete to be more readable

* refactor(home): rearange code to match former style

* refactor(tags): guard against missing model in tag-selector

* refactor(tags): rename vars in tag_delete

* refactor(tags): allow any authenticated user to fetch tag list

* refactor(endpoints): replace controller function with class

* refactor(endpoints): replace function with helper

* refactor(endpoints): replace controller with class

* refactor(tags): revert tags-selector to use 1 way bindings

* refactor(endpoints): load empty tag array instead of nil

* refactor(endpoints): revert default tag ids

* refactor(endpoints): use function in place

* refactor(tags): use lodash

* style(tags): use parens in arrow functions

* fix(tags): remove tag from tag model

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* chore(yarn): change start:client to start webpack dev server (#3595)

* chore(yarn): change start:client to start webpack dev server

* Update package.json

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* create tag from tag selector (#3640)

* feat(tags): add button to save tag when doesn't exist

* feat(endpoints): allow the creating of tags in endpoint edit

* feat(groups): allow user to create tags in create group

* feat(groups): allow user to create tags in edit group

* feat(endpoint): allow user to create tags from endpoint create

* feat(tags): allow the creation of a new tag from dropdown

* feat(tag): replace "add" with "create"

* feat(tags): show tags input when not tags

* feat(tags): hide create message when not allowed

* refactor(tags): replace component controller with class

* refactor(tags): replace native methods with lodash

* refactor(tags): remove unused onChangeTags function

* refactor(tags): remove on-change binding

* style(tags): remove white space

* refactor(endpoint-groups): move controller to separate file

* fix(groups): allow admin to create tag in group form

* refactor(endpoints): wrap async function with try catch and $async

* style(tags): wrap arrow function args with parenthesis

* refactor(endpoints): return $async functions

* refactor(tags): throw error in the format Notification expects

* chore(yarn): add start:client script back (#3691)

* feat(endpoints): filter by ids and/or tag ids (#3690)

* feat(endpoints): add filter by tagIds

* refactor(endpoints): change endpoints service to query by tagIds

* fix(endpoints): filter by tags

* feat(endpoints): filter by endpoint groups tags

* feat(endpoints): filter by ids

* refactor(project): sort portainer types and interface definitions (#3694)

* refactor(portainer): sort types

* style(portainer): add comment about role service

* refactor(portainer): sort interface types

* refactor(portainer): sort enums

* Update README.md

* Update README.md

* Update README.md

* chore(project): add prettier for code format (#3645)

* chore(project): install prettier and lint-staged

* chore(project): apply prettier to html too

* chore(project): git ignore eslintcache

* chore(project): add a comment about format script

* chore(prettier): update printWidth

* chore(prettier): remove useTabs option

* chore(prettier): add HTML validation

* refactor(prettier): fix closing tags

* feat(prettier): define angular parser for html templates

* style(prettier): run prettier on codebase

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* chore(prettier): run format on client codebase

Co-authored-by: itsconquest <william.conquest@portainer.io>
Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
Co-authored-by: Ben Brooks <ben@bbrks.me>
Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
Co-authored-by: Neil Cresswell <neil@cresswell.net.nz>

* feat(edge-stacks): create basic edge stack service (#3704)

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* feat(edge-groups): Provide a switch to use AND or OR for tags (#3695)

* feat(edge-groups): add switch to form

* feat(project): add property to EdgeGroup

* feat(edge-groups): save mustHaveAllTags

* feat(edge-groups): fetch associated endpoints (AND and OR)

* feat(edge-groups): add AND selector

* feat(edge-groups): default to AND

* fix(edge-groups): rewrite selector options

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* refactor(endpoints): move margin to schedule form

* fix(edge-groups): move the selector to top of group

* refactor(edge-groups): replace partialMatch property

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* feat(edge-stacks): add Edge stack creation view (#3705)

* feat(edge-stacks): basic creation view

* feat(edge-stacks): add group selector

* feat(edge-stack): create edge stack

* fix(code-editor): apply digest cycle after editor is changed

* style(project): reformat constants file

* feat(edge-stacks): add a note about missing edge groups

* fix(edge-stacks): add groups when creating stack from file

* feat(edge-groups): add associated endpoints table (#3710)

* feat(edge-groups): load associated endpoints

* feat(endpoints): add option to filter endpoint by partial match tags

* feat(edge-groups): query endpoints by PartialMatch

* feat(edge-groups): reload endpoints when form changes

* feat(edge-groups): remove columns

* feat(edge-group): remove url column

* refactor(edge-group): remove props

* feat(edge-stacks): add list view (#3713)

* feat(edge-stacks): basic datatable

* feat(edge-stacks): remove stack

* refactor(edge-stacks): convert to class

* refactor(edge-stacks): replace id with stackId

* feat(edge-stacks) edit edge stack view (#3716)

* feat(edge-stack): load file content

* feat(edge-stack): edit view

* feat(edge-stack): enable update stack

* refactor(edge-stacks): move form to component

* feat(edge-stacks): add endpoints status

* feat(edge-stacks): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* feat(edge-groups) prevent deletion of edge group used by an edge stack (#3722)

* feat(edge-groups): show if group belonges to edge stack

* feat(edge-group): protect deletion of used edge group

* feat(edge-groups): diable selection of used group

* feat(edge-groups): add inuse tag (#3739)

* feat(edge-groups): add inuse tag

* Update app/edge/components/groups-datatable/groupsDatatable.html

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* feat(edge-stack): update stack version when stack file is changed (#3746)

* feat(edge-stack): update version when stack file is changed

* refactor(edge-stacks): move update of version to clientside

* feat(edge-groups): replace Edge group endpoint selector (#3738)

* feat(edge-groups): replace selector

* feat(edge-group): add selector in edit form

* feat(edge-groups): show tags in endpoint selector

* feat(edge-groups): show the endpoint group name

* fix(edge-group): remove element from associated endpoints

* feat(edge-groups): add group column

* feat(edge-groups): move endpoints to other column

* fix(groups): disable sort

* refactor(endpoints): toggle backend pagination as a property

* fix(endpoints): show group name in group-association-table

* feat(endpoints): truncate table columns

* fix(endpoints): update group association table colspan

* fix(endpoint-groups): show dash when no tags

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>

* feat(edge-stacks): add api for edge to query stack config (#3748)

* refactor(http): move edge validation to bouncer

* feat(edge-stacks): add api for edge to query stack config

* style(edge-stack): remove parentheses

* Update api/http/security/bouncer.go

* refactor(edge-stacks): move config inspect to endpoints handler

* refactor(endpoints): move stack inspect to edge handler

* style(security): fix typo

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* refactor(endpoints): rename file

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

* feat(edge-groups): add dynamic group endpoints table (#3780)

* fix(edge-stacks): update version when updating stack files (#3778)

* feat(edgestacks): change status permission to edge enpoints

* feat(edge-compute): add stack info to edge status inspect (#3764)

* feat(edge-compute): create helper functions

* feat(endpoints): add relation object and service

* feat(db): create endpoint relation migration

* feat(endpoints): create relation when creating endpoint

* feat(endpoints): update relation when updating endpoint

* feat(endpoints): delete relation when deleting endpoint

* feat(endpoint): add stack status to endpoint_status

* feat(edge-stacks): connect new edge stack to endpoint

* refactor(edgestack): return errors.New

* refactor(edgestacks): return error

* refactor(edgegroup): endpoint can be related only if edge endpoint

* feat(endpoints): update relation only when tags or groups were changd

* refactor(tags): change tags functions to set functions

* refactor(edgestack): return a list of endpoints for a list of edgegroups

* feat(edgestacks): update relation when updating stack

* feat(edgestacks): remove relations when deleting edge stack

* feat(edgegroup): update related endpoints

* feat(endpoint-group): update endpoints relations on create

* feat(endpointgroup): add relatd stacks to endpoint when added to group

* feat(endpoint-groups): update relation when group is changed

* feat(endpointgroup): when deleting group, update its endpoints relations

* feat(tags): update related endpoints when deleting tag

* refactor(edge-compute): use pointers

* refactor(endpointgroup): handle unassociated endpoint

* fix(edgestack): show correct stack status

* fix(endpoint): remove deleted endpoint from related tags

* feat(edge-stacks): change acknowledged status color to blue (#3810)

* feat(edge-compute): provide stack name to edge endpoint (#3809)

* feat(edge-groups): when no tags selected show empty list of endpoints (#3811)

* feat(edge-groups): when no tags selected show empty list of endpoints

* fix(edge-group): change empty associated endpoint text

* fix(edge-compute): add missing relations updates (#3817)

* fix(endpoint): remove deleted endpoint from edge group

* fix(tags): remove deleted tag from edge group

* fix(endpoint): remove deleted endpoint from edge stack

* fix(edge-groups): remove clearing of edgeGroup fields

* fix(edge-groups): show dynamic edge groups without tags

* fix(edge-compute): use sequential delete in resources (#3818)

* fix(endpoints): delete endpoints on by one

* fix(tags): remove tags one by one

* fix(groups): remove endpoint groups one by one

* fix(edge-stacks): remove stack one by one

* fix(edge-groups): remove edge group one by one

* fix(edge-stacks): add link to root in breadcrumbs

* style(edge): add empty line after errors

* refactor(tags): remove old function

* refactor(endpoints): revert changes to multi-endpoint-selector

* feat(edge-stacks): support Edge stack templates (#3812)

* feat(edge-compute): fetch templates from url

* feat(edge-stacks): fetch edge templates

* feat(edge-stacks): choose template and save

* feat(edge-stacks): add placeholder to templates select

* feat(edge-templates): show info

* fix(edge-stacks): fix typo

* feat(edge-templates): replace template url

* feat(edge-compute): use custom url if available

* fix(edge-stacks): show error message when failing

* feat(edge-compute): show description in template

* feat(edge-templates): change access to route

* style(edge-compute): change EdgeTemplatesURL description

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
Co-authored-by: itsconquest <william.conquest@portainer.io>
Co-authored-by: Ben Brooks <ben@bbrks.me>
Co-authored-by: Neil Cresswell <neil@cresswell.net.nz>
2020-05-14 14:14:28 +12:00
Anthony Lapenna
8e09b935cd feat(cli): add deprecation warnings (#3826) 2020-05-13 16:21:17 +12:00
Anthony Lapenna
9dcd223134 feat(stacks): prevent external stack removal by a non-administrator user (#3800)
* fix(stacks): prevent external stacks removal by non admin

* feat(stacks): add RBAC checks for external stack removals

Co-authored-by: Maxime Bajeux <max.bajeux@gmail.com>
2020-05-13 15:37:35 +12:00
Anthony Lapenna
29c0584454 fix(api): update restricted volume browsing operation logic (#3798)
* fix(api): prevent a potential panic

* fix(api): update restricted volume browsing operation logic
2020-05-12 16:08:01 +12:00
Anthony Lapenna
5c274f5b0c docs(readme): update README 2020-05-12 10:30:12 +12:00
Maxime Bajeux
b3af91cea3 feat(volumes): Revise the UX for creation of NFS volumes (#3815)
* feat(volumes): Revise the UX for creation of NFS volumes

* feat(volume-creation): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-05-12 10:23:42 +12:00
Anthony Lapenna
c8f55ac896 feat(project): update pull-dog configuration 2020-05-11 11:23:56 +12:00
Anthony Lapenna
659e4486db feat(project): add pull-dog config 2020-05-11 09:31:07 +12:00
pull-dog-user
cc091ee589 feat(project): enable Pull Dog for the repository (#3801)
* Create pull-dog.json

* Create docker-compose.pull-dog.yml

* Update pull-dog.json

* Update docker-compose.pull-dog.yml
2020-05-11 09:25:30 +12:00
Maxime Bajeux
8046fb0438 fix(volumes): add unicity check on volumes (#3779)
* fix(volumes): add unicity check on volumes

* fix(volumes): add header to volume creation request

* fix(volumes): change few things
2020-05-09 09:40:49 +12:00
Chaim Lev-Ari
7fa73d1147 fix(endpoints): show line breaks in edge run commands (#3794) 2020-05-06 17:45:17 +12:00
Shivam Goyal
bfd6cca33f feat(image-build): fix typo (#3787) 2020-05-04 19:54:09 +12:00
Maxime Bajeux
7fe7ce1a0a fix(container-creation): ensure exposedPorts exists (#3770) 2020-04-29 14:33:37 +12:00
Maxime Bajeux
7f0ce61413 feat(networks): remove the ability to create host network (#3771) 2020-04-29 14:05:32 +12:00
Maxime Bajeux
3de533042d feat(networks): add ipv6 support (#3717)
* feat(portainer-core): add ipv6 support

* feat(networks): add few changes

* refacto(networks): write regex once

* fix(networks): fix indentation

* refacto(networks): use foreach instead map and pluralize ipvxconfig

* refacto(networks): pluralize ipvxconfig

* feat(networks): support ipv6 with ports

* feat(networks): add an explicit error message

* fix(networks): hide ipv6 configuration when creating macvlan
2020-04-28 12:34:54 +12:00
Dan Underwood
b2f36a3bbe fix(networking): convert from localhost addresses to 127.0.0.1 (#3411) 2020-04-27 13:54:37 +12:00
Anthony Lapenna
3d5bdab620 feat(project): add alpine based Dockerfile (#3759) 2020-04-27 13:46:12 +12:00
Anthony Lapenna
fee20248ea Update CONTRIBUTING.md 2020-04-21 11:45:01 +12:00
Mariell
f525c8d022 feat(container-creation): add support for --init (#2111) (#3714) 2020-04-15 13:09:42 +12:00
Chaim Lev-Ari
bba622a500 chore(eslint): add rule to sort imports (#3715)
* chore(eslint): add plugin to sort imports

* chore(eslint): sort imports

* chore(eslint): add eslint-config-prettier
2020-04-15 11:46:34 +12:00
Chaim Lev-Ari
cf5056d9c0 chore(project): add prettier for code format (#3645)
* chore(project): install prettier and lint-staged

* chore(project): apply prettier to html too

* chore(project): git ignore eslintcache

* chore(project): add a comment about format script

* chore(prettier): update printWidth

* chore(prettier): remove useTabs option

* chore(prettier): add HTML validation

* refactor(prettier): fix closing tags

* feat(prettier): define angular parser for html templates

* style(prettier): run prettier on codebase

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-04-11 09:54:53 +12:00
Neil Cresswell
6663073be1 Update README.md 2020-04-09 10:01:20 +12:00
Neil Cresswell
18a38d597a Update README.md 2020-04-09 10:00:29 +12:00
Neil Cresswell
aeea88be36 Update README.md 2020-04-09 09:59:14 +12:00
Chaim Lev-Ari
6da38d466b refactor(project): sort portainer types and interface definitions (#3694)
* refactor(portainer): sort types

* style(portainer): add comment about role service

* refactor(portainer): sort interface types

* refactor(portainer): sort enums
2020-04-09 09:26:11 +12:00
Chaim Lev-Ari
2542d30a09 feat(endpoints): filter by ids and/or tag ids (#3690)
* feat(endpoints): add filter by tagIds

* refactor(endpoints): change endpoints service to query by tagIds

* fix(endpoints): filter by tags

* feat(endpoints): filter by endpoint groups tags

* feat(endpoints): filter by ids
2020-04-08 21:14:50 +12:00
Chaim Lev-Ari
df13f3b4cc chore(yarn): add start:client script back (#3691) 2020-04-08 21:03:52 +12:00
Chaim Lev-Ari
db8b3d6e5a create tag from tag selector (#3640)
* feat(tags): add button to save tag when doesn't exist

* feat(endpoints): allow the creating of tags in endpoint edit

* feat(groups): allow user to create tags in create group

* feat(groups): allow user to create tags in edit group

* feat(endpoint): allow user to create tags from endpoint create

* feat(tags): allow the creation of a new tag from dropdown

* feat(tag): replace "add" with "create"

* feat(tags): show tags input when not tags

* feat(tags): hide create message when not allowed

* refactor(tags): replace component controller with class

* refactor(tags): replace native methods with lodash

* refactor(tags): remove unused onChangeTags function

* refactor(tags): remove on-change binding

* style(tags): remove white space

* refactor(endpoint-groups): move controller to separate file

* fix(groups): allow admin to create tag in group form

* refactor(endpoints): wrap async function with try catch and $async

* style(tags): wrap arrow function args with parenthesis

* refactor(endpoints): return $async functions

* refactor(tags): throw error in the format Notification expects
2020-04-08 19:56:24 +12:00
Chaim Lev-Ari
dd6262cf69 chore(yarn): change start:client to start webpack dev server (#3595)
* chore(yarn): change start:client to start webpack dev server

* Update package.json

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
2020-04-06 09:06:59 +12:00
Chaim Lev-Ari
edd86f2506 refactor(tags): refactor tag management (#3628)
* refactor(tags): replace tags with tag ids

* refactor(tags): revert tags to be strings and add tagids

* refactor(tags): enable search by tag in home view

* refactor(tags): show endpoint tags

* refactor(endpoints): expect tagIds on create payload

* refactor(endpoints): expect tagIds on update payload

* refactor(endpoints): replace TagIds to TagIDs

* refactor(endpoints): set endpoint group to get TagIDs

* refactor(endpoints): refactor tag-selector to receive tag-ids

* refactor(endpoints): show tags in multi-endpoint-selector

* chore(tags): revert reformat

* refactor(endpoints): remove unneeded bind

* refactor(endpoints): change param tags to tagids in endpoint create

* refactor(endpoints): remove console.log

* refactor(tags): remove deleted tag from endpoint and endpoint group

* fix(endpoints): show loading label while loading tags

* chore(go): remove obsolete import labels

* chore(db): add db version comment

* fix(db): add tag service to migrator

* refactor(db): add error checks in migrator

* style(db): sort props in alphabetical order

* style(tags): fix typo

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* refactor(endpoints): replace tagsMap with tag string representation

* refactor(tags): rewrite tag delete to be more readable

* refactor(home): rearange code to match former style

* refactor(tags): guard against missing model in tag-selector

* refactor(tags): rename vars in tag_delete

* refactor(tags): allow any authenticated user to fetch tag list

* refactor(endpoints): replace controller function with class

* refactor(endpoints): replace function with helper

* refactor(endpoints): replace controller with class

* refactor(tags): revert tags-selector to use 1 way bindings

* refactor(endpoints): load empty tag array instead of nil

* refactor(endpoints): revert default tag ids

* refactor(endpoints): use function in place

* refactor(tags): use lodash

* style(tags): use parens in arrow functions

* fix(tags): remove tag from tag model

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
2020-03-29 22:54:14 +13:00
Ben Brooks
fe89a4fc01 fix(services): enforce minimum replica count of 0 (#3653)
* fix(services): enforce minimum replica count of 0

Fixes #3652

Prevents replica count from being set below zero and causing an error.

* fix(services): enforce replica count is an integer

Prevents users entering decimals in the replica count
2020-03-29 13:25:50 +13:00
Ben Brooks
00bef100ee chore(assets): double UI image resolutions for HiDPI displays (#3648)
Fixes #3069

Prevents users seeing blurry logos and other images when using a hidpi
display (like scaled 4k, or a Retina display).

These images have been recreated manually with 2x the original
resolution but should resemble the originals as much as possible.

They have also been run through pngcrush for compression.
2020-03-27 16:49:20 +13:00
Chaim Lev-Ari
ae7f46c8ef feat(endpoints): filter by endpoint type (#3646) 2020-03-26 18:44:27 +13:00
Anthony Lapenna
78558f9c8e chore(version): bump version number 2020-03-20 11:37:35 +13:00
Anthony Lapenna
5a3caab9c4 Merge tag '1.23.2' into develop
Release 1.23.2
2020-03-20 11:35:49 +13:00
Anthony Lapenna
5396a069f2 Merge branch 'release/1.23.2' 2020-03-20 11:35:43 +13:00
Anthony Lapenna
2a92fcb802 chore(version): bump version number 2020-03-20 11:35:36 +13:00
itsconquest
2c400eb3b4 feat(support): make support type dynamic (#3621) 2020-03-19 09:38:56 +13:00
Anthony Lapenna
a11a348893 fix(containers): do not persist container status filter (#3615) 2020-03-16 14:37:59 +13:00
itsconquest
d022853059 feat(support): add new offerings (#3608)
* feat(support): add new offerings

* feat(support): refactor for simplicity

* feat(support): rename for clarity
2020-03-16 11:35:55 +13:00
xAt0mZ
bfdb4dba12 fix(container-creation): validate runtime property (#3581)
Co-authored-by: linquize <linquize2@yahoo.com>
2020-02-26 16:31:59 +13:00
William
8d7bae0560 fix(dependencies): bump go-winio lib (#3569)
* fix(dependencies): bump go-winio lib

* fix(api): update gomod

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-02-25 18:56:34 +13:00
Anthony Lapenna
e0d83db609 fix(authentication/ldap): fix an issue with authorizations not updated after ldap login (#3577) 2020-02-25 18:54:32 +13:00
Steven Kang
ad5f51964c fix(build): Remove -ErrorAction:SilentlyContinue (#3571) 2020-02-22 18:18:09 +13:00
Anthony Lapenna
9cc8448418 chore(version): bump version number 2020-02-20 09:24:06 +13:00
Anthony Lapenna
b2cc6be007 fix(api): update gomod 2020-02-20 08:20:45 +13:00
Anthony Lapenna
be0b01611f Merge tag '1.23.1' into develop
Release 1.23.1
2020-02-18 13:46:17 +13:00
Anthony Lapenna
bcda7e2d7e Merge branch 'release/1.23.1' 2020-02-18 13:46:10 +13:00
Anthony Lapenna
d0e998ddc4 chore(version): bump version number 2020-02-18 13:46:04 +13:00
William
1f7e5fec4f fix(settings/authentication): patch LDAP connectivity check (#3561) 2020-02-18 12:25:30 +13:00
Anthony Lapenna
d3a625e22f feat(api): update gomod 2020-02-15 09:09:45 +13:00
William
eff1b79a4a fix(networks): patch datatable (#3557) 2020-02-12 20:41:41 +01:00
William
0330b16776 fix(container-create): patch dns (#3556) 2020-02-11 15:23:56 +01:00
William
97a0ea4a31 fix(templates): select volume name not object (#3549) 2020-02-06 09:07:23 +13:00
William
167d4319b5 fix(authentication): frontend changes (#3456)
* fix(authentication): frontend changes

* fix(authentication): suggested changes

* fix(authentication): support AnonymousMode boolean

* feat(authentication): support empty vals + move from scope to formValues

* feat(authentication): allow test of TLS & anon

* feat(authentication): remove unneeded whitespace

* feat(authentication): remove un-needed whitespace

* feat(refactor): rebase + cleanup logic
2020-02-06 09:06:22 +13:00
Mike Church
6f59f130a1 feat(dashboard): add health status to home page and dashboard (#3489)
* feat(dashboard): add health status to home page and dashboard

* fix(dashboard): code review updates, using builtin for substring search
2020-02-05 07:59:29 +13:00
William
cc8d3c8639 refactor(UX): disable/remove uneeded UI elements (#3530)
* refactor(UX): disable/remove uneeded UI elements

* refactor(UX): rm missed th in container network

* refactor(UX): minor formatting improvement
2020-01-31 16:49:59 +01:00
Hugo Hromic
f4c461d7fb feat(settings/ldap): preserve ReaderDN in database if empty in settings payload (#3537)
* Allows to avoid changing any current value when using LDAP Anonymous Mode
2020-01-31 13:17:19 +13:00
William
6c492d2290 fix(UX): prevent task expand on row selection (#3531)
* fix(UX): prevent task expand on row selection

* refactor(UX): apply service expand logic to networks
2020-01-29 14:44:02 +01:00
William
8bea0988dd fix(api): lower Docker client API version for backwards support (#3534) 2020-01-29 17:36:28 +13:00
William
8dda67c8d0 refactor(UX): fix grammar (#3528) 2020-01-27 14:02:04 +13:00
William
7365afa1bb feature(UX): sort dropdowns alphabetically (#3524) 2020-01-25 09:53:48 +13:00
Kirill K
1ef29f2671 feat: add setting to change DNS servers (#3511)
* feat: add setting to change DNS servers

* style: fixing codeclimate warning

Looks like conditional was excessive, it works as expected even without
it.

* style: rename 'DNS Server 1/2' to 'Primary/Secondary DNS Server'

Signed-off-by: Kirill K <kovalev.kirill.a@gmail.com>

* style: rename variables in code to match UI naming

* feat: add tooltips on DNS servers input fields

Signed-off-by: Kirill K <kovalev.kirill.a@gmail.com>

* Revert "feat: add tooltips on DNS servers input fields"

This reverts commit b83ef50825.

* style: secondary DNS placeholder

Signed-off-by: Kirill K <kovalev.kirill.a@gmail.com>
2020-01-24 15:49:28 +01:00
William
fa5bb9b1be feat(stack-creation): add note for 2FA (#3509)
* refactor(stack-creation): add note for 2FA

* Update app/portainer/views/stacks/create/createstack.html

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
2020-01-23 09:17:04 +13:00
Hugo Hromic
2ba195adaa feat(api): implement anonymous mode for LDAP connection (#3460)
* When enabled, ReaderDN and Password will not be used
* Anonymous mode is set to `true` by default on fresh installations
2020-01-22 11:14:07 +13:00
William
9da08bc792 refactor(endpoint-creation): remove unneeded port (#3467)
* refactor(endpoint-creation): remove unneeded port

* refactor(endpoint-creation): remove from clipboard
2020-01-22 09:17:41 +13:00
William
17bc17f638 fix(api): fix an issue with ownership for services and stacks (#3512) 2020-01-21 08:09:30 +13:00
William
efae49d92b chore(project): require Portainer logs (#3508) 2020-01-19 18:46:40 +13:00
Iceyer
58c00401e9 fix: atob convert unicode in config failed (#3415)
atob only support decode ascii char, when this unicode in config, it will show unknown char.
2019-12-09 17:52:02 +01:00
Anthony Lapenna
e9f6861df0 feat(api): add go module support (#3408)
* feat(api): experiment with go mod

* feat(api): experiment with go mod

* feat(api): experiment with go mod

* feat(api): add go module support

* refactor(api): go fmt
2019-12-05 17:02:27 +13:00
Anthony Lapenna
bba13f69ad chore(version): bump version number 2019-12-04 17:07:21 +13:00
Anthony Lapenna
36020dd8bc Merge tag '1.23.0' into develop
Release 1.23.0
2019-12-04 17:05:49 +13:00
Anthony Lapenna
b7eca7ce17 Merge branch 'release/1.23.0' 2019-12-04 17:05:42 +13:00
Anthony Lapenna
2189deb3bd chore(version): bump version number 2019-12-04 17:05:36 +13:00
Anthony Lapenna
29b7eeef5a fix(api): trigger an authorization update after auto-provisioning users (#3428) 2019-12-04 15:32:55 +13:00
Anthony Lapenna
f6cefb3318 fix(api): fix invalid method call for docker_windows proxy 2019-12-04 12:54:11 +13:00
Anthony Lapenna
a42619a442 fix(api): fix invalid extensions.json location 2019-12-04 11:42:43 +13:00
xAt0mZ
1465825988 feat(container): disable recreate/duplicate buttons with RBAC for non admins (#3426) 2019-12-04 10:47:07 +13:00
xAt0mZ
2d576394d0 fix(registry-selector): unique images in auto suggest (#3425) 2019-12-04 10:46:03 +13:00
William
f79dae3e27 feat(about): add analytics notice (#3423) 2019-12-04 08:05:00 +13:00
Anthony Lapenna
badb6ee50f fix(http): update volume browsing validation (#3416) 2019-12-03 10:42:55 +13:00
Anthony Lapenna
c2e1129804 feat(extensions): update offline manifest 2019-12-03 09:50:10 +13:00
Mohab Abd El-Dayem
3b1a8e4bba feat(cli): remove the logging of the hashed password of the admin user (#3328) 2019-11-29 09:23:18 +13:00
William
dd0c80e915 fix(container-creation): preserve aliases if null (#3405)
* fix(container-creation): preserve aliases if null

* Update app/docker/views/containers/create/createContainerController.js
2019-11-29 09:21:23 +13:00
William
5ab63bd151 fix(container-create): patch aliases (#3403)
* fix(container-create): patch aliases

* Update app/docker/views/containers/create/createContainerController.js
2019-11-28 17:38:53 +13:00
xAt0mZ
ea1ca76f70 fix(auth): clean browser cache on logout (#3402) 2019-11-28 12:16:34 +13:00
xAt0mZ
e19bc8abc7 fix(app): registry push-pull features overhaul (#3393)
* feat(registry): registry or direct url selector

* feat(app): push pull container creation

* feat(app): push pull container duplicate

* feat(app): push pull container details recreate

* feat(app): push pull container details commit

* feat(app): push pull images

* feat(app): push pull image tag

* feat(app): push pull image push

* feat(app): push pull image pull

* feat(app): push pull service creation

* feat(app): push pull templates create container

* feat(app): push pull templates create stacks

* feat(app): push pull template edit

* feat(app): push pull service details update

* fix(app): refactor registry selector + registry auto select

* feat(app): remove autocomplete on registry selector

* style(image-registry): reword simple/advanced mode

* Revert "feat(app): remove autocomplete on registry selector"

This reverts commit 97ec2ddd62.

* refactor(registry-selector): reverse registry and image fields

* feat(app): autocomplete on registry selector

* feat(registry-selector): change gitlab registry autocomplete

* feat(registry-selector): autocomplete for dockerhub

* feat(registry-selector): gitlab url based on locked value instead of name

* fix(registry-selector): gitlab registries URL are not modified anymore

* fix(registry-selector): change gitlab image autofill on duplicate

* fix(registry-selector): gitlab registries now only suggest their own images and not all from gitlab

* fix(registry-selector): psuh pull issues with gitlab registries

* fix(registry-selector): dockerhub registry selection on duplicate for dockerhub images

* fix(templates): registry retrieval for template

* feat(images): add autocomplete on image pull panel

* fix(registry-selector): add latest tag when no tag is specified

* fix(registry-selector): latest tag now applied for non gitlab registries
2019-11-28 11:36:39 +13:00
William
61c38534a7 fix(container-creation): preserve network aliases (#3401) 2019-11-28 09:35:14 +13:00
William
7f54584ed6 fix(container-creation): match container_network by id (#3398) 2019-11-27 09:19:22 +13:00
xAt0mZ
1a65dbf85f fix(app): permissions lost for UI on browser refresh (#3354)
* fix(app): permissions lost for UI on browser refresh

* fix(app): permissions retrieval moved to global app resolve
2019-11-26 17:01:39 +13:00
William
a3a83d1d7e fix(container): hide opts when autoremove true (#3397) 2019-11-26 08:08:48 +13:00
KemoNine
a41ca1fd46 feat(container-creation): allow empty value for labels (#2655)
* Allow empty values for labels

* Allow empty labels when creating containers from a template
2019-11-25 13:25:30 +13:00
Anthony Lapenna
130c188717 fix(libcompose): apply same normalize name rule as libcompose on stack name (#3395) 2019-11-24 14:28:07 +13:00
Anthony Lapenna
a85f0058ee feat(extensions): add the ability to upload and enable an extension (#3345)
* feat(extensions): offline mode mockup

* feat(extensions): offline mode mockup

* feat(api): add support for extensionUpload API operation

* feat(extensions): offline extension upload

* feat(api): better support for extensions in offline mode

* feat(extension): update offline description

* feat(api): introduce local extension manifest

* fix(api): fix LocalExtensionManifestFile value

* feat(api): use a 5second timeout for online extension infos

* feat(extensions): add download archive link

* feat(extensions): add support for offline update

* fix(api): fix issues with offline install and online updates of extensions

* fix(extensions): fix extensions link URL

* fix(extension): hide screenshot in offline mode
2019-11-20 18:16:40 +13:00
Anthony Lapenna
8b0eb71d69 feat(api): automatically update extensions at startup (#3349)
* feat(api): automatically update extensions at startup

* feat(api): review updateAndStartExtensions
2019-11-20 18:02:07 +13:00
Anthony Lapenna
1f90a091a8 feat(api): bind extensions stdout and stderr to current process (#3375) 2019-11-20 14:08:16 +13:00
Anthony Lapenna
b8be795505 feat(templates): replace volume selector with typeahead (#3371) 2019-11-20 12:18:27 +13:00
Anthony Lapenna
4239db7b34 fix(api): remove roles associated to access policies after removing RBAC extension (#3373) 2019-11-20 11:58:26 +13:00
Anthony Lapenna
81c0bf0632 fix(api): introduce priority based logic for RBAC roles (#3374)
* fix(api): introduce priority based logic for RBAC roles

* refactor(api): rename method
2019-11-18 21:22:47 +13:00
Anthony Lapenna
9decbce511 chore(version): bump version number 2019-11-14 17:50:11 +13:00
Anthony Lapenna
914b46f813 fix(api): introduce gitlab proxy package 2019-11-13 13:12:55 +13:00
Anthony Lapenna
19d4db13be feat(api): rewrite access control management in Docker (#3337)
* feat(api): decorate Docker resource creation response with resource control

* fix(api): fix a potential resource control conflict between stacks/volumes

* feat(api): generate a default private resource control instead of admin only

* fix(api): fix default RC value

* fix(api): update RC authorizations check to support admin only flag

* refactor(api): relocate access control related methods

* fix(api): fix a potential conflict when fetching RC from database

* refactor(api): refactor access control logic

* refactor(api): remove the concept of DecoratedStack

* feat(api): automatically remove RC when removing a Docker resource

* refactor(api): update filter resource methods documentation

* refactor(api): update proxy package structure

* refactor(api): renamed proxy/misc package

* feat(api): re-introduce ResourceControlDelete operation as admin restricted

* refactor(api): relocate default endpoint authorizations

* feat(api): migrate RBAC data

* feat(app): ResourceControl management refactor

* fix(api): fix access control issue on stack deletion and automatically delete RC

* fix(api): fix stack filtering

* fix(api): fix UpdateResourceControl operation checks

* refactor(api): introduce a NewTransport builder method

* refactor(api): inject endpoint in Docker transport

* refactor(api): introduce Docker client into Docker transport

* refactor(api): refactor http/proxy package

* feat(api): inspect a Docker resource labels during access control validation

* fix(api): only apply automatic resource control creation on success response

* fix(api): fix stack access control check

* fix(api): use StatusCreated instead of StatusOK for automatic resource control creation

* fix(app): resource control fixes

* fix(api): fix an issue preventing administrator to inspect a resource with a RC

* refactor(api): remove useless error return

* refactor(api): document DecorateStacks function

* fix(api): fix invalid resource control type for container deletion

* feat(api): support Docker system networks

* feat(api): update Swagger docs

* refactor(api): rename transport variable

* refactor(api): rename transport variable

* feat(networks): add system tag for system networks

* feat(api): add support for resource control labels

* feat(api): upgrade to DBVersion 22

* refactor(api): refactor access control management in Docker proxy

* refactor(api): re-implement docker proxy taskListOperation

* refactor(api): review parameters declaration

* refactor(api): remove extra blank line

* refactor(api): review method comments

* fix(api): fix invalid ServerAddress property and review method visibility

* feat(api): update error message

* feat(api): update restrictedVolumeBrowserOperation method

* refactor(api): refactor method parameters

* refactor(api): minor refactor

* refactor(api): change Azure transport visibility

* refactor(api): update struct documentation

* refactor(api): update struct documentation

* feat(api): review restrictedResourceOperation method

* refactor(api): remove unused authorization methods

* feat(api): apply RBAC when enabled on stack operations

* fix(api): fix invalid data migration procedure for DBVersion = 22

* fix(app): RC duplicate on private resource

* feat(api): change Docker API version logic for libcompose/client factory

* fix(api): update access denied error message to be Docker API compliant

* fix(api): update volume browsing authorizations data migration

* fix(api): fix an issue with access control in multi-node agent Swarm cluster
2019-11-13 12:41:42 +13:00
xAt0mZ
198e92c734 feat(registry): gitlab support (#3107)
* feat(api): gitlab registry type

* feat(registries): early support for gitlab registries

* feat(app): registry service selector

* feat(registry): gitlab support : list repositories and tags - remove features missing

* feat(registry): gitlab registry remove features

* feat(registry): gitlab switch to registry V2 API for repositories and tags

* feat(api): use development extension binary

* fix(registry): avoid 401 on gitlab retrieve to disconnect the user

* feat(registry): gitlab browse projects without extension

* style(app): code cleaning

* refactor(app): PR review changes + refactor on types

* fix(gitlab): remove gitlab info from registrymanagementconfig and force gitlab type

* style(api): go fmt

* feat(api): update APIVersion and ExtensionDefinitionsURL

* fix(api): fix invalid RM extension URL

* feat(registry): PAT scope help

* feat(registry): defaults on registry creation

* style(registry-creation): update layout and text for Gitlab registry

* feat(registry-creation): update gitlab notice
2019-11-12 16:28:31 +13:00
Anthony Lapenna
03d9d6afbb Revert "fix(api): fix invalid resource control check (#3225)" (#3327)
This reverts commit 1fbe6a12f1.
2019-11-01 17:46:53 +13:00
George Cheng
c559b6b55c fix(container-creation): Fix bad env in container creation (#2996)
Currently we are using RegExp `/\=(.+)/` to catch key-value
of environment variables, which could not match empty-value
environment variables such as `KEY=`.

This commit will change the RegExp to `/\=(.*)/`, which
matches the empty values.
2019-11-01 16:15:33 +13:00
Anthony Lapenna
0175490161 fix(api): data migration to update default Portainer authorizations (#3314) 2019-10-31 12:12:04 +13:00
Anthony Lapenna
310b6b34da fix(api): update user authorizations after team deletion (#3315) 2019-10-31 08:46:50 +13:00
Anthony Lapenna
07db1ca16e feat(test): update e2e to support swarm and CI mode 2019-10-29 12:51:26 +13:00
Anthony Lapenna
36de0aee7b feat(test): update e2e setup 2019-10-29 11:38:38 +13:00
Anthony Lapenna
c6e9d8e616 feat(test): update docker-compose file for cypress e2e testing 2019-10-28 16:51:59 +13:00
Anthony Lapenna
dbef3a0508 feat(test): update cypress projectId 2019-10-28 15:29:32 +13:00
William
91c83eccd2 feat(project): add automated testing with cypress (#3305)
* feat(project): add automated testing with cypress

* feat(project): made suggested edits

* feat(project): add init test

* feat(project): add socket to correct container
2019-10-25 18:53:29 +13:00
William
542b76912a feat(endpoint-details): add edge-key to commands (#3302) 2019-10-24 16:36:24 +02:00
Aaron Korte
53942b741a fix(api): increment stack identifier atomically (#3290) 2019-10-24 11:38:41 +13:00
Mattias Edlund
accca0f2a6 feat(containers): added support for port range mappings when deploying containers (#3194)
* feat(containers): added support for port range mappings when deploying containers

* feat(containers): added placeholders to port publishing input fields

* feat(containers): added a tooltip to the manual network port publishing

* feat(containers): improved the code consistency
2019-10-15 11:13:57 +02:00
xAt0mZ
f67e866e7e feat(registry): inspect repository images (#3121)
* feat(registry): inspect repository images

* fix(registry): tag inspect column sorting
2019-10-14 15:46:33 +02:00
xAt0mZ
2445a5aed5 fix(registry): Performance issues with Registry Manager (#2648)
* fix(registry): fetch datatable details on page/filter/order state change instead of fetching all data on first load

* fix(registry): fetch tags datatable details on state change instead of fetching all data on first load

* fix(registry): add pagination support for tags + loading display on data load

* fix(registry): debounce on text filter to avoid querying transient matching values

* refactor(registry): rebase on latest develop

* feat(registries): background tags and optimisation -- need code cleanup and for-await-of to cancel on page leave

* refactor(registry-management): code cleanup

* feat(registry): most optimized version -- need fix for add/retag

* fix(registry): addTag working without page reload

* fix(registry): retag working without reload

* fix(registry): remove tag working without reload

* fix(registry): remove repository working with latest changes

* fix(registry): disable cache on firefox

* feat(registry): use jquery for all 'most used' manifests requests

* feat(registry): retag with progression + rewrite manifest REST service to jquery

* fix(registry): remove forgotten DI

* fix(registry): pagination on repository details

* refactor(registry): info message + hidding images count until fetch has been done

* fix(registry): fix selection reset deleting selectAll function and not resetting status

* fix(registry): resetSelection was trying to set value on a getter

* fix(registry): tags were dropped when too much tags were impacted by a tag removal

* fix(registry): firefox add tag + progression

* refactor(registry): rewording of elements

* style(registry): add space between buttons and texts in status elements

* fix(registry): cancelling a retag/delete action was not removing the status panel

* fix(registry): tags count of empty repositories

* feat(registry): reload page on action cancel to avoid desync

* feat(registry): uncancellable modal on long operations

* feat(registry): modal now closes on error + modal message improvement

* feat(registries): remove empty repositories from the list

* fix(registry): various bugfixes

* feat(registry): independant timer on async actions + modal fix
2019-10-14 15:45:09 +02:00
xAt0mZ
8a8cef9b20 feat(deps): multiselect library as dependency (#3255) 2019-10-14 15:43:58 +02:00
xAt0mZ
e20a139c5a fix(registry): remove checkboxes on repositories list (#3109) 2019-10-14 15:43:27 +02:00
Tim van den Eijnden
774380fb44 chore(icons): update fontawesome dependency (#3219) 2019-10-14 15:40:19 +02:00
Anthony Lapenna
3632e07654 Merge tag '1.22.1' into develop
Release 1.22.1
2019-10-11 10:40:58 +13:00
Anthony Lapenna
80ad5079f7 Merge branch 'release/1.22.1' 2019-10-11 10:40:52 +13:00
Anthony Lapenna
4fad28590d chore(version): bump version number 2019-10-11 10:40:41 +13:00
Soham Mondal
8de507a15d feat(container-details): add entrypoint to container details view (#3120)
* feat(container-details): add entrypoint to container details view

* feat(container-details): restore file from develop branch to bring back original indentation

* feat(container-details): add entrypoint to container details view
2019-10-10 17:47:25 +13:00
Anthony Lapenna
19810b9f4e fix(build-system): fix build system on CI for Windows (#3250)
* fix(build-system): fix build system on CI for Windows

* fix(build-system): fix build system on CI for Windows

* fix(build-system): fix build system on CI for Windows

* fix(build-system): fix build system on CI for Windows

* fix(build-system): fix build system on CI for Windows

* fix(build-system): fix build system on CI for Windows

* fix(build-system): fix build system on CI for Windows

* fix(build-system): fix build system on CI for Windows

* fix(build-system): fix build system on CI for Windows
2019-10-10 16:29:00 +13:00
Anthony Lapenna
ab2acea463 feat(app): add externally sourced support options (#3249)
* feat(app): add externally sourced support options

* refactor(api): rename struct fields
2019-10-10 10:59:27 +13:00
Anthony Lapenna
521a36e629 fix(api): fix missing default settings for LDAPSettings 2019-10-10 10:28:17 +13:00
Anthony Lapenna
182f3734d0 fix(api): fix an issue with unsupported cron format (#3240)
* fix(api): fix an issue with unsupported cron format

* refactor(api): review migration method
2019-10-08 16:18:32 +13:00
Anthony Lapenna
d717ad947b feat(api): remove cron second support 2019-10-08 14:39:37 +13:00
Anthony Lapenna
9aa52a6975 feat(settings): add new settings to disable volume browser (#3239)
* feat(settings): add new settings to disable volume browser

* feat(api): update setting to be compliant with RBAC

* refactor(api): update method comment

* fix(api): remove volume browsing authorizations by default

* feat(settings): rewrite volume management setting description

* feat(settings): rewrite volume management setting tooltip

* Update app/portainer/views/settings/settings.html

Co-Authored-By: William <william.conquest@portainer.io>
2019-10-08 13:17:58 +13:00
firecyberice
ef4c138e03 fix(authentication): trim the newline character from the password string (#3091) 2019-10-08 11:52:37 +13:00
Anthony Lapenna
68fe5d6906 fix(api): fix invalid restriction on StatusInspectVersion 2019-10-08 11:45:16 +13:00
Anthony Lapenna
b0f48ee3ad feat(app): fix XSS vulnerabilities (#3230) 2019-10-07 16:24:48 +13:00
Anthony Lapenna
2912e78f68 fix(api): add access validation for agent browse requests (#3235)
* fix(api): add access validation for agent browse requests

* fix(api): review query parameter retrieval

* refactor(api): remove useless else case
2019-10-07 16:24:08 +13:00
Anthony Lapenna
fb6f6738d9 fix(api): prevent the use of bind mounts in stacks if setting enabled (#3232) 2019-10-07 16:12:21 +13:00
Anthony Lapenna
f7480c4ad4 feat(api): prevent non administrator users to use admin restricted API endpoints (#3227) 2019-10-07 16:10:51 +13:00
Anthony Lapenna
1fbe6a12f1 fix(api): fix invalid resource control check (#3225) 2019-10-07 16:09:35 +13:00
Anthony Lapenna
b7c38b9569 feat(api): trigger user authorization update when required (#3213)
* refactor(api): remove useless type cast

* feat(api): trigger user authorization update when required

* fix(api): fix missing RegistryService injection
2019-10-07 15:42:01 +13:00
Frans-Jan van Steenbeek
6c996377f5 fix(container-creation): prevent duplicate MAC addresses after edit (#1645) (#2993) 2019-10-03 15:37:34 +13:00
William
81e9484dd3 docs(project): add security info to readme (#3211)
* docs(project): add security info to readme

* docs(project): fix whitespace in previous commit
2019-10-03 13:03:14 +13:00
Anthony Lapenna
3ab0422361 Revert "feat(build-system): bump Docker binary version to 19.03.2 (#3202)" (#3210)
This reverts commit ed70d0fb2b.
2019-10-03 11:23:07 +13:00
Anthony Lapenna
d4fa4d8a52 fix(api): always persist data after initial extension check 2019-09-30 14:03:59 +13:00
Pierre Kisters
ed70d0fb2b feat(build-system): bump Docker binary version to 19.03.2 (#3202) 2019-09-30 10:22:04 +13:00
Anthony Lapenna
ea05d96c73 feat(sidebar): add update notification (#3196)
* feat(sidebar): add update notification

* style(sidebar): update notification color palette

* refactor(api): rollback to latest version

* feat(sidebar): update style

* style(sidebar): fix color override
2019-09-26 08:38:11 +12:00
xAt0mZ
b034a60724 fix(auth): authController full rewrite (#3173)
* fix(auth): authController full rewrite

fixes 2 bugs caused by legacy code

* fix(auth): moving state to cookies for Firefox private browsing

* fix(auth): clean query params on OAuth response
2019-09-25 13:36:24 +12:00
Anthony Lapenna
646038cd0f feat(exec): add DEBUG statement when validating license (#3191) 2019-09-24 17:06:08 +12:00
Anthony Lapenna
42d4e1e11c fix(api): prevent panic in auth when OAuth is enabled (#3179) 2019-09-24 11:03:44 +12:00
Anthony Lapenna
b84fa9db2f feat(build-system): remove VOLUME statement from Windows Dockerfile (#3181) 2019-09-20 16:38:43 +12:00
Anthony Lapenna
7509283072 fix(home): refresh the view on endpoint ping failure (#3161)
* fix(api): remove automatic backend failure for Down endpoints

* fix(home): refresh the view on endpoint ping failure
2019-09-20 16:14:44 +12:00
Anthony Lapenna
1f68aad07f feat(api): prevent endpoint creation with already paired agent (#3159) 2019-09-20 16:14:19 +12:00
Anthony Lapenna
07505fabcc fix(api): remove automatic backend failure for Down endpoints (#3160) 2019-09-20 16:13:58 +12:00
Anthony Lapenna
a5e5983c28 feat(api): only error on ping failure for snapshots (#3177) 2019-09-20 16:13:44 +12:00
Anthony Lapenna
baa64ca927 refactor(api): update scheduler to match new cron lib API (#3157) 2019-09-15 10:47:44 +12:00
William
8e922dbfc6 fix(endpoint-creation): clarify docker endpoint (#3148)
* fix(endpoint-creation): clarify docker endpoint

* fix(endpoint-creation): change default order
2019-09-11 07:24:29 +12:00
Anthony Lapenna
7d76bc89e7 feat(api): relocate authorizations outside of JWT (#3079)
* feat(api): relocate authorizations outside of JWT

* fix(api): update user authorization after enabling the RBAC extension

* feat(api): add PortainerEndpointList operation in the default portainer authorizations

* feat(auth): retrieve authorization from API instead of JWT

* refactor(auth): move permissions retrieval to function

* refactor(api): document authorizations methods
2019-09-10 10:58:26 +12:00
xAt0mZ
7ebb3e62dd fix(services): mounted volumes are now persisted and displayed correctly (#3114) 2019-09-10 10:57:36 +12:00
xAt0mZ
52704e681b feat(services): rollback service capability (#3057)
* feat(services): rollback service capability

* refactor(services): notification reword

Co-Authored-By: William <william.conquest@portainer.io>

* refactor(services): remove TODO comment + add note on rollback capability

* fix(services): service update rpc error version out of sync

* feat(services): confirmation modal on rollback

* feat(services): rpc error no previous spec message
2019-09-10 10:56:57 +12:00
Steven Kang
ec19faaa24 fix(stack): Skip SSL Verification (#3064)
* fix(stack): Skip SSL Verification

* fix(stack): Skip SSL Verification

* fix(stack): move httpsCli into service

* fix(stack): clean-up

* fix(stack): move httpsCli back into the function

* fix(stack): move httpsCli and InstallProtocol back into service

* fix(stack): clean-up debugging

* fix(stack): parameter cleanup

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>
2019-09-10 10:56:16 +12:00
Anthony Lapenna
628d4960cc fix(api): fix an issue with RegistryUpdate operation (#3137) 2019-09-10 10:55:27 +12:00
Anthony Lapenna
2b48f1e49a refactor(build-system): clarify build system usage through yarn (#3140)
* refactor(build-system): clarify build system usage through yarn

* refactor(build-system): rename azure devops build scripts
2019-09-09 12:40:22 +12:00
Anthony Lapenna
849ff8cf9b docs(api): document EdgeAgentCheckinInterval parameter for SettingsUpdate 2019-09-02 07:17:41 +12:00
Anthony Lapenna
a90fa857ee docs(api): document Edge agent environment type 2019-08-30 09:30:30 +12:00
Mattias Kågström
c34e83cafd docs(README): fix typo in readme (#3071) 2019-08-14 15:03:47 +02:00
Anthony Brame
ea6cddcfd3 feat(swarmvisualizer): add labels display under node info (#2886)
* feat(swarmvisualizer): add labels display under node info

* feat(swarmvisualizer): fix css

* add toggle to display node labels

* feat(swarmvisualizer): rename filters section + fix display when label has no value

* feat(swarmvisualizer): retrieve state from local storage for node labels display toggle
2019-08-13 17:38:04 +02:00
xAt0mZ
96155ac97f feat(app): debounce on all search fields (#3058) 2019-08-12 16:27:05 +02:00
xAt0mZ
c12ce5a5c7 feat(networks): group networks for swarm endpoints (#3028)
* feat(networks): group networks for swarm endpoints

* fix(networks): display error on networks with 1 sub
2019-08-12 16:26:44 +02:00
xAt0mZ
552c897b3b fix(oauth): okta support (#3051)
* fix(oauth): okta support

* fix(oauth): state to follow OAuth 2 RFC against CSRF
2019-08-12 16:26:06 +02:00
xAt0mZ
24013bc524 fix(datatables): saved orderBy was always overridden by the default one (#3052) 2019-08-12 16:25:35 +02:00
William
3afeb13891 chore(project): adjust stalebot config (#3081) 2019-08-12 10:30:19 +02:00
Anthony Lapenna
e11df28df6 fix(api): fix missing windows dependency 2019-07-28 10:30:12 +12:00
xAt0mZ
a33dbd1e91 fix(oauth): state to follow OAuth 2 RFC against CSRF 2019-07-26 20:05:25 +02:00
xAt0mZ
b537a9ad0d fix(oauth): okta support 2019-07-26 20:05:25 +02:00
Anthony Lapenna
a6692ee526 Merge tag '1.22.0' into develop
Release 1.22.0
2019-07-26 14:02:03 +12:00
Anthony Lapenna
0b2a76d75a Merge branch 'release/1.22.0' 2019-07-26 14:01:58 +12:00
Anthony Lapenna
8cb18f9877 chore(version): bump version number 2019-07-26 14:01:49 +12:00
Anthony Lapenna
448003aaa4 docs(swagger): update Swagger documentation 2019-07-26 11:10:26 +12:00
Anthony Lapenna
12a512f01f feat(edge): introduce support for Edge agent (#3031)
* feat(edge): fix webconsole and agent deployment command

* feat(edge): display agent features when connected to IoT endpoint

* feat(edge): add -e CAP_HOST_MANAGEMENT=1 to agent command

* feat(edge): add -v /:/host and --name portainer_agent_iot to agent command

* style(endpoint-creation): refactor IoT agent to Edge agent

* refactor(api): rename AgentIoTEnvironment to AgentEdgeEnvironment

* refactor(api): rename AgentIoTEnvironment to AgentEdgeEnvironment

* feat(endpoint-creation): update Edge agent deployment instructions

* feat(edge): wip edge

* feat(edge): refactor key creation

* feat(edge): update deployment instructions

* feat(home): update Edge agent endpoint item

* feat(edge): support dynamic ports

* feat(edge): support sleep/wake and snapshots

* feat(edge): support offline mode

* feat(edge): host job support for Edge endpoints

* feat(edge): introduce STANDBY state

* feat(edge): update Edge agent deployment command

* feat(edge): introduce EDGE_ID support

* feat(edge): update default inactivity interval to 5min

* feat(edge): reload Edge schedules after restart

* fix(edge): fix execution of endpoint job against an Edge endpoint

* fix(edge): fix minor issues with scheduling UI/UX

* feat(edge): introduce EdgeSchedule version management

* feat(edge): switch back to REQUIRED state from ACTIVE on error

* refactor(edge): remove comment

* feat(edge): updated tunnel status management

* feat(edge): fix flickering UI when accessing Edge endpoint from home view

* feat(edge): remove STANDBY status

* fix(edge): fix an issue with console and Swarm endpoint

* fix(edge): fix an issue with stack deployment

* fix(edge): reset timer when applying active status

* feat(edge): add background ping for Edge endpoints

* fix(edge): fix infinite loading loop after Edge endpoint connection failure

* fix(home): fix an issue with merge

* feat(api): remove SnapshotRaw from EndpointList response

* feat(api): add pagination for EndpointList operation

* feat(api): rename last_id query parameter to start

* feat(api): implement filter for EndpointList operation

* fix(edge): prevent a pointer issue after removing an active Edge endpoint

* feat(home): front - endpoint backend pagination (#2990)

* feat(home): endpoint pagination with backend

* feat(api): remove default limit value

* fix(endpoints): fix a minor issue with column span

* fix(endpointgroup-create): fix an issue with endpoint group creation

* feat(app): minor loading optimizations

* refactor(api): small refactor of EndpointList operation

* fix(home): fix minor loading text display issue

* refactor(api): document bolt services functions

* feat(home): minor optimization

* fix(api): replace seek with index scanning for EndpointPaginated

* fix(api): fix invalid starting index issue

* fix(api): first implementation of working filter

* fix(home): endpoints list keeps backend pagination when it needs to

* fix(api): endpoint pagination doesn't drop the first item on pages >=2 anymore

* fix(home): UI flickering on page/filter load/change

* feat(auth): login spinner

* feat(api): support searching in associated endpoint group data

* refactor(api): remove unused API endpoint

* refactor(api): remove comment

* refactor(api): refactor proxy manager

* feat(api): declare EndpointList params as optional

* feat(api): support groupID filter on endpoints route

* feat(api): add new API operations endpointGroupAddEndpoint and endpointGroupDeleteEndpoint

* feat(edge): new icon for Edge agent endpoint

* fix(edge): fix missing exec quick action

* fix(edge): add loading indicator when connecting to Edge endpoint

* feat(edge): disable service webhooks for Edge endpoints

* feat(endpoints): backend pagination for endpoints view (#3004)

* feat(edge): dynamic loading for stack migration feature

* feat(edge): wordwrap edge key

* feat(endpoint-groups): backend pagination support for create and edit

* feat(endpoint-groups): debounce on filter for create/edit views

* feat(endpoint-groups): filter assigned on create view

* (endpoint-groups): unassigned endpoints edit view

* refactor(endpoint-groups): code clean

* feat(endpoint-groups): remove message for Unassigned group

* refactor(websocket): minor refactor associated to Edge agent

* feat(endpoint-group): enable backend pagination (#3017)

* feat(api): support groupID filter on endpoints route

* feat(api): add new API operations endpointGroupAddEndpoint and endpointGroupDeleteEndpoint

* feat(endpoint-groups): backend pagination support for create and edit

* feat(endpoint-groups): debounce on filter for create/edit views

* feat(endpoint-groups): filter assigned on create view

* (endpoint-groups): unassigned endpoints edit view

* refactor(endpoint-groups): code clean

* feat(endpoint-groups): remove message for Unassigned group

* refactor(api): endpoint group endpoint association refactor

* refactor(api): rename files and remove comments

* refactor(api): remove usage of utils

* refactor(api): optional parameters

* Merge branch 'feat-endpoint-backend-pagination' into edge

# Conflicts:
#	api/bolt/endpoint/endpoint.go
#	api/http/handler/endpointgroups/endpointgroup_update.go
#	api/http/handler/endpointgroups/handler.go
#	api/http/handler/endpoints/endpoint_list.go
#	app/portainer/services/api/endpointService.js

* fix(api): fix default tunnel server credentials

* feat(api): update endpointListOperation behavior and parameters

* fix(api): fix interface declaration

* feat(edge): support configurable Edge agent checkin interval

* feat(edge): support dynamic tunnel credentials

* feat(edge): update Edge agent deployment commands

* style(edge): update Edge agent settings text

* refactor(edge): remove unused credentials management methods

* feat(edge): associate a remote addr to tunnel credentials

* style(edge): update Edge endpoint icon

* feat(edge): support encrypted tunnel credentials

* fix(edge): fix invalid pointer cast

* feat(bolt): decode endpoints with jsoniter

* feat(edge): persist reverse tunnel keyseed

* refactor(edge): minor refactor

* feat(edge): update chisel library usage

* refactor(endpoint): use controller function

* feat(api): database migration to DBVersion 19

* refactor(api): refactor AddSchedule function

* refactor(schedules): remove comment

* refactor(api): remove comment

* refactor(api): remove comment

* feat(api): tunnel manager now only manage Edge endpoints

* refactor(api): clean-up and clarification of the Edge service

* refactor(api): clean-up and clarification of the Edge service

* fix(api): fix an issue with Edge agent snapshots

* refactor(api): add missing comments

* refactor(api): update constant description

* style(home): remove loading text on error

* feat(endpoint): remove 15s timeout for ping request

* style(home): display information about associated Edge endpoints

* feat(home): redirect to endpoint details on click on unassociated Edge endpoint

* feat(settings): remove 60s Edge poll frequency option
2019-07-26 10:38:07 +12:00
Anthony Lapenna
2252ab9da7 style(app): update app loading text (#3046) 2019-07-26 10:20:38 +12:00
xAt0mZ
7338e5fabd fix(security): bump lodash to 4.17.15 (#3043) 2019-07-26 10:14:18 +12:00
Anthony Lapenna
5b91b1a6c9 feat(api): bump default Docker library timeout to 60s (#3038) 2019-07-24 11:56:31 +12:00
xAt0mZ
66b6a6cbbd fix(app): UI settings persistency (#3025) 2019-07-22 20:10:49 -07:00
xAt0mZ
1089846fd6 fix(datatables): default orderby now applied correctly (#3022) 2019-07-22 20:09:43 -07:00
William
fbcffb7969 chore(project): adjust stalebot config (#3029) 2019-07-22 16:28:39 -07:00
xAt0mZ
2bf125c8cc fix(app): un-needed checkbox in service details view (#2982) 2019-07-22 12:59:29 +02:00
xAt0mZ
9ec83bb065 style(container-stats): clarify network graph is aggregate (#3003) 2019-07-22 12:59:01 +02:00
xAt0mZ
64d382f612 fix(containers): multiple clics on image commit (#3013) 2019-07-22 12:58:22 +02:00
xAt0mZ
4fcd2e8afe style(container-creation): clarify ports mapping (#2995) 2019-07-22 12:55:58 +02:00
William
16234aa0c1 style(users): fix typo/grammar (#3010) 2019-07-22 12:55:40 +02:00
xAt0mZ
03c82cac69 feat(datatables): auto refresh on datatables (#2974)
* feat(datatables): auto refresh on datatables

* feat(datatables): auto refresh implementation on docker related resources
2019-07-22 12:54:59 +02:00
linquize
cc487ae68a fix(registries): can edit registries when --no-auth is set (#2763) 2019-07-20 16:48:59 -07:00
Anthony Lapenna
90d3f3a358 Enable endpoint backend pagination (#2989)
* feat(api): remove SnapshotRaw from EndpointList response

* feat(api): add pagination for EndpointList operation

* feat(api): rename last_id query parameter to start

* feat(api): implement filter for EndpointList operation

* feat(home): front - endpoint backend pagination (#2990)

* feat(home): endpoint pagination with backend

* feat(api): remove default limit value

* fix(endpoints): fix a minor issue with column span

* fix(endpointgroup-create): fix an issue with endpoint group creation

* feat(app): minor loading optimizations

* refactor(api): small refactor of EndpointList operation

* fix(home): fix minor loading text display issue

* refactor(api): document bolt services functions

* feat(home): minor optimization

* fix(api): replace seek with index scanning for EndpointPaginated

* fix(api): fix invalid starting index issue

* fix(api): first implementation of working filter

* fix(home): endpoints list keeps backend pagination when it needs to

* fix(api): endpoint pagination doesn't drop the first item on pages >=2 anymore

* fix(home): UI flickering on page/filter load/change

* feat(api): support searching in associated endpoint group data

* feat(api): declare EndpointList params as optional

* feat(endpoints): backend pagination for endpoints view (#3004)

* feat(endpoint-group): enable backend pagination (#3017)

* feat(api): support groupID filter on endpoints route

* feat(api): add new API operations endpointGroupAddEndpoint and endpointGroupDeleteEndpoint

* feat(endpoint-groups): backend pagination support for create and edit

* feat(endpoint-groups): debounce on filter for create/edit views

* feat(endpoint-groups): filter assigned on create view

* (endpoint-groups): unassigned endpoints edit view

* refactor(endpoint-groups): code clean

* feat(endpoint-groups): remove message for Unassigned group

* refactor(api): endpoint group endpoint association refactor

* refactor(api): rename files and remove comments

* refactor(api): remove usage of utils

* refactor(api): optional parameters

* feat(api): update endpointListOperation behavior and parameters

* refactor(api): remove unused methods associated to EndpointService

* refactor(api): remove unused methods associated to EndpointService

* refactor(api): minor refactor
2019-07-20 16:28:11 -07:00
William
d52a1a870c chore(project): clarify bug template (#3021) 2019-07-18 17:46:25 -07:00
William
0b7500827b chore(project): stalebot integration (#3019)
* chore(project): stalebot integration

* chore(project): put file in correct directory
2019-07-18 16:28:08 -07:00
xAt0mZ
f71a565acc refactor(container): reword notification messages 2019-07-18 17:19:00 +02:00
Anthony Lapenna
92a615d7b6 Revert "fix(api): AddCron fix after library update (#3014)" (#3016)
This reverts commit c432ead45f.
2019-07-16 22:22:57 -07:00
xAt0mZ
c432ead45f fix(api): AddCron fix after library update (#3014) 2019-07-16 21:34:31 -07:00
xAt0mZ
a856053338 fix(containers): multiple clics on image commit button were creating a lot of images 2019-07-15 13:28:30 +02:00
itsconquest
afda5d07bf style(container-stats): clarify network graph is aggregate 2019-07-11 16:52:28 +12:00
xAt0mZ
693182fbd3 feat(auth): login spinner (#2999) 2019-07-11 04:13:03 +12:00
itsconquest
d1fee6f119 style(container-creation): clarify ports mapping 2019-07-10 17:16:43 +12:00
xAt0mZ
4084e7c8ec feat(home): pagination on endpoints list (#2981) 2019-07-05 09:46:59 +12:00
xAt0mZ
f20526d662 fix(app): disable-authorization directive was hiding/showing elements instead of disabling them 2019-07-04 15:36:29 +02:00
xAt0mZ
3d4af7c54f feat(registry): disable browse for quay.io registry (#2971)
* feat(registry): disable browse for quay.io registry

* refactor(registry): browsable urls check done with function
2019-07-03 00:33:46 +02:00
xAt0mZ
1138fd5ab1 fix(datatables): allow selecting range using shift (#344) (#2962)
* fix(datatables): allow selecting range using shift (#344)

* feat(datatables): more intuitive batch select behaviour

* feat(datatables): add overridable function called on selection change

* refactor(datatables): remove custom selectAll on Generic-extending Controllers

* fix(datatables): stored state data retrieval on Generic-extanding datatables controllers

* refactor(datatables): remove code duplication between GenericController and extending controllers
2019-07-02 17:51:17 +02:00
xAt0mZ
6591498ab9 feat(node-details): move engine labels from node-details panel to engine-details panel (#2966) 2019-06-25 11:22:45 +12:00
Anthony Lapenna
7a8a54c96a refactor(api): introduce ExtensionServer constant 2019-06-23 11:36:45 +12:00
Anthony Brame
b3c7c76be2 fix(swarmvisualizer): nodes are now sorted by roles then by hostname (#2885) 2019-06-21 15:50:58 +02:00
Michael Oborne
fb69ffa764 fix(create-container): init ExposedPorts on container creation process (#2933) 2019-06-21 15:48:52 +02:00
Pedro Henrique
96f266adf6 fix(volume-browser): download capability for all types of files (#2954) 2019-06-21 15:44:29 +02:00
William
f3b9668629 fix(endpoints): always reset agent headers when switching state (#2939) 2019-06-18 14:45:49 +02:00
xAt0mZ
71b1da8d32 fix(app): wrapper for UI refresh trigger with async/await (#2945)
* fix(app): wrapper for UI refresh trigger with async/await

* fix(async): $async wrapper now accepts functions with params

* fix(async): $async should return a promise to be chained with ES5 .then() style

* fix(async): $async with multiple params was not working

* refactor(app): wrap all async functions with $async

* docs(async): add link to async wrapper documentation
2019-06-17 16:51:39 +02:00
xAt0mZ
09cf55a7dc fix(build): bump auto-ngtemplate-loader to 2.0.1 to fix windows builds (#2935) 2019-06-14 14:22:49 +02:00
dependabot[bot]
ead160f792 chore(deps): bump js-yaml from 3.10.0 to 3.13.1 (#2930)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.10.0 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.10.0...3.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-11 23:41:32 +02:00
xAt0mZ
144e0ae07e refactor(app): move storidge to new 'integrations' module (#2905)
* refactor(app): move storidge to new 'integrations' module

* style(storidge): revert TODO note removal
2019-06-11 23:13:18 +02:00
Anthony Lapenna
67de71a18f docs(api): update swagger documentation 2019-06-11 10:34:54 +12:00
Anthony Lapenna
e5f092058b Merge tag '1.21.0' into develop
Release 1.21.0
2019-06-04 15:51:32 +12:00
Anthony Lapenna
c1433eff0d Merge branch 'release/1.21.0' 2019-06-04 15:51:20 +12:00
Anthony Lapenna
48281df41a chore(version): bump version number 2019-06-04 15:51:11 +12:00
Steven Kang
af08a1b0f6 fix(build-system) - fix Windows build on Azure devops (#2921)
* fix(build-system) - add sac2016 tag

This is to fix the Windows image build, where MS stopped supporting the `latest` tag

* fix(build-system) - use ARG for win multi-arch

* fix(build-system) - use ARG for win multi-arch

* fix(build-system) - delete unused Dockerfile

* fix(build-system) - use ARG for win multi-arch

* fix(build-system) - update GOPATH

* fix(build-system) - update GOPATH and add debug

* Debug

* Debug

* fix(build-system) - add static tag

* fix(build-system) - add static tag

* fix(build-system) - revert GOPATH

* Debug

* Debugging

* Debugging

* Debugging

* Debugging

* fix(build-system) - fix binary location

* fix(build-system) - enable verbose output

* fix(build-system) - Remove relativeTo Options

* fix(build-system) - update options

* fix(build-system) - Remove Debug
2019-06-04 14:05:04 +12:00
Anthony Lapenna
b4c16a1fb4 refactor(api): update ExtensionDefinitionsURL 2019-06-04 13:54:16 +12:00
Anthony Lapenna
d55212e9da docs(api): update Swagger documentation 2019-06-04 11:19:37 +12:00
Anthony Lapenna
50f547a6e7 feat(motd): add the ability to use custom style (#2918)
* feat(motd): rework motd display mechanism for more flexibility on motd content

* feat(api): enhance MOTD

* refactor(api): refactor MOTD related codebase

* feat(motd): hash on message
2019-06-02 18:16:43 +12:00
Anthony Lapenna
1d9166216a feat(app): set anonymizeIp property for GA (#2919) 2019-06-02 18:16:07 +12:00
Steven Kang
d75f2f5d7d fix(build-system) - add sac2016 tag for Windows image (#2909) 2019-05-29 16:57:30 +12:00
baron_l
5388585ef1 fix(app): extensions status retrieval (#2910)
* fix(rbac): extensions status retrieval not interrupted anymore

* refactor(extensions): change endpoint used to retrieve extension activation status
2019-05-29 12:39:30 +12:00
Anthony Lapenna
086d4f1d1c feat(containers): hide the attach quick action by default (#2908)
* feat(containers): hide the attach quick action by default

* fix(containers): add missing display checks for quick actions column

* fix(services): add missing showQuickActionAttach property
2019-05-29 12:15:52 +12:00
baron_l
608fc497a8 fix(app): extensions cache only for rbac (#2904) 2019-05-28 20:41:20 +12:00
Anthony Lapenna
dc3a29ad43 refactor(rbac): update RBAC name to full-length name 2019-05-27 15:48:46 +12:00
Anthony Lapenna
5fda4ff9f8 refactor(api): update role descriptions 2019-05-27 15:47:08 +12:00
Anthony Lapenna
23eaf14f58 style(roles): fix typo 2019-05-27 10:43:03 +12:00
Anthony Lapenna
a2d29df21b fix(rbac): add specific authorization for Storidge management 2019-05-27 10:41:12 +12:00
Anthony Lapenna
4349f5803c fix(api): fix missing default Portainer permissions for users 2019-05-27 09:31:20 +12:00
Anthony Lapenna
407328f9ed fix(api): remove admin restriction for registry proxy endpoint 2019-05-27 09:15:50 +12:00
William
e3eeb32a11 style(container-creation): clarify port mapping (#2899) 2019-05-25 09:56:30 +12:00
baron_l
851607394c feat(integrations): storidge evolution (#2711)
* feat(storidge): update storidge routes

* feat(storidge): add new fields on profile create/edit

* feat(storidge): add drives list and details view

* feat(storidge): add node details / cordon / uncordon / remove

* feat(storidge): add volume and snapshot details

* feat(storidge): add snapshot creation on volume details

* feat(storidge): add rescan drives button

* refactor(storidge): move add / remove / put in / put ouf maintenance buttons for cluster nodes

* style(storidge): change cluster / node icon color based on status

* feat(storidge): profiles can enable snapshots without interval + interval in minutes

* refactor(storidge): split cluster and node status badge filter

* fix(storidge): error on volume IOPS update

* fix(storidge): snapshot can now be created without comments

* feat(storidge): remove snapshots panels when volume snapshots are disabled

* fix(app): paginatedItemLimit now retrieved for datables extending GenericDatatableController

* fix(storidge): addDrive is called with the good parameters

* fix(storidge): update model and views for Storidge v2695

* refactor(storidge): webpack migration

* fix(storidge): display modifications + fix js errors

* feat(storidge): snapshots, profile and nodes evolution

* fix(storidge): values for InterfaceDriver on profile create/edit

* feat(storidge): v5 update without style (profile / statuses / volume)

* fix(storidge): description tables on the same view have now the same fixed offset

* fix(app): override rdash-ui select style

* Revert "fix(app): override rdash-ui select style"

This reverts commit e724833261.

* feat(storidge): wip on update 6

* feat(storidge): update 6

* feat(storidge): update 6

* feat(storidge): update 6

* feat(storidge): update 7 - node details + cluster views

* fix(storidge): update 7 - profiles creation + volume details

* fix(storidge): update 7 - profile create/edit interface type

* feat(storidge): update 8 - add drive

* feat(storidge): update 8 - UI refactors + cluster availability

* fix(storidge): update 8 - revert cluster availability

* feat(storidge): update 8 - node availability on swarm overview

* feat(storidge): cluster condition badge

* fix(storidge): update 9 - move add storage button + api profile filesystem kv to obj

* feat(storidge): update 9 - disable add drive button when action is in progress

* fix(storidge): update 9 - add drive button will now change only for the concerned drive

* fix(storidge): update 10 - disable remove drive button when removal in progress

* fix(api): update Storidge proxy creation process

* refactor(api): update version number

* feat(extensions): fix an issue with Storidge API URL

* feat(storidge): force the use of a manager node
2019-05-25 09:53:10 +12:00
Anthony Lapenna
17765d992e fix(api): fix missing winio dependency 2019-05-24 19:35:15 +12:00
Anthony Lapenna
8057aa45c4 feat(extensions): introduce RBAC extension (#2900) 2019-05-24 18:04:58 +12:00
William
27a0188949 feat(build-system): remove webpack-bundle-analyzer plugin (#2898) 2019-05-24 17:59:44 +12:00
William
c8c8345a43 dep(jquery): update jquery to version 3.4.0 (#2897) 2019-05-24 17:58:25 +12:00
William
8025d4c817 fix(support): enforce minimum purchase amount (#2891)
* fix(support): enforce minimum purchase amount

* Update app/portainer/views/support/product/product.html

Co-Authored-By: Anthony Lapenna <lapenna.anthony@gmail.com>

* fix(support): fix product img tags for webpack
2019-05-24 17:57:27 +12:00
Anthony Lapenna
6be394c2e0 refactor(api): minor refactor to stream.go 2019-05-13 09:20:55 +12:00
Kai
540d3c2c6b feat(api): support utf8 output in websocket endpoints
* change TCPConnToWebsocketConn read function to ReadRune

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Update websocket_exec.go

* Delete Project_Default.xml

* Delete modules.xml

* Delete portainer.iml

* Delete vcs.xml

* Delete workspace.xml

* Delete exec.go

* change TCPConnToWebsocketConn read function to ReadRune

* Apply suggestions from code review

Co-Authored-By: Anthony Lapenna <lapenna.anthony@gmail.com>

* Update stream.go
2019-05-13 08:55:25 +12:00
mrdrogdrog
1af9fb4490 feat(containers): add support docker attach (#2842)
* #592 feat(container-details): split websocket backend code into more files and add attach handler

* #592 feat(container-details): rename console to exec and add attach console

* Revert "#592 feat(container-details): rename console to exec and add attach console"

This reverts commit f2deaee1

* #592 feat(container-details): add attach to containerconsole

* #592 feat(container-details): catch more errors

* #592 feat(container-details): use less vars

* #592 feat(container-details): error message is more verbose

* #592 feat(container-details): go fmt

* #592 feat(container-details): unpack netdial

* #592 feat(container-details): reformat service

* #592 feat(container-details): fix go compiler bugs

* #592 feat(container-details): refactor services

* #592 feat(container-details): fix windows dial

* #592 feat(container-details): gofmt dial_windows.go

* #592 feat(container-details): split console into two views and fix breadcrumbs

* #592 feat(container-details): swap exec and attach action

* #592 feat(container-details): add some warnings

* #592 feat(container-details): refresh view more

* #592 feat(container-details): use less functions for connecting/disconnecting

* #592 feat(container-details): move link replacements into initTerm

* #592 feat(container-details): disable attach/exec button if container is not running

* #592 feat(container-details): fix typo

* #592 feat(container-details): autoconnect attach view

* #592 feat(container-details): fix first draw after attach + reformat code

* #592 feat(container-details): remove init-helper-div

* #592 feat(container-details): console resize code and remove padding

* #592 feat(container-details): swap height and width arguments in container tty resize restcall

* #592 feat(container-details): swap height and width arguments in exec tty resize restcall

* #592 feat(container-details): remove css unit

* #592 feat(container-details): remove loaded state from states object

* #592 feat(container-details): reword Disattach to Detach

* #592 feat(container-details): remove unloaded state from states object

* #592 feat(container-details): remove useless code

* #592 feat(container-details): clearer state-check

* #592 feat(container-details): fixed resize bugs by using xterms col attribute
2019-05-09 14:04:40 +12:00
Steven Kang
dc9a3de88f feat(webhooks): Add Tag Support (#2871)
* feat(webhooks): Add Tag Support

* feat(webhooks): Add Tag Support
2019-05-08 10:41:31 +12:00
baron_l
7b3ef7f1a2 fix(node-details): engine labels were displayed as Objects (#2858) 2019-05-02 08:37:24 +12:00
William
80c5052b55 style(users): fix typo/grammar (#2848) 2019-04-23 12:22:54 +12:00
William
845f4e912b fix(secret-creation): prevent assignment of label with no name (#2838) 2019-04-19 09:18:40 +12:00
Anthony Lapenna
e5fd61044a feat(project): update issue templates to include a note about support policy 2019-04-12 10:00:18 +12:00
Anthony Lapenna
c3066d7f3f docs(README): add a note about support policy 2019-04-12 09:57:56 +12:00
William
8a7a73fe84 fix(notifications): fix create user errormessage (#2820) 2019-04-08 15:48:43 +12:00
William
0f8de0a039 fix(build-system): fix lodash imports (#2818) 2019-04-08 12:35:02 +12:00
William
e4a81df42e fix(group-access): fix authorize/deny all buttons behavior (#2813) 2019-04-08 09:28:57 +12:00
William
c39807e86c fix(team): fix invalid team leader count (#2811) 2019-04-05 14:49:08 +13:00
Chaim Lev-Ari
45113a7ff4 refactor(app): introduce webpack and babel (#2407)
* feat(agent): add new host page

* feat(agent): convert volume-browser to files-datatable

* fix(agent): browse folders in file-datatable

* feat(engine-details): replace engine view with host view

* feat(engine-details): remove old panels

* feat(engine-details): add basic engine-details-panel component

* feat(engine-details): pass details to the different components

* feat(engine-details): replace host-view with host-overview

* feat(engine-details): add commaseperated filter

* feat(engine-details): add host-view container component

* feat(engine-details): add host-details component

* feat(engine-details): build host details object

* feat(engine-details): format engine version

* feat(engine-details): get details for one node

* feat(engine-details): pass is-agent from view

* feat(engine-details): replace old node view with a new component

* feat(engine-details): add swarm-node-details component

* feat(engine-details): remove isSwarm binding

* feat(engine-details): remove node-details and include in parent

* feat(engine-details): add labels-table component

* feat(engine-details): add update node service

* feat(engine-details): add update label functionality

* style(engine-details): remove whitespaces

* feat(engine-details): remove old node page

* feat(engine-details): pass is agent to host details

* feat(host-details): hide missing info

* feat(host-details): update node availability

* style(host-details): remove obsolete event object

* feat(host-details): fix labels not sending

* feat(host-details): remove flags for hiding data

* feat(host-details): create mock call to server for agent host info

* style(host-details): fix spelling mistake in filter's name

* feat(host-details): get info from agent

* feat(host-details): hide engine labels when empty

* feat(node-details): move labels table and save button

* feat(host-info): add different urls for refresh

* feat(host-details): show disk/devices info for agent

* feat(host-view): add loading indicator to devices-panel

* feat(host-details): add loading indicator to disks panel

* feat(agent): fix browse volume

* feat(agent): browse files

* feat(agent): enable rename

* feat(agent): download file

* fix(agent): download file from root

* feat(agent): delete file

* style(agent): remove whitespaces

* fix(agent): fix link on node browser

* feat(agent): basic file uploader

* feat(agent): add basic file upload

* fix(volume-browser): move volume id to query params

* feat(node-browser): moved uploader into browser

* feat(node-browser): add upload spinner

* feat(agent): browse files relative to root

* feat(build): add webpack build config

* feat(build): add missing imports

* feat(webpack): add missing imports

* feat(build): enable eslint on build

* feat(build): add webpack notifier

* feat(build): clean terminal on build

* feat(build): import all globals

* feat(build): add angular import

* feat(build): fix styles

* feat(build): load favicons

* feat(build): load css before script

* feat(webpack): split vendors css and js to a different bundle

* feat(webpack): import angular in all files

* feat(webpack): remove eslint global config

* feat(webpack): add webpack clean dist

* feat(webpack): fix styling issues

* refactor(webpack): remove empty controllers

* refactor(webpack): optimize moment

* refactor(webpack): add bundle analyzer

* feat(webpack): add babel

* refactor(webpack): optimize lodash

* refactor(toastr): update toastr

* feat(webpack): create basic production and dev config

* fix(webpack): fix production config

* fix(webpack): fix html templates url

* refactor(webpack): remove angular imports

* refactor(webpack): remove more angular imports

* refactor(webpack): return angular to entry file

* style(webpack): remove comments from config

* fix(hosts): remove browse button

* fix(webpack): import lodash

* fix(webpack): import missing htmls

* feat(webpack): reduce lodash size

* feat(webpack): config grunt to use webpack

* feat(webpack): add postcss

* chore(codeclimate): use eslint-5 channel

* feat(deps): upgrade from lodash to lodash-es

* fix(webpack): fix bug with lodash

* chore(build): add build client script

* fix(webpack): fix missing jsyaml reference

* refactor(webpack): seperate builds of img files

* chore(build): add a way to check times of webpack build

* feat(webpack): add dev server

* fix(webpack): fix css output name

* chore(webpack): optimize images

* chore(webpack): add node env

* fix(build): copy templates on release

* chore(webpack): set env NODE_ENV

* feat(webpack): set NODE_ENV on production builds

* fix(extensions): set image path

* refactor(css): move vendor css to js import

* style(app): remove whitespaces

* fix(build-system): allow DevOps pipeline to leverage webpack (#2670)

* Update devopsbuild task to use webpack & remove AppVeyor environment var

* Added -Force to replace the existing dist folder

* Removed Test-Path

* dep(build-system): add angularjs-annotate to webpack + fix on imports

* Merge branch 'develop' into webpack

* refactor(app): webpack aliases for imports + async / await dep + start refactor

* style(extensions): use develop version of the view

* fix(app): fix several issues introduced by webpack migration

* fix(webpack): fix ng-include not loading templates with webpack

* Fix Windows CI with Webpack (#2782)

* fix(configs): refactor broke configs creation and list views

* fix(build-system): update build_binary_devops for Windows
2019-03-21 18:46:49 +13:00
Anthony Lapenna
14845a4a53 refactor(api): refactor base import path (#2788)
* refactor(api): refactor base import path

* fix(build-system): update build_binary_devops

* fix(build-system): fix build_binary_devops for linux

* fix(build-system): fix build_binary_devops for Windows
2019-03-21 14:20:14 +13:00
Steven Kang
0c7d69eb17 fix(build-system): fix an issue with Windows build in CI (#2780)
* Change GOPATH outside of the current project path

* Fix ENV Variable

* Fix locations

* Fix dist directory location
2019-03-15 19:08:35 +13:00
William
3b8f982dbd fix(build-system): Install docker binary when on macOS (#2775) 2019-03-13 14:58:04 +13:00
Fabian Grutschus
dbab524e5d style(containers): change order of container action buttons to match ordering of quick action buttons (#2772) 2019-03-13 11:10:15 +13:00
Anthony Lapenna
1618388e39 refactor(app): minor refactor (#2773) 2019-03-13 11:09:53 +13:00
William
ac4af41317 fix(services): Do not display quick actions in a regular swarm environment (#2769) 2019-03-11 16:48:00 +13:00
linquize
ce6cb837f9 refactor(api): fix lint issues (#2760) 2019-03-11 12:50:10 +13:00
Anthony Lapenna
9967ae5994 Merge tag '1.20.2' into develop
Release 1.20.2
2019-03-05 17:34:33 +13:00
Anthony Lapenna
a171e540c5 Merge branch 'release/1.20.2' 2019-03-05 17:34:28 +13:00
Anthony Lapenna
cb858f0412 chore(version): bump version number 2019-03-05 17:34:19 +13:00
Anthony Lapenna
82078a8d8f style(extensions): update extensions information panel 2019-03-05 16:09:03 +13:00
Anthony Lapenna
2b31f489d9 feat(api): add support for an externally fetched title for motd (#2755)
* feat(api): add support for an externally fetched title for motd

* refactor(api): gofmt motd.go

* refactor(api): update go comment
2019-03-05 16:05:15 +13:00
Anthony Lapenna
e2a17480af Merge branch 'develop' of github.com:portainer/portainer into develop 2019-03-04 13:48:01 +13:00
Anthony Lapenna
0670079566 feat(api): update ExtensionDefinitionsURL 2019-03-04 13:46:27 +13:00
Anthony Lapenna
5ca9501540 dep(api): update docker binary version to 18.09.3 (#2749) 2019-03-01 14:45:36 +13:00
Anthony Lapenna
415c1759d1 Merge branch 'oath-poc' into develop 2019-03-01 14:16:04 +13:00
Anthony Lapenna
db0091b46d feat(api): revert extension URLs to correct one 2019-03-01 13:58:55 +13:00
linquize
42529cc5ea feat(volumes): show volume creation date (#2745) 2019-03-01 11:59:11 +13:00
Anthony Lapenna
60fbfeba23 fix(oauth): fix settings displaying issue for custom OAuth configuration 2019-03-01 11:24:47 +13:00
Anthony Lapenna
f5091ce5fb fix(auth): fix invalid condition to display OAuth login button 2019-03-01 10:58:18 +13:00
Anthony Lapenna
58962de20e Merge branch 'develop' into oath-poc 2019-03-01 09:42:38 +13:00
Anthony Lapenna
1eb7e6bacc fix(auth): rollback changes introduced via #2591 (#2747) 2019-02-28 11:38:02 +13:00
Anthony Lapenna
130baddea0 fix(api): fix an issue when removing non local administrators 2019-02-25 18:54:21 +13:00
Tim van den Eijnden
9cbf1f34a7 feat(networks): prevent removal of predefined networks (#2697)
* fix(networks): disable removing predefined networks (#1838)

*  fix(networks): disable select all for predefined networks (#1838)

* fix(networks): do not allow delete in network-details & use constant (#1838)
2019-02-25 14:25:48 +13:00
linquize
c152d3f62e fix(stacks): update web editor to set tab key to insert spaces (#2735) 2019-02-25 14:19:53 +13:00
linquize
da44f14e07 fix(auth): prevent redirect parameter to use state portainer.auth (#2701) 2019-02-25 13:57:11 +13:00
Anthony Lapenna
49516e2c3f style(oauth): update Azure UI elements 2019-02-25 13:38:27 +13:00
Anthony Lapenna
9c4c782a90 style(container-creation): review auto remove element position 2019-02-25 13:09:09 +13:00
baron_l
7aa6a30614 feat(registry-manager): allow regular users to use the registry browse feature (#2664)
* feat(registries): registries accessibility to all authorized people and not only admins

* feat(registry): dockerhub settings for admin only

* feat(registry): remove registry config access for non admin users

* feat(api): use AuthenticatedAccess policy instead of RestrictedAccess for extensionList operation

* refactor(api): minor update to security package

* refactor(api): revert unexporting function changes

* refactor(api): apply gofmt
2019-02-25 13:02:49 +13:00
linquize
99e50370bd feat(container-creation): support auto remove option (docker run --rm) (#2684) 2019-02-25 09:48:31 +13:00
Anthony Lapenna
dc2a8cf1f4 feat(oauth): update OAuth configuration UX 2019-02-21 14:02:25 +13:00
Anthony Lapenna
b9ac3d4286 feat(oauth): fix the double refresh issue 2019-02-21 11:09:57 +13:00
Anthony Lapenna
6711e6c969 feat(oauth): update configuration override UX 2019-02-21 10:30:09 +13:00
Anthony Lapenna
4a5fa211a7 feat(account): display a warning message in the account view 2019-02-20 13:57:13 +13:00
Anthony Lapenna
d510d23408 feat(oauth): improve Azure OAuth support 2019-02-20 13:53:25 +13:00
Anthony Lapenna
ce9e009e22 feat(oauth): update UI/UX 2019-02-19 14:38:42 +13:00
Anthony Lapenna
9918c1260b feat(oauth): update authentication panel with OAuth provider details 2019-02-19 09:54:02 +13:00
Anthony Lapenna
e325ad10dd fix(oauth): fix an UX issue when updating microsoft oauth settings 2019-02-18 16:18:48 +13:00
Anthony Lapenna
73f20b5157 refactor(oauth): remove console log statement 2019-02-18 15:21:34 +13:00
Anthony Lapenna
b6f04c5e0d fix(oauth): fix missing scopes for microsoft provider 2019-02-18 15:21:06 +13:00
Anthony Lapenna
2ef8c0b33e fix(app): rewrite URLHelper to avoid an issue with minification 2019-02-18 15:08:54 +13:00
Anthony Lapenna
7643f8d08c feat(oauth): dev build supporting Oauth extension 2019-02-18 14:46:34 +13:00
Anthony Lapenna
086bad2956 Merge branch 'develop' into oath-poc 2019-02-18 09:58:51 +13:00
Anthony Lapenna
d5dfc889bb docs(README): remove gitter badges 2019-02-18 09:51:20 +13:00
Montana Flynn
ef926dce33 docs(README): update logo src (#2719)
The current logo src is 404: https://portainer.io/images/logo_alt.png

The repo already includes the logo: https://github.com/portainer/portainer/blob/develop/assets/images/logo_alt.png?raw=true
2019-02-18 09:49:34 +13:00
Anthony Lapenna
d768e72a21 feat(oauth): add support for default team 2019-02-17 19:01:42 +13:00
Anthony Lapenna
78e2aaf7d4 feat(oauth): update OAuth UX 2019-02-17 17:01:36 +13:00
Anthony Lapenna
17cf374c30 Merge branch 'develop' into oath-poc 2019-02-17 16:39:23 +13:00
Nathan Baum
165096bef0 refactor(api): fix a typo (#2712)
Just a trivial spelling error.
2019-02-15 09:12:53 +13:00
Anthony Lapenna
de76ba4e67 feat(oauth): update OAuth UX 2019-02-14 15:58:45 +13:00
linquize
b1e048e218 feat(build-system): prefix some dependencies with "semver:" (#2690)
This makes both npm and yarn to work
2019-02-14 12:13:48 +13:00
linquize
8f32d58fae fix(templates): redirect to home if endpoint not yet selected #2709 (#2710) 2019-02-14 12:08:46 +13:00
Anthony Lapenna
16226b1202 Merge branch 'oath-poc' of github.com:portainer/pportainer into oath-poc 2019-02-13 10:01:06 +13:00
baron_l
8f568c8699 style(oauth): oauth loading + oauth config rework 2019-02-08 16:07:16 +01:00
Anthony Lapenna
af34b99cd4 Merge branch 'develop' into oath-poc 2019-02-08 13:32:53 +13:00
baron_l
2755527d28 feat(oauth): default team for user on oauth settings 2019-02-07 19:32:02 +01:00
baron_l
4d8133f696 feat(oauth): spinner on code evaluation after sucessfull oauth 2019-02-07 15:07:10 +01:00
Anthony Lapenna
fdc11dbe3a feat(build-system): update build system (#2682) 2019-02-07 12:00:47 +13:00
Anthony Lapenna
508352f4ea Merge branch 'develop' into oath-poc 2019-02-04 09:19:12 +13:00
Daniel Cardoza
9b6b6e09ae fix(endpoints): correct agent stack download url (#2667)
* 2584 fix(endpoints): correct agent stack download url

The directions for installing the agent stack from the endpoints
view used an old url. Update to the new url.

* Drop the portainer- prefix for the download path and filename

Co-Authored-By: dang3r <danielpcardoza@gmail.com>
2019-02-04 09:06:07 +13:00
Anthony Lapenna
899cd5f279 fix(home): fix an issue when trying to connect to an Azure ACI endpoint (#2671) 2019-02-04 09:04:52 +13:00
Anthony Lapenna
2eec8b75d0 Merge tag '1.20.1' into develop
Release 1.20.1
2019-01-31 13:15:28 +13:00
Anthony Lapenna
048c74a0dc Merge branch 'release/1.20.1' 2019-01-31 13:15:23 +13:00
Anthony Lapenna
6b1c476b63 chore(version): bump version number 2019-01-31 13:15:18 +13:00
Anthony Lapenna
c5b5f80bea docs(README): update build badge 2019-01-31 12:02:12 +13:00
Anthony Lapenna
cea2c60b55 refactor(build-system): fix lint issues 2019-01-31 11:38:27 +13:00
Steven Kang
576f369152 feat(build-system): introduce Azure DevOps support (#2666) 2019-01-31 11:37:16 +13:00
Anthony Lapenna
fca4f619b5 fix(api): re-use previous password when ldap settings update use empty password (#2659) 2019-01-30 14:53:14 +13:00
Chaim Lev Ari
90281fd7f0 feat(oauth): add providers to providers-selector 2019-01-25 10:57:40 +02:00
Chaim Lev Ari
c1939f6070 feature(oauth): add provider selector 2019-01-25 10:46:17 +02:00
Chaim Lev Ari
50c604ee4c fix(auth): use the right function to oauth validate 2019-01-25 10:44:31 +02:00
Chaim Lev Ari
41ded64037 Revert "refactor(auth): extract oauth login mechanism to service"
This reverts commit 0a439b3893.
2019-01-25 10:37:23 +02:00
baron_l
801336336f fix(registry-manager): add repositories pagination support (#2641)
* fix(registry-management): add support for repositories list with multiple requests

* refactor(registry-management): change regex usage to a reusable interceptor function

* refactor(registry-management): change interceptor to transformResponse function
2019-01-24 13:38:36 +13:00
Anthony Lapenna
90a0998502 feat(templates): add sonatype nexus 3 template 2019-01-23 16:05:07 +13:00
Anthony Lapenna
1a4dff536d fix(container-creation): fix an issue with command parsing (#2642)
* fix(container-creation): fix an issue with command parsing

* refactor(container-creation): remove indentation update
2019-01-23 12:25:42 +13:00
Chaim Lev-Ari
f772cd31cb feat(auth): preserve url when redirected to login (#2591)
* feat(auth): preserve url when redirected to login

* feat(auth): add redirect also to unauthenticated flow

* style(app): remove style changes from files

* fix(app): remove reference to otpLogin

* style(auth): remove semicolon
2019-01-23 12:22:56 +13:00
Chaim Lev-Ari
8160fe4717 feat(app): redirect to home if no endpoint is set (#2601)
* refactor(stacks): set newstack state as a child state of stacks

* fix(docker): add check on docker states for endpoint

* refactor(app): remove redirect notification
2019-01-23 12:21:48 +13:00
Anthony Lapenna
86c60807cd feat(endpoint-creation): fix invalid link (#2644) 2019-01-23 12:18:18 +13:00
baron_l
c1f2d90997 fix(container-creation): fix missing capabilities on duplicate (#2635) 2019-01-23 09:28:44 +13:00
Chaim Lev Ari
3699b794eb feat(oauth): add providers selectors 2019-01-18 12:14:12 +02:00
Chaim Lev Ari
69252a8377 refactour(auth): move information body to each setting 2019-01-18 12:08:18 +02:00
Chaim Lev Ari
193e7eb3f8 refactor(oauth): remove separation of strings 2019-01-18 11:53:44 +02:00
Chaim Lev Ari
de5f6086d0 refactor(oauth): return parse content error 2019-01-18 11:51:41 +02:00
Chaim Lev Ari
46e8f10aea refactor(ouath): use oauth2 library to get token 2019-01-18 10:56:16 +02:00
Chaim Lev Ari
60040e90d0 refactor(oauth): move build url logic to service 2019-01-18 10:24:42 +02:00
Chaim Lev Ari
c5c06b307a refactor(oauth): rename authenticate function 2019-01-18 10:15:02 +02:00
Chaim Lev Ari
c28274667d refactor(oauth): use oauth2 to generate login url 2019-01-18 10:13:33 +02:00
Anthony Lapenna
54163e3b92 fix(extensions): fix an issue with extensions with expired licenses (#2628)
* fix(extensions): fix an issue with extensions with expired licenses

* fix(api): fix invalid log call

* fix(api): allow to re-enable an extension
2019-01-18 10:00:18 +13:00
Chaim Lev-Ari
62eb47b3cb fix(container-creation): revert container state if creation failed (#2565)
* fix(container): rename old container only if exist

* fix(container): remove new container only if created

* style(container): fix typo

Co-Authored-By: chiptus <chiptus@users.noreply.github.com>
2019-01-18 08:59:43 +13:00
Anthony Lapenna
808eb7d341 dep(bootstrap): update bootstrap version to 3.4.0 (#2632) 2019-01-18 08:51:12 +13:00
hiyao
a33eca4bbb fix(registry-manager): fix an issue when removing all tags of a repository (#2545)
* fix repository reload got error in remove tags

When I remove all tags, removeTags() will reload and do initView() again, but data.tags response null, that trigger data.tags.length got error.

* Revert "fix repository reload got error in remove tags"

This reverts commit 5d9b1778ef.

* fix(registry-management): change response repository tags type to array by force

* feat(registry-management): redirect to repositories page when no tag in the repository after delete tags
2019-01-18 08:01:47 +13:00
baron_l
50e77d2bf1 fix(network-details): displaying all subnets and gateways on network details (#2629) 2019-01-17 11:39:15 +13:00
DevHugo
50a3b08209 feat(app): add driver name in the volume selector for container/service creation (#2534)
* Feat(containers): add driver name in the volume selector

* Feat(services): add driver name in the volume selector
2019-01-17 11:28:40 +13:00
Chaim Lev Ari
0a439b3893 refactor(auth): extract oauth login mechanism to service 2019-01-16 18:57:15 +02:00
Chaim Lev Ari
0d4e1d00f0 refactor(login): move oauth button to right 2019-01-16 18:00:01 +02:00
Chaim Lev Ari
b09f491f62 style(auth): remove comments and change error 2019-01-16 17:53:10 +02:00
Chaim Lev Ari
dc067b3308 refactor(http): remove old oauth handler 2019-01-16 17:41:56 +02:00
Chaim Lev Ari
b121f975fa refactor(settings): remove duplicate settings 2019-01-16 17:38:07 +02:00
Chaim Lev Ari
3f44925d7e fix(auth): fix typo - missing function 2019-01-16 17:37:50 +02:00
Chaim Lev Ari
80d570861d refactor(auth): move public settings into view model 2019-01-16 17:34:12 +02:00
Chaim Lev Ari
317bd53e43 Merge branch 'oath-poc' of github.com:portainer/pportainer into oath-poc 2019-01-16 17:26:29 +02:00
Chaim Lev Ari
24f066716b refactor(auth): expose only the login url 2019-01-16 17:25:16 +02:00
Chaim Lev Ari
4cbde7bb0d refactor(auth): move oauth handler under auth 2019-01-16 17:24:58 +02:00
Chaim Lev Ari
f6bdc5c2b3 refactor(auth): move oauth handler code to its own file 2019-01-16 17:01:38 +02:00
Anthony Lapenna
c650fe56c2 fix(auth): fix typos
Co-Authored-By: chiptus <chiptus@users.noreply.github.com>
2019-01-16 16:53:24 +02:00
Anthony Lapenna
fc8938e871 fix(auth): change oauth error type
Co-Authored-By: chiptus <chiptus@users.noreply.github.com>
2019-01-16 16:50:19 +02:00
Anthony Lapenna
44b7e0fdca fix(auth): change error type
Co-Authored-By: chiptus <chiptus@users.noreply.github.com>
2019-01-16 16:49:33 +02:00
Chaim Lev-Ari
fe63b4a156 fix(container-creation): populate logger config from existing container (#2602)
* refactor(container): change map function to lodash

* style(container): add semicolon
2019-01-16 13:34:28 +13:00
Chaim Lev-Ari
42365a52b1 feat(container-details): change network identifier to name (#2623) 2019-01-16 08:05:55 +13:00
Mark Stansberry
d6aafceba8 docs(api): update swagger definitions 2019-01-16 08:04:47 +13:00
baron_l
c7983d8993 fix(app): remove endpoint status update on 502/503 http return
* refactor(app): removing unused dep and function
2019-01-16 07:58:35 +13:00
Anthony Lapenna
34667bd3b3 fix(network-creation): force overlay network creation on manager node (#2622)
* fix(network-creation): force overlay network creation on manager node

* fix(app): fix function override

* fix(app): use portainerAgentManagerOperation in interceptor
2019-01-15 12:10:29 +13:00
Anthony Lapenna
3a3577754e fix(home): only display group name if available (#2621) 2019-01-15 08:52:26 +13:00
Anthony Lapenna
bed49c37e4 fix(teams): remove name sanitization when creating a team (#2619) 2019-01-14 17:27:55 +13:00
Anthony Lapenna
dedc02cc8d docs(api): fix invalid example value for AutoCreateUsers property (#2618) 2019-01-14 16:50:53 +13:00
Chaim Lev Ari
17ac3e5ed1 refactor(oauth): move enpoint constant to extension 2019-01-03 13:36:17 +02:00
Chaim Lev Ari
25620c5008 refactor(auth): refactor get url params 2019-01-02 20:49:25 +02:00
Chaim Lev Ari
9bebe9dee7 refactor(auth): move user setter into function 2019-01-02 20:01:23 +02:00
Chaim Lev Ari
81e3ace232 fix(auth): fix oauh enabled function 2019-01-02 20:01:06 +02:00
Chaim Lev Ari
15b6941872 refactor(oauth): move oauth rest service to extension 2019-01-02 20:00:41 +02:00
Chaim Lev Ari
7aaa9e58e9 refactor(auth): move oauth info to component 2019-01-02 16:24:10 +02:00
Chaim Lev Ari
515daf6dba refactor(auth): exprt oauth settings into extension 2019-01-02 16:21:36 +02:00
Chaim Lev Ari
0a1643bbcf style(auth): remove added spaces 2019-01-02 16:01:10 +02:00
Chaim Lev Ari
38f24683a6 refactor(auth): remove empty $q.deffered 2019-01-02 15:59:38 +02:00
Chaim Lev Ari
7494101a4d refactor(auth): refactor auth controller 2019-01-02 15:56:08 +02:00
Chaim Lev Ari
996319d299 feat(auth): don't clear client secret on update 2018-12-30 18:39:16 +02:00
Chaim Lev Ari
2ee6f2780b refactor(oauth): add debug logs 2018-12-30 18:25:30 +02:00
Chaim Lev Ari
241a701eca feat(oauth): merge pr from https://github.com/portainer/portainer/pull/2515 2018-12-30 18:02:22 +02:00
Anthony Lapenna
463b379876 docs(README): remove broken badges and links 2018-12-27 09:03:13 +01:00
Chaim Lev-Ari
f2cd33e831 feat(container-creation): call stopAndRename after pullImage (#2564)
* refactor(container): remove bind of function
2018-12-21 00:37:35 +09:00
Anthony Lapenna
6b05a35881 fix(api): set a default value for potentially empty snapshot interval (#2543) 2018-12-12 21:16:44 +13:00
Anthony Lapenna
6648c0bbe7 Merge tag '1.20.0' into develop
Release 1.20.0
2018-12-12 17:03:36 +13:00
Anthony Lapenna
dbda568481 Merge branch 'release/1.20.0' 2018-12-12 17:03:31 +13:00
Anthony Lapenna
189d131105 chore(version): bump version number 2018-12-12 17:03:25 +13:00
Anthony Lapenna
1384359baf fix(api): fix snapshot hanging 2018-12-12 17:00:15 +13:00
Anthony Lapenna
6c26cf1f39 style(support): update support pricing 2018-12-12 16:03:20 +13:00
Anthony Lapenna
8780b0a901 feat(api): update extension path on Windows arch 2018-12-12 14:19:58 +13:00
Anthony Lapenna
f5ada3085e fix(api): fix an issue with schedule update 2018-12-12 14:11:40 +13:00
Anthony Lapenna
acc5218c16 fix(api): fix snapshot schedule loading 2018-12-12 12:31:55 +13:00
Anthony Lapenna
8a186b4024 feat(api): update DigitalSignatureService (#2539) 2018-12-12 11:19:23 +13:00
Anthony Lapenna
5c2e714e69 style(extensions): minor update to extension UX/UI (#2538)
* style(extensions): update extension icons

* style(extensions): style update

* feat(extensions): update extension UX

* style(extensions): update extension style

* style(extension-details): update screenshot default size

* style(extensions): update overview diagram image

* refactor(support): fix support URLs
2018-12-12 10:28:21 +13:00
Anthony Lapenna
f222b3cb1a feat(templates): update logo URLs 2018-12-12 09:47:28 +13:00
Anthony Lapenna
e440ba53cb feat(api): migrate template data logo URLs (#2537) 2018-12-12 09:46:05 +13:00
Anthony Lapenna
17d85fdc15 fix(registry-creation): fix registry creation request being fired twice on firefox 2018-12-10 21:56:07 +13:00
Anthony Lapenna
42a357f863 fix(support-details): fix a js error 2018-12-09 17:03:26 +13:00
Anthony Lapenna
6fd5ddc802 feat(extensions): introduce extension support (#2527)
* wip

* wip: missing repository & tags removal

* feat(registry): private registry management

* style(plugin-details): update view

* wip

* wip

* wip

* feat(plugins): add license info

* feat(plugins): browse feature preview

* feat(registry-configure): add the ability to configure registry management

* style(app): update text in app

* feat(plugins): add plugin version number

* feat(plugins): wip plugin upgrade process

* feat(plugins): wip plugin upgrade

* feat(plugins): add the ability to update a plugin

* feat(plugins): init plugins at startup time

* feat(plugins): add the ability to remove a plugin

* feat(plugins): update to latest plugin definitions

* feat(plugins): introduce plugin-tooltip component

* refactor(app): relocate plugin files to app/plugins

* feat(plugins): introduce PluginDefinitionsURL constant

* feat(plugins): update the flags used by the plugins

* feat(plugins): wip

* feat(plugins): display a label when a plugin has expired

* wip

* feat(registry-creation): update registry creation logic

* refactor(registry-creation): change name/ids for inputs

* feat(api): pass registry type to management configuration

* feat(api): unstrip /v2 in regsitry proxy

* docs(api): add TODO

* feat(store): mockup-1

* feat(store): mockup 2

* feat(store): mockup 2

* feat(store): update mockup-2

* feat(app): add unauthenticated event check

* update gruntfile

* style(support): update support views

* style(support): update product views

* refactor(extensions): refactor plugins to extensions

* feat(extensions): add a deal property

* feat(extensions): introduce ExtensionManager

* style(extensions): update extension details style

* feat(extensions): display license/company when enabling extension

* feat(extensions): update extensions views

* feat(extensions): use ProductId defined in extension schema

* style(app): remove padding left for form section title elements

* style(support): use per host model

* refactor(extensions): multiple refactors related to extensions mecanism

* feat(extensions): update tls file path for registry extension

* feat(extensions): update registry management configuration

* feat(extensions): send license in header to extension proxy

* fix(proxy): fix invalid default loopback address

* feat(extensions): add header X-RegistryManagement-ForceNew for specific operations

* feat(extensions): add the ability to display screenshots

* feat(extensions): center screenshots

* style(extensions): tune style

* feat(extensions-details): open full screen image on click (#2517)

* feat(extension-details): show magnifying glass on images

* feat(extensions): support extension logo

* feat(extensions): update support logos

* refactor(lint): fix lint issues
2018-12-09 16:49:27 +13:00
Anthony Lapenna
f5dc663879 fix(build-system): revert appveyor integration
* Revert "fix(build-system): fix local build system after appveyor introduction (#2528)"

This reverts commit 79c24ced96.

* Revert "feat(build-system): add support for AppVeyor CI (#2449)"

This reverts commit 65979709e9.
2018-12-09 16:32:12 +13:00
Anthony Lapenna
79c24ced96 fix(build-system): fix local build system after appveyor introduction (#2528) 2018-12-09 16:08:36 +13:00
Steven Kang
65979709e9 feat(build-system): add support for AppVeyor CI (#2449) 2018-12-07 16:19:58 +13:00
Olli Janatuinen
2541f4daea feat(UX): persist search criterias (#2425)
* feat(ui): persist search criteria

* fix(ui): trying make templates search working correctly

* fix(ui): corrected search persistance on home and templates

* fix(ui): corrected javascript errors
2018-12-07 08:54:34 +13:00
baron_l
1a94158f77 * feat(UX): schedule creation UX overhaul (#2485)
* feat(api): add a new Recurring property on Schedule

* feat(schedules): date to cron convert + recurring flag

* feat(schedules): update angularjs-datetime-picker from v1 to v2

* chore(app): use minified dependency for angularjs-datetime-picker

* chore(vendor): rollback version of angularjs-datetime-picker

* * feat(ux): replace datepicker for schedule creation/details

* feat(container-stats): add refresh rate of 1 and 3 seconds (#2493)

* fix(templates): set var to default value if no value selected (#2323)

* fix(templates): set preset to true iff var type is preset

* fix(templates): add env var value when changing type

* feat(security): shutdown instance after 5minutes if no admin account created (#2500)

* feat(security): skip admin check if --no-auth

* fix(security): change error message

* fix(vendor): use datepicker minified version

* feat(schedule-creation): replace angular-datetime-picker

* feat(schedule): parse cron to datetime

* fix(schedule): fix zero based months
2018-12-07 08:53:23 +13:00
Anthony Lapenna
9e1800e2ec style(settings): update host management tooltip 2018-12-06 14:01:49 +13:00
baron_l
a9b107dbb5 feat(app): add the capability to enable/disable host management features (#2472)
* feat(settings): add the capability to enable/disable the host management features

* feat(settings): remove the validation of EnableHostManagementFeatures in frontend

* feat(api): disable schedules API when HostManagementFeatures is false + DB migration

* style(settings): update host management settings tooltip

* refacot(schedules): update DBVersion to 15
2018-12-06 11:36:25 +13:00
Chaim Lev-Ari
101bb41587 feat(security): shutdown instance after 5minutes if no admin account created (#2500)
* feat(security): skip admin check if --no-auth

* fix(security): change error message
2018-12-04 16:50:41 +13:00
Chaim Lev-Ari
acce5e0023 fix(templates): set var to default value if no value selected (#2323)
* fix(templates): set preset to true iff var type is preset

* 

* fix(templates): add env var value when changing type
2018-12-04 09:52:59 +13:00
linquize
5fa4403d20 feat(container-stats): add refresh rate of 1 and 3 seconds (#2493) 2018-12-03 21:49:02 +13:00
Anthony Lapenna
dc9a878f4b chore(docker): update docker binary version to 18.09.0 (#2510) 2018-12-03 12:10:55 +13:00
baron_l
969f70edeb fix(image-upload): uploading a tar with multiple images wont display an error anymore (#2503) 2018-11-29 07:00:58 +13:00
baron_l
c778e79004 fix(container-console): close the console when selected shell does not exist inside the container (#2502) 2018-11-29 06:57:36 +13:00
Chaim Lev-Ari
34b886d690 chore(build-system): add start and start:server scripts (#2495) 2018-11-27 10:05:13 +13:00
Andreas Roussos
b809177147 feat(dashboard): use plural form only when required
* fix(endpoint-item): use plural form only when required

* refactor(endpoint-item): use clearer patterns

* refactor(dashboard): use clearer patterns
2018-11-25 09:46:13 +13:00
baron_l
52788029ed feat(container-details): add visual feedback when creating image from container (#2487) 2018-11-24 11:11:58 +13:00
Anthony Lapenna
d510bbbcfd feat(api): filter LDAP password from settings response (#2488) 2018-11-24 08:40:56 +13:00
Olli Janatuinen
17d63ae3ca chore(dependencies): updated xterm to 3.8.0 version (#2452) 2018-11-23 22:00:30 +13:00
baron_l
5e49f934b9 fix(containers-stats): accessing a down container stats wont display a js error anymore (#2484) 2018-11-23 21:44:34 +13:00
Anthony Lapenna
d03fd5805a feat(api): support AGENT_SECRET environment variable (#2486) 2018-11-23 11:46:51 +13:00
baron_l
fe8dfee69a feat(home): display each endpoint URL (#2471) 2018-11-19 19:07:38 +13:00
baron_l
488dc5f9db fix(network-creation): macvlan availability for standalone endpoints (#2441) 2018-11-16 13:26:56 +13:00
Anthony Lapenna
0ef25a4cbd fix(schedules): add schedule name validation and remove endpoint name prefix (#2470) 2018-11-14 16:10:49 +13:00
Anthony Lapenna
94d3d7bde2 feat(motd): relocate motd file URL and always return 200 (#2466) 2018-11-14 12:20:33 +13:00
Christer Warén
40e0c3879c style(dashboard): change blocklist-item border color (#2465)
Changing blocklist-item border color to more confortable color that makes UI look more consistence
2018-11-14 10:01:36 +13:00
baron_l
d455ab3fc7 feat(endpoints): enhance offline browsing (#2454)
* feat(api): rewrite error response when trying to query a down endpoint

* feat(interceptors): adding custom backend return code on offline fastfail
2018-11-13 16:08:12 +13:00
Anthony Lapenna
0825d05546 feat(endpoints): improve offline banner UX (#2462)
* feat(endpoints): add the last snapshot timestamp in offline banner

* feat(endpoints): add the ability to refresh a snapshot in the offline banner
2018-11-13 16:02:49 +13:00
Anthony Lapenna
cf370f6a4c refactor(endpoints): remove time.Sleep call 2018-11-13 15:19:29 +13:00
Anthony Lapenna
381ab81fdd fix(endpoints): ensure endpoint is up to date after snapshot (#2460)
* feat(snapshots): fix a potential concurrency issue with endpoint snapshots

* fix(endpoints): ensure endpoint is up to date after snapshot
2018-11-13 15:18:38 +13:00
Anthony Lapenna
64c29f7402 feat(schedules): add the ability to list tasks from snapshots (#2458)
* feat(schedules): add the ability to list tasks from snapshots

* feat(schedules): update schedules

* refactor(schedules): fix linting issue
2018-11-13 14:39:26 +13:00
Anthony Lapenna
a2d9f591a7 feat(schedules): add retry policy to script schedules (#2445) 2018-11-09 15:22:08 +13:00
Anthony Lapenna
e7ab057c81 feat(sidebar): add a new Scheduler top entry 2018-11-08 14:09:21 +13:00
Yassir Hannoun
309620545c fix(container-stat): fix cpu/mem charts on Windows containers
* Fixing the CPU and Memory charts on Windows containers

* Fixing the CPU and Memory charts on Windows containers
2018-11-08 13:31:33 +13:00
Dmitriy Larionov
55b50c2a49 feat(container-creation): allow escaped quotes in command field (#2419) 2018-11-08 09:53:19 +13:00
Anthony Lapenna
807c830db0 feat(schedules): add the ability to update a schedule script (#2438) 2018-11-07 17:19:10 +13:00
Anthony Lapenna
695c28d4f8 fix(host): fix a typo in job history clear notification 2018-11-07 16:06:27 +13:00
Anthony Lapenna
4740375ba5 feat(schedules): add schedules UI (#2414)
* feat(schedules): add schedules UI mockups

* feat(schedules): update controller pattern

* feat(schedules): leverages API

* feat(schedules): add the ability create/edit a script execution job schedule

* feat(schedules): add form validation and details about cron expression
2018-11-07 11:59:21 +13:00
Anthony Lapenna
7d32a6619d feat(api): add created property for schedules (#2435) 2018-11-07 09:22:30 +13:00
Anthony Lapenna
110fcc46a6 feat(api): revamp scheduling to introduce system schedules (#2433)
* feat(api): revamp scheduling to introduce system schedules

* fix(api): fix linting issues

* fix(api): fix lint issues

* refactor(api): fix lint issues
2018-11-06 22:49:48 +13:00
Chaim Lev-Ari
dbbea0a20f feat(schedules): add the schedule API
* feat(jobs): add job service interface

* feat(jobs): create job execution api

* style(jobs): remove comment

* feat(jobs): add bindings

* feat(jobs): validate payload different cases

* refactor(jobs): rename endpointJob method

* refactor(jobs): return original error

* feat(jobs): pull image before creating container

* feat(jobs): run jobs with sh

* style(jobs): remove comment

* refactor(jobs): change error names

* feat(jobs): sync pull image

* fix(jobs): close image reader after error check

* style(jobs): remove comment and add docs

* refactor(jobs): inline script command

* fix(jobs): handle pul image error

* refactor(jobs): handle image pull output

* fix(docker): set http client timeout to 100s

* feat(api): create schedule type

* feat(agent): add basic schedule api

* feat(schedules): add schedule service in bolt

* feat(schedule): add schedule service to handler

* feat(schedule): add and list schedules from db

* feat(agent): get schedule from db

* feat(schedule): update schedule in db

* feat(agent): delete schedule

* fix(bolt): remove sync method from scheduleService

* feat(schedules): save/delete script in fs

* feat(schedules): schedules cron service implementation

* feat(schedule): integrate handler with cron

* feat(schedules): schedules API overhaul

* refactor(project): remove .idea folder

* fix(schedules): fix script task execute call

* refactor(schedules): refactor/fix golint issues

* refactor(schedules): update SnapshotTask documentation

* refactor(schedules): validate image name in ScheduleCreate operation
2018-11-06 09:58:15 +13:00
Anthony Lapenna
e94d6ad6b2 docs(swagger): update EndpointCreate operation 2018-11-01 07:32:41 +13:00
Jan Jansen
78bf374548 feat(ux): normalize quick actions buttons (#2389)
* feat(ux): normalize quick actions buttons

Fixes #2013

* fix(ux): fix wrong naming of variable
2018-10-31 15:50:38 +13:00
pc
8df64031e8 feat(log-viewer): change line count default to 100 and add a since parameter (#2377)
* chore(log-viewer): add the ability to use`since` parameter #1942

https://github.com/portainer/portainer/issues/1942#issuecomment-430246378

* chore(log-viewer): change lineCount to 100 #1942

https://github.com/portainer/portainer/issues/1942#issuecomment-430246378

* fix(log-viewer): js syntax typo for `;` and `'`

forget to lint the code, reported by codeclimate

* fix(log-viewer): use mementjs to format timestamp

1. use moment lib instead of define a function in filter.js(not the right place for this function, removed)
2. set sinceTimestamp init value to `24 hours ago`, as we just need to focus on the relative latest logs after the log-viewer loading, not all the logs(to speedup the process)
3. use moment().unix() to convert the `sinceTimestamp`  to local unix timestamp(not utc)

* chore(log-viewer): add the ability to select the datetime for `since`

* chore(log-viewer): add the ability to fetch logs from specific time
2018-10-29 17:49:35 +13:00
baron_l
a61654a35d feat(endpoints): add the ability to browse offline endpoints (#2253)
* feat(back): saved data in snapshot

* feat(endpoints): adding interceptors to retrieve saved data on offline endpoints

* feat(endpoints): offline dashboard working - need tests on offline views

* refactor(endpoints): interceptors cleaning and saving/loading offline endpoints data in/from localstorage

* feat(endpoints): browsing offline endpoints

* feat(endpoints): removing all the link in offline mode - sidebar not working when switching between off and on modes w/ stateManager logic

* feat(endpoints): endpoint status detection in real time

* fix(endpoints): offline swarm endpoint are not accessible anymore

* fix(endpoints): refactor message + disable offline browsing for an endpoint when no snapshot is available for it

* fix(endpoints): adding timeout and enabling loading bar for offline requests

* fix(endpoints): trying to access a down endpoint wont remove sidebar items if it fails

* feat(endpoints): disable checkboxes on offline views for offline mode

* feat(endpoints): updating endpoint status when detecting a change

* refactor(host): moved offline status panel from engine view to new host view

* fix(endpoints): missing endpoint update on ping from home view

* fix(api): rework EndpointUpdate operation

* refactor(offline): moved endpoint status to EndpointProvider and refactor the status-changed detection

* fix(offline): moved status detection to callback on views -> prevent displaying the offline message when endpoint is back online on view change

* fix(offline): offline message is now displayed online when browsing an offline endpoint

* fix(offline): sidebar updates correctly on endpoint status change

* fix(offline): offline panel not displayed and hidden on online mode

* refactor(offline): rework of OfflineMode management

* refactor(offline): extract information-panel for offlineMode into a component

* refactor(offline): remove redundant binding of informationPanel + endpointStatusInterceptor patter as service

* refactor(interceptors): moved interceptors pattern to service pattern

* feat(stacks): prevent inspection of a stack in offline mode

* feat(host): hide devices/disk panels in offline mode

* feat(host): disable browse action in offline mode

* refactor(home): remove comments
2018-10-28 22:27:06 +13:00
baron_l
354fda31f1 feat(jobs): add the ability to run a job on a target endpoint #2374
* feat(jobs): adding the ability to run scripts on endpoints

fix(job): click on containerId in JobsDatatable redirects to container's logs
refactor(job): remove the jobs datatable settings + texts changes on JobCreation view
fix(jobs): jobs payloads are now following API rules and case
feat(jobs): adding the capability to run scripts on hosts

* feat(jobs): adding the ability to purge jobs containers

* refactor(job): apply review changes

* feat(job-creation): store image name in local storage

* feat(host): disable job exec link in non-agent Swarm setup

* feat(host): only display execute job in agent setups or standalone

* feat(job): job execution overhaul

* docs(swagger): update EndpointJob documentation
2018-10-28 19:06:50 +13:00
Mark Stansberry
6ab510e5cb docs(api): update swagger related files to support swagger-codegen (#2404)
* Linting updates to api/swagger.yaml

* Security updates to api/swagger.yml

* Add api/swagger_config.json for swagger-codegen

* Add swagger_config.json packageVersion to match swagger.yml
2018-10-28 16:05:54 +13:00
Damian Czaja
7e6c647e93 feat(container-creation): add the ability to override the logging driver (#2384) 2018-10-28 16:00:56 +13:00
Yassir Hannoun
07c1e1bc3e feat(container-stats): display cache in memory usage chart (#2383) 2018-10-28 15:45:02 +13:00
Ricardo Cardona Ramirez
fe6ca042f3 feat(ux): Alphabetically sort configs and secrets in service details/creation (#2396)
* fix(sorting): Alphabetically sort configs in service details select box
* fix(sorting): Alphabetically sort configs and secrets  for service creation
2018-10-28 15:39:09 +13:00
Chaim Lev-Ari
9813099aa4 feat(app): toggle features based on agent API version (#2378)
* feat(agent): get agent's version from ping

* feat(agent): add version to api url

* feat(agent): query agent with api version

* feat(agent): rename agent api version name on state

* feat(agent): disable feature based on agent's api version

* style(agent): rename ping rest service + remove whitespaces

* style(state): remove whitespace

* style(agent): add whitespace

* fix(agent): remove check for error status 403

* refactor(agent): rename ping file name

* refactor(agent): move old services to v1 folder

* refactor(agent): turn ping service to usual pattern

* refactor(agent): change version to a global variable

* refactor(agent): move ping to version2

* refactor(agent): restore ping to use root ping

* fix(volumes): add volumeID to browse api path

* feat(volume): add upload button to volume browser
2018-10-26 16:16:29 +13:00
Yassir Hannoun
cca378b2e8 docs(README): fix semaphore badge 2018-10-24 08:55:30 +13:00
Anthony Lapenna
b5dfaff292 refactor(app): refactor unauthenticated state management (#2393)
* refactor(app): refactor Authentication service

* refactor(app): refactor unauthenticated state management
2018-10-23 17:28:59 +13:00
Anthony Lapenna
4f9a8180f9 docs(swagger): document the endpoint job execution (#2392) 2018-10-23 11:59:43 +13:00
Anthony Lapenna
14d2bf4ebb refactor(api): fix typo (#2391)
* refactor(api): fix typo

* refactor(api): remove newline
2018-10-23 10:07:39 +13:00
Chaim Lev-Ari
65291c68e9 feat(jobs): add the job execution API
* feat(jobs): add job service interface

* feat(jobs): create job execution api

* style(jobs): remove comment

* feat(jobs): add bindings

* feat(jobs): validate payload different cases

* refactor(jobs): rename endpointJob method

* refactor(jobs): return original error

* feat(jobs): pull image before creating container

* feat(jobs): run jobs with sh

* style(jobs): remove comment

* refactor(jobs): change error names

* feat(jobs): sync pull image

* fix(jobs): close image reader after error check

* style(jobs): remove comment and add docs

* refactor(jobs): inline script command

* fix(jobs): handle pul image error

* refactor(jobs): handle image pull output

* fix(docker): set http client timeout to 100s

* fix(client): remove timeout from http client
2018-10-23 10:03:30 +13:00
Yassir Hannoun
719299d75b fix(container-stat) : exclude cache from the Memory Usage chart to avoid misinterpret… (#2371) 2018-10-18 10:00:45 +13:00
Jan Jansen
d6ba46ed7f feat(ux): Redirect from init/admin to home when admin already exists (#2340)
Fixes #1853
2018-10-13 19:29:44 +13:00
Chaim Lev-Ari
c5aecfe6f3 feat(host): Add host file browser with upload/download files (#2337)
* feat(agent): add new host page

* feat(agent): convert volume-browser to files-datatable

* fix(agent): browse folders in file-datatable

* feat(engine-details): replace engine view with host view

* feat(engine-details): remove old panels

* feat(engine-details): add basic engine-details-panel component

* feat(engine-details): pass details to the different components

* feat(engine-details): replace host-view with host-overview

* feat(engine-details): add commaseperated filter

* feat(engine-details): add host-view container component

* feat(engine-details): add host-details component

* feat(engine-details): build host details object

* feat(engine-details): format engine version

* feat(engine-details): get details for one node

* feat(engine-details): pass is-agent from view

* feat(engine-details): replace old node view with a new component

* feat(engine-details): add swarm-node-details component

* feat(engine-details): remove isSwarm binding

* feat(engine-details): remove node-details and include in parent

* feat(engine-details): add labels-table component

* feat(engine-details): add update node service

* feat(engine-details): add update label functionality

* style(engine-details): remove whitespaces

* feat(engine-details): remove old node page

* feat(engine-details): pass is agent to host details

* feat(host-details): hide missing info

* feat(host-details): update node availability

* style(host-details): remove obsolete event object

* feat(host-details): fix labels not sending

* feat(host-details): remove flags for hiding data

* feat(host-details): create mock call to server for agent host info

* style(host-details): fix spelling mistake in filter's name

* feat(host-details): get info from agent

* feat(host-details): hide engine labels when empty

* feat(node-details): move labels table and save button

* feat(host-info): add different urls for refresh

* feat(host-details): show disk/devices info for agent

* feat(host-view): add loading indicator to devices-panel

* feat(host-details): add loading indicator to disks panel

* feat(agent): fix browse volume

* feat(agent): browse files

* feat(agent): enable rename

* feat(agent): download file

* fix(agent): download file from root

* feat(agent): delete file

* style(agent): remove whitespaces

* fix(agent): fix link on node browser

* feat(agent): basic file uploader

* feat(agent): add basic file upload

* fix(volume-browser): move volume id to query params

* feat(node-browser): moved uploader into browser

* feat(node-browser): add upload spinner

* feat(agent): browse files relative to root

* feat(agent): browse standalone agent

* feat(agent): move browse button from header

* fix(agent): fix url of browser view

* fix(agent): fix breadcrumb on title of host-browser

* feat(agent): fix url on node-browser breadcrumb

* refactor(agent): remove unused controller

* refactor(docker): remove unused filter

* refactor(docker): remove unused controllers

* refactor(docker): remove isAgent binding
2018-10-12 11:32:17 +13:00
Anthony Lapenna
5341ad33af docs(swagger): update StackUpdateRequest model (#2360) 2018-10-11 13:09:51 +13:00
baron_l
e948d606f4 fix(container-creation): set a default runtime value (#2325)
* fix(containers): creating a container with default runtime let the docker daemon assume the correct value

* refactor(containers): implementation simplification of default runtime value
2018-10-09 09:28:26 +13:00
Chaim Lev-Ari
ca08b2fa2a feat(host): replace engine view with host view (#2255)
* feat(engine-details): remove old panels

* feat(engine-details): add basic engine-details-panel component

* feat(engine-details): pass details to the different components

* feat(engine-details): replace host-view with host-overview

* feat(engine-details): add commaseperated filter

* feat(engine-details): add host-view container component

* feat(engine-details): add host-details component

* feat(engine-details): build host details object

* feat(engine-details): format engine version

* feat(engine-details): get details for one node

* feat(engine-details): pass is-agent from view

* feat(engine-details): replace old node view with a new component

* feat(engine-details): add swarm-node-details component

* feat(engine-details): remove isSwarm binding

* feat(engine-details): remove node-details and include in parent

* feat(engine-details): add labels-table component

* feat(engine-details): add update node service

* feat(engine-details): add update label functionality

* style(engine-details): remove whitespaces

* feat(engine-details): remove old node page

* feat(engine-details): pass is agent to host details

* feat(host-details): hide missing info

* feat(host-details): update node availability

* style(host-details): remove obsolete event object

* feat(host-details): fix labels not sending

* feat(host-details): remove flags for hiding data

* feat(host-details): create mock call to server for agent host info

* style(host-details): fix spelling mistake in filter's name

* feat(host-details): get info from agent

* feat(host-details): hide engine labels when empty

* feat(node-details): move labels table and save button

* feat(host-info): add different urls for refresh

* feat(host-details): show disk/devices info for agent

* feat(host-view): add loading indicator to devices-panel

* feat(host-details): add loading indicator to disks panel

* feat(host-details): show devices/disks on standalone agent

* refactor(host-details): remove default value

* refactor(host-details): remove redundant commaSeperated filter

* refactor(host-details): remove unused functions

* style(host-details): remove whitespace
2018-10-08 11:44:08 +13:00
Chaim Lev-Ari
275fcf5587 fix(volume-browser): move volume id to query params (#2338) 2018-10-08 11:34:47 +13:00
Anthony Lapenna
3422662191 fix(app): fix invalid state name (#2330)
* fix(app): fix invalid state name

* fix(app): update ui-sref
2018-10-04 13:28:39 +13:00
Brian Kabiro
f6d9a4c7c1 feat(nodes): display node name when available (#2328)
- check if the name of a node is available, otherwise default to the Hostname
2018-10-04 12:07:31 +13:00
Ricardo Cardona Ramirez
575735a6f7 feat(ux): sort networks alphabetically in network selection dropdowns (#2326)
* Sort network lists
2018-10-04 12:04:38 +13:00
Brian Kabiro
b7c48fcbed feat(visualizer): sort tasks in alphabetical order on refresh (#2329)
- sort the tasks on each node in alphabetical order to make it easier to track what has changed
2018-10-04 11:57:07 +13:00
Tolik Litovsky
6e8a10d72f fix(api): remove x-frame-options header (#2322) 2018-10-03 14:18:03 +13:00
Chaim Lev-Ari
bad95987ec feat(backend): trigger startup snapshot job in a goroutine (#2309)
* feat(backend): wrap init enpoint with goroutine

* feat(backend): wrap job snapshot with goroutine

* feat(snapshots): reset changes for main and job_endpoint

* feat(snapshot): run first job.snapshot as a goroutine
2018-10-01 14:38:14 +13:00
Chaim Lev-Ari
9b4870d57e feat(stack-details): Add the ability to duplicate a stack (#2278)
* feat(stack-details): add duplicate-stack button

* feat(stack-details): add stack-duplication-form component

* feat(stack-details): add duplicate stack method on controller

* feat(stack-details): add duplicate stack method

* feat(stack-details): remove old duplication in progress flag

* feat(stack-details): combine migration and duplication forms

* feat(stack-details): pass new stack name to server

* feat(stack-details): add option to rename migrated stack

* feat(stack-details): disable both migrate/duplicate buttons

* feat(stack-details): disable migration button on same endpoint

* feat(stack-details): change duplicate icon

* style(stack-details): remove whitespaces and fix pattern

* feat(stack-details): add name to migration payload in swagger.yml

* style(stack-details): add semicolon

* bug(stack-details): toggle endpoints before and after duplication
2018-10-01 14:36:49 +13:00
Chaim Lev-Ari
6e262e6e89 feat(home): support search in multiple fields (name, group, tag, status) (#2285)
* feat(home): search multiple fields (group/tag)

* feat(home): change search from "OR" to "AND"

* feat(home): search only for a tag or a group

* feat(home): search by keywords in name,group,tag

* feat(home): support case insensitive search

* style(home): remove unused $filter

* feat(home): search state

* style(home): update search input placeholder
2018-10-01 09:06:58 +13:00
Chaim Lev-Ari
5be2684442 feat(home): add the ability to edit an endpoint (#2305)
* feat(home): add edit button

* feat(home): style edit button

* feat(home): make endpoint editable on admin only
2018-09-30 11:20:10 +13:00
Chaim Lev-Ari
226c45f035 fix(template-creation): fix an issue related to the network setting (#2312)
* bug(template): pass network name on creation

* bug(templates): choose network object on update

* fix(templates): set network only when available
2018-09-28 15:06:47 +12:00
Angele
92b15523f0 feat(containers): add container name in error notification
* containersDatable: add containers name if error on executeActionOnContainerList

* Update containersDatatableActionsController.js

* Update containersDatatableActionsController.js
2018-09-28 10:49:30 +12:00
Anthony Lapenna
f0f01c33bd feat(endpoint-creation): add requirement message for agent endpoint (#2303) 2018-09-26 18:59:50 +12:00
Lukas Joergensen
94b202fedc fix(authentication): escape LDAP filters (#2209) 2018-09-25 11:10:41 +12:00
Anthony Lapenna
d5dd362d53 feat(api): update client.Get with a new timeout parameter and default… (#2297)
* feat(api): update client.Get with a new timeout parameter and default to 5s

* fix(api): fix invalid type
2018-09-24 12:09:12 +12:00
Anthony Lapenna
c3d80a1b21 docs(project): update CONTRIBUTING.md 2018-09-19 11:40:06 +08:00
Anthony Lapenna
b192b098ca feat(build-system): update shippedDockerVersion to 18.06.1-ce (#2281) 2018-09-17 09:26:37 +08:00
Anthony Lapenna
22450bbdeb chore(build): update build script and add grunt yarn script (#2276) 2018-09-16 10:34:46 +08:00
Anthony Lapenna
313c8be997 chore(version): bump version number 2018-09-15 19:26:03 +08:00
Anthony Lapenna
885c61fb7b Merge tag '1.19.2' into develop
Release 1.19.2
2018-09-15 16:40:43 +08:00
1872 changed files with 131818 additions and 36363 deletions

13
.babelrc Normal file
View File

@@ -0,0 +1,13 @@
{
"plugins": ["lodash", "angularjs-annotate"],
"presets": [
[
"@babel/preset-env",
{
"modules": false,
"useBuiltIns": "entry",
"corejs": "2"
}
]
]
}

View File

@@ -1,61 +1,44 @@
version: "2"
checks:
argument-count:
enabled: true
config:
threshold: 4
enabled: false
complex-logic:
enabled: true
config:
threshold: 4
enabled: false
file-lines:
enabled: true
config:
threshold: 300
enabled: false
method-complexity:
enabled: false
method-count:
enabled: true
config:
threshold: 20
enabled: false
method-lines:
enabled: true
config:
threshold: 50
enabled: false
nested-control-flow:
enabled: true
config:
threshold: 4
enabled: false
return-statements:
enabled: false
similar-code:
enabled: true
config:
threshold: #language-specific defaults. overrides affect all languages.
enabled: false
identical-code:
enabled: true
config:
threshold: #language-specific defaults. overrides affect all languages.
enabled: false
plugins:
gofmt:
enabled: true
golint:
enabled: true
govet:
enabled: true
csslint:
enabled: true
duplication:
enabled: true
config:
languages:
javascript:
mass_threshold: 80
eslint:
enabled: true
channel: "eslint-5"
config:
config: .eslintrc.yml
fixme:
enabled: true
exclude_patterns:
- assets/
- build/
- dist/
- distribution/
- node_modules
- test/
- webpack/
- gruntfile.js
- webpack.config.js
- api/
- "!app/kubernetes/**"
- .github/
- .tmp/

3
.eslintignore Normal file
View File

@@ -0,0 +1,3 @@
node_modules/
dist/
test/

View File

@@ -1,287 +1,28 @@
env:
browser: true
jquery: true
node: true
es6: true
globals:
angular: true
# globals:
# angular: true
# $: true
# _: true
# moment: true
# filesize: true
# splitargs: true
extends:
- 'eslint:recommended'
- prettier
plugins:
- import
parserOptions:
ecmaVersion: 2018
sourceType: module
ecmaFeatures:
modules: true
# http://eslint.org/docs/rules/
rules:
# Possible Errors
no-await-in-loop: off
no-cond-assign: error
no-console: off
no-constant-condition: error
no-control-regex: error
no-debugger: error
no-dupe-args: error
no-dupe-keys: error
no-duplicate-case: error
no-empty-character-class: error
no-empty: error
no-ex-assign: error
no-extra-boolean-cast: error
no-extra-parens: off
no-extra-semi: error
no-func-assign: error
no-inner-declarations:
- error
- functions
no-invalid-regexp: error
no-irregular-whitespace: error
no-negated-in-lhs: error
no-obj-calls: error
no-prototype-builtins: off
no-regex-spaces: error
no-sparse-arrays: error
no-template-curly-in-string: off
no-unexpected-multiline: error
no-unreachable: error
no-unsafe-finally: off
no-unsafe-negation: off
use-isnan: error
valid-jsdoc: off
valid-typeof: error
# Best Practices
accessor-pairs: error
array-callback-return: off
block-scoped-var: off
class-methods-use-this: off
complexity:
- error
- 6
consistent-return: off
curly: off
default-case: off
dot-location: off
dot-notation: off
eqeqeq: error
guard-for-in: error
no-alert: error
no-caller: error
no-case-declarations: error
no-div-regex: error
no-else-return: off
no-empty-function: off
no-empty-pattern: error
no-eq-null: error
no-eval: error
no-extend-native: error
no-extra-bind: error
no-extra-label: off
no-fallthrough: error
no-floating-decimal: off
no-global-assign: off
no-implicit-coercion: off
no-implied-eval: error
no-invalid-this: off
no-iterator: error
no-labels:
- error
- allowLoop: true
allowSwitch: true
no-lone-blocks: error
no-loop-func: error
no-magic-number: off
no-multi-spaces: off
no-multi-str: off
no-native-reassign: error
no-new-func: error
no-new-wrappers: error
no-new: error
no-octal-escape: error
no-octal: error
no-param-reassign: off
no-proto: error
no-redeclare: error
no-restricted-properties: off
no-return-assign: error
no-return-await: off
no-script-url: error
no-self-assign: off
no-self-compare: error
no-sequences: off
no-throw-literal: off
no-unmodified-loop-condition: off
no-unused-expressions: error
no-unused-labels: off
no-useless-call: error
no-useless-concat: error
no-control-regex: off
no-empty: warn
no-empty-function: warn
no-useless-escape: off
no-useless-return: off
no-void: error
no-warning-comments: off
no-with: error
prefer-promise-reject-errors: off
radix: error
require-await: off
vars-on-top: off
wrap-iife: error
yoda: off
# Strict
strict: off
# Variables
init-declarations: off
no-catch-shadow: error
no-delete-var: error
no-label-var: error
no-restricted-globals: off
no-shadow-restricted-names: error
no-shadow: off
no-undef-init: error
no-undef: off
no-undefined: off
no-unused-vars:
- warn
-
vars: local
no-use-before-define: off
# Node.js and CommonJS
callback-return: error
global-require: error
handle-callback-err: error
no-mixed-requires: off
no-new-require: off
no-path-concat: error
no-process-env: off
no-process-exit: error
no-restricted-modules: off
no-sync: off
# Stylistic Issues
array-bracket-spacing: off
block-spacing: off
brace-style: off
camelcase: off
capitalized-comments: off
comma-dangle:
- error
- never
comma-spacing: off
comma-style: off
computed-property-spacing: off
consistent-this: off
eol-last: off
func-call-spacing: off
func-name-matching: off
func-names: off
func-style: off
id-length: off
id-match: off
indent: off
jsx-quotes: off
key-spacing: off
keyword-spacing: off
line-comment-position: off
linebreak-style:
- error
- unix
lines-around-comment: off
lines-around-directive: off
max-depth: off
max-len: off
max-nested-callbacks: off
max-params: off
max-statements-per-line: off
max-statements:
- error
- 30
multiline-ternary: off
new-cap: off
new-parens: off
newline-after-var: off
newline-before-return: off
newline-per-chained-call: off
no-array-constructor: off
no-bitwise: off
no-continue: off
no-inline-comments: off
no-lonely-if: off
no-mixed-operators: off
no-mixed-spaces-and-tabs: off
no-multi-assign: off
no-multiple-empty-lines: off
no-negated-condition: off
no-nested-ternary: off
no-new-object: off
no-plusplus: off
no-restricted-syntax: off
no-spaced-func: off
no-tabs: off
no-ternary: off
no-trailing-spaces: off
no-underscore-dangle: off
no-unneeded-ternary: off
object-curly-newline: off
object-curly-spacing: off
object-property-newline: off
one-var-declaration-per-line: off
one-var: off
operator-assignment: off
operator-linebreak: off
padded-blocks: off
quote-props: off
quotes:
- error
- single
require-jsdoc: off
semi-spacing: off
semi:
- error
- always
sort-keys: off
sort-vars: off
space-before-blocks: off
space-before-function-paren: off
space-in-parens: off
space-infix-ops: off
space-unary-ops: off
spaced-comment: off
template-tag-spacing: off
unicode-bom: off
wrap-regex: off
# ECMAScript 6
arrow-body-style: off
arrow-parens: off
arrow-spacing: off
constructor-super: off
generator-star-spacing: off
no-class-assign: off
no-confusing-arrow: off
no-const-assign: off
no-dupe-class-members: off
no-duplicate-imports: off
no-new-symbol: off
no-restricted-imports: off
no-this-before-super: off
no-useless-computed-key: off
no-useless-constructor: off
no-useless-rename: off
no-var: off
object-shorthand: off
prefer-arrow-callback: off
prefer-const: off
prefer-destructuring: off
prefer-numeric-literals: off
prefer-rest-params: off
prefer-reflect: off
prefer-spread: off
prefer-template: off
require-yield: off
rest-spread-spacing: off
sort-imports: off
symbol-description: off
template-curly-spacing: off
yield-star-spacing: off
import/order: error

View File

@@ -1,47 +1,48 @@
---
name: Bug report
about: Create a bug report
---
<!--
Thanks for reporting a bug for Portainer !
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.
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
repository. If there is a duplicate, please close your issue and add a comment
to the existing issue instead.
Also, be sure to check our FAQ and documentation first: https://portainer.readthedocs.io
-->
**Bug description**
A clear and concise description of what the bug is.
**Expected behavior**
A clear and concise description of what you expected to happen.
Briefly describe what you were expecting.
**Steps to reproduce the issue:**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Technical details:**
* Portainer version:
* Docker version (managed by Portainer):
* Platform (windows/linux):
* Command used to start Portainer (`docker run -p 9000:9000 portainer/portainer`):
* Browser:
**Additional context**
Add any other context about the problem here.
---
name: Bug report
about: Create a bug report
---
<!--
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 http://portainer.io/slack/.
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
repository. If there is a duplicate, please close your issue and add a comment
to the existing issue instead.
Also, be sure to check our FAQ and documentation first: https://documentation.portainer.io/
-->
**Bug description**
A clear and concise description of what the bug is.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Portainer Logs**
Provide the logs of your Portainer container or Service.
You can see how [here](https://documentation.portainer.io/archive/1.23.2/faq/#how-do-i-get-the-logs-from-portainer)
**Steps to reproduce the issue:**
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Technical details:**
- Portainer version:
- Docker version (managed by Portainer):
- Platform (windows/linux):
- Command used to start Portainer (`docker run -p 9000:9000 portainer/portainer`):
- Browser:
**Additional context**
Add any other context about the problem here.

View File

@@ -6,7 +6,9 @@ about: Ask us a question about Portainer usage or deployment
<!--
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.
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 http://portainer.io/slack/
Also, be sure to check our FAQ and documentation first: https://portainer.readthedocs.io
-->

View File

@@ -8,7 +8,7 @@ about: Suggest a feature/enhancement that should be added in Portainer
Thanks for opening a feature request for Portainer !
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.
Do you need help or have a question? Come chat with us on Slack http://portainer.io/slack/
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

53
.github/stale.yml vendored Normal file
View File

@@ -0,0 +1,53 @@
# Config for Stalebot, limited to only `issues`
only: issues
# Issues config
issues:
daysUntilStale: 60
daysUntilClose: 7
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Issues with these labels will never be considered stale
exemptLabels:
- kind/enhancement
- kind/question
- kind/style
- kind/workaround
- bug/need-confirmation
- bug/confirmed
- status/discuss
# Only issues with all of these labels are checked if stale. Defaults to `[]` (disabled)
onlyLabels: []
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: true
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: true
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: true
# Label to use when marking an issue as stale
staleLabel: status/stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been marked as stale as it has not had recent activity,
it will be closed if no further activity occurs in the next 7 days.
If you believe that it has been incorrectly labelled as stale,
leave a comment and the label will be removed.
# Comment to post when removing the stale label.
# unmarkComment: >
# Your comment here.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
Since no further activity has appeared on this issue it will be closed.
If you believe that it has been incorrectly closed, leave a comment
mentioning `ametdoohan`, `balasu` or `keverv` and one of our staff will then review the issue.
Note - If it is an old bug report, make sure that it is reproduceable in the
latest version of Portainer as it may have already been fixed.

12
.gitignore vendored
View File

@@ -4,4 +4,14 @@ dist
portainer-checksum.txt
api/cmd/portainer/portainer*
.tmp
.vscode
**/.vscode/settings.json
**/.vscode/tasks.json
.eslintcache
.idea
test/e2e/cypress/screenshots
*.db
*.log
__debug_bin
api/docs
.env

13
.prettierrc Normal file
View File

@@ -0,0 +1,13 @@
{
"printWidth": 180,
"singleQuote": true,
"htmlWhitespaceSensitivity": "strict",
"overrides": [
{
"files": ["*.html"],
"options": {
"parser": "angular"
}
}
]
}

View File

@@ -0,0 +1,19 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceRoot}/api/cmd/portainer/main.go",
"cwd": "${workspaceRoot}",
"env": {},
"showLog": true,
"args": ["--data", "${env:HOME}/portainer-data", "--assets", "${workspaceRoot}/dist"]
}
]
}

View File

@@ -0,0 +1,167 @@
{
// Place your portainer workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
// Placeholders with the same ids are connected.
// Example:
// "Print to console": {
// "scope": "javascript,typescript",
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// }
"Component": {
"scope": "javascript",
"prefix": "mycomponent",
"description": "Dummy Angularjs Component",
"body": [
"import angular from 'angular';",
"import controller from './${TM_FILENAME_BASE}Controller'",
"",
"angular.module('portainer.${TM_DIRECTORY/.*\\/app\\/([^\\/]*)(\\/.*)?$/$1/}').component('$TM_FILENAME_BASE', {",
" templateUrl: './$TM_FILENAME_BASE.html',",
" controller,",
"});",
""
]
},
"Controller": {
"scope": "javascript",
"prefix": "mycontroller",
"body": [
"class ${TM_FILENAME_BASE/(.*)/${1:/capitalize}/} {",
"\t/* @ngInject */",
"\tconstructor($0) {",
"\t}",
"}",
"",
"export default ${TM_FILENAME_BASE/(.*)/${1:/capitalize}/};"
],
"description": "Dummy ES6+ controller"
},
"Service": {
"scope": "javascript",
"prefix": "myservice",
"description": "Dummy ES6+ service",
"body": [
"import angular from 'angular';",
"import PortainerError from 'Portainer/error';",
"",
"class $1 {",
" /* @ngInject */",
" constructor(\\$async, $0) {",
" this.\\$async = \\$async;",
"",
" this.getAsync = this.getAsync.bind(this);",
" this.getAllAsync = this.getAllAsync.bind(this);",
" this.createAsync = this.createAsync.bind(this);",
" this.updateAsync = this.updateAsync.bind(this);",
" this.deleteAsync = this.deleteAsync.bind(this);",
" }",
"",
" /**",
" * GET",
" */",
" async getAsync() {",
" try {",
"",
" } catch (err) {",
" throw new PortainerError('', err);",
" }",
" }",
"",
" async getAllAsync() {",
" try {",
"",
" } catch (err) {",
" throw new PortainerError('', err);",
" }",
" }",
"",
" get() {",
" if () {",
" return this.\\$async(this.getAsync);",
" }",
" return this.\\$async(this.getAllAsync);",
" }",
"",
" /**",
" * CREATE",
" */",
" async createAsync() {",
" try {",
"",
" } catch (err) {",
" throw new PortainerError('', err);",
" }",
" }",
"",
" create() {",
" return this.\\$async(this.createAsync);",
" }",
"",
" /**",
" * UPDATE",
" */",
" async updateAsync() {",
" try {",
"",
" } catch (err) {",
" throw new PortainerError('', err);",
" }",
" }",
"",
" update() {",
" return this.\\$async(this.updateAsync);",
" }",
"",
" /**",
" * DELETE",
" */",
" async deleteAsync() {",
" try {",
"",
" } catch (err) {",
" throw new PortainerError('', err);",
" }",
" }",
"",
" delete() {",
" return this.\\$async(this.deleteAsync);",
" }",
"}",
"",
"export default $1;",
"angular.module('portainer.${TM_DIRECTORY/.*\\/app\\/([^\\/]*)(\\/.*)?$/$1/}').service('$1', $1);"
]
},
"swagger-api-doc": {
"prefix": "swapi",
"scope": "go",
"description": "Snippet for a api doc",
"body": [
"// @id ",
"// @summary ",
"// @description ",
"// @description **Access policy**: ",
"// @tags ",
"// @security jwt",
"// @accept json",
"// @produce json",
"// @param id path int true \"identifier\"",
"// @param body body Object true \"details\"",
"// @success 200 {object} portainer. \"Success\"",
"// @success 204 \"Success\"",
"// @failure 400 \"Invalid request\"",
"// @failure 403 \"Permission denied\"",
"// @failure 404 \" not found\"",
"// @failure 500 \"Server error\"",
"// @router /{id} [get]"
]
}
}

View File

@@ -6,30 +6,16 @@ Some basic conventions for contributing to this project.
Please make sure that there aren't existing pull requests attempting to address the issue mentioned. Likewise, please check for issues related to update, as someone else may be working on the issue in a branch or fork.
* Please open a discussion in a new issue / existing issue to talk about the changes you'd like to bring
* Develop in a topic branch, not master/develop
- Please open a discussion in a new issue / existing issue to talk about the changes you'd like to bring
- Develop in a topic branch, not master/develop
When creating a new branch, prefix it with the *type* of the change (see section **Commit Message Format** below), the associated opened issue number, a dash and some text describing the issue (using dash as a separator).
When creating a new branch, prefix it with the _type_ of the change (see section **Commit Message Format** below), the associated opened issue number, a dash and some text describing the issue (using dash as a separator).
For example, if you work on a bugfix for the issue #361, you could name the branch `fix361-template-selection`.
## Issues open to contribution
Want to contribute but don't know where to start?
Some of the open issues are labeled with prefix `exp/`, this is used to mark them as available for contributors to work on. All of these have an attributed difficulty level:
* **beginner**: a task that should be accessible with users not familiar with the codebase
* **intermediate**: a task that require some understanding of the project codebase or some experience in
either AngularJS or Golang
* **advanced**: a task that require a deep understanding of the project codebase
You can use Github filters to list these issues:
* beginner labeled issues: https://github.com/portainer/portainer/labels/exp%2Fbeginner
* intermediate labeled issues: https://github.com/portainer/portainer/labels/exp%2Fintermediate
* advanced labeled issues: https://github.com/portainer/portainer/labels/exp%2Fadvanced
Want to contribute but don't know where to start? Have a look at the issues labeled with the `good first issue` label: https://github.com/portainer/portainer/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22
## Commit Message Format
@@ -51,14 +37,14 @@ Lines should not exceed 100 characters. This allows the message to be easier to
Must be one of the following:
* **feat**: A new feature
* **fix**: A bug fix
* **docs**: Documentation only changes
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
- **feat**: A new feature
- **fix**: A bug fix
- **docs**: Documentation only changes
- **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
semi-colons, etc)
* **refactor**: A code change that neither fixes a bug or adds a feature
* **test**: Adding missing tests
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
- **refactor**: A code change that neither fixes a bug or adds a feature
- **test**: Adding missing tests
- **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
generation
### Scope
@@ -71,20 +57,73 @@ You can use the **area** label tag associated on the issue here (for `area/conta
The subject contains succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize first letter
- no dot (.) at the end
## Contribution process
Our contribution process is described below. Some of the steps can be visualized inside Github via specific `contrib/` labels, such as `contrib/func-review-in-progress` or `contrib/tech-review-approved`.
Our contribution process is described below. Some of the steps can be visualized inside Github via specific `status/` labels, such as `status/1-functional-review` or `status/2-technical-review`.
### Bug report
![portainer_bugreport_workflow](https://user-images.githubusercontent.com/5485061/43569306-5571b3a0-9637-11e8-8559-786cfc82a14f.png)
![portainer_bugreport_workflow](https://user-images.githubusercontent.com/5485061/45727219-50190a00-bbf5-11e8-9fe8-3a563bb8d5d7.png)
### Feature request
The feature request process is similar to the bug report process but has an extra functional validation before the technical validation.
The feature request process is similar to the bug report process but has an extra functional validation before the technical validation as well as a documentation validation before the testing phase.
![portainer_featurerequest_workflow](https://user-images.githubusercontent.com/5485061/43569315-5d30a308-9637-11e8-8292-3c62b5612925.png)
![portainer_featurerequest_workflow](https://user-images.githubusercontent.com/5485061/45727229-5ad39f00-bbf5-11e8-9550-16ba66c50615.png)
## Build Portainer locally
Ensure you have Docker, Node.js, yarn, and Golang installed in the correct versions.
Install dependencies with yarn:
```sh
$ yarn
```
Then build and run the project:
```sh
$ yarn start
```
Portainer can now be accessed at <http://localhost:9000>.
Find more detailed steps at <https://documentation.portainer.io/contributing/instructions/>.
## Adding api docs
When adding a new resource (or a route handler), we should add a new tag to api/http/handler/handler.go#L136 like this:
```
// @tag.name <Name of resource>
// @tag.description a short description
```
When adding a new route to an existing handler use the following as a template (you can use `swapi` snippet if you're using vscode):
```
// @id
// @summary
// @description
// @description **Access policy**:
// @tags
// @security jwt
// @accept json
// @produce json
// @param id path int true "identifier"
// @param body body Object true "details"
// @success 200 {object} portainer. "Success"
// @success 204 "Success"
// @failure 400 "Invalid request"
// @failure 403 "Permission denied"
// @failure 404 " not found"
// @failure 500 "Server error"
// @router /{id} [get]
```
explanation about each line can be found (here)[https://github.com/swaggo/swag#api-operation]

View File

@@ -1,27 +1,19 @@
<p align="center">
<img title="portainer" src='https://portainer.io/images/logo_alt.png' />
<img title="portainer" src='https://github.com/portainer/portainer/blob/develop/app/assets/images/logo_alt.png?raw=true' />
</p>
[![Docker Pulls](https://img.shields.io/docker/pulls/portainer/portainer.svg)](https://hub.docker.com/r/portainer/portainer/)
[![Microbadger](https://images.microbadger.com/badges/image/portainer/portainer.svg)](http://microbadger.com/images/portainer/portainer "Image size")
[![Documentation Status](https://readthedocs.org/projects/portainer/badge/?version=stable)](http://portainer.readthedocs.io/en/stable/?badge=stable)
[![Build Status](https://semaphoreci.com/api/v1/portainer/portainer/branches/develop/badge.svg)](https://semaphoreci.com/portainer/portainer)
[![Microbadger](https://images.microbadger.com/badges/image/portainer/portainer.svg)](http://microbadger.com/images/portainer/portainer 'Image size')
[![Build Status](https://portainer.visualstudio.com/Portainer%20CI/_apis/build/status/Portainer%20CI?branchName=develop)](https://portainer.visualstudio.com/Portainer%20CI/_build/latest?definitionId=3&branchName=develop)
[![Code Climate](https://codeclimate.com/github/portainer/portainer/badges/gpa.svg)](https://codeclimate.com/github/portainer/portainer)
[![Slack](https://portainer.io/slack/badge.svg)](https://portainer.io/slack/)
[![Gitter](https://badges.gitter.im/portainer/Lobby.svg)](https://gitter.im/portainer/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YHXZJQNJQ36H6)
**_Portainer_** is a lightweight management UI which allows you to **easily** manage your different Docker environments (Docker hosts or Swarm clusters).
**_Portainer_** is meant to be as **simple** to deploy as it is to use. It consists of a single container that can run on any Docker engine (can be deployed as Linux container or a Windows native container).
**_Portainer_** allows you to manage your Docker containers, images, volumes, networks and more ! It is compatible with the *standalone Docker* engine and with *Docker Swarm mode*.
**_Portainer_** is meant to be as **simple** to deploy as it is to use. It consists of a single container that can run on any Docker engine (can be deployed as Linux container or a Windows native container, supports other platforms too).
**_Portainer_** allows you to manage all your Docker resources (containers, images, volumes, networks and more!) It is compatible with the _standalone Docker_ engine and with _Docker Swarm mode_.
## Demo
<img src="https://portainer.io/images/screenshots/portainer.gif" width="77%"/>
You can try out the public demo instance: http://demo.portainer.io/ (login with the username **admin** and the password **tryportainer**).
Please note that the public demo cluster is **reset every 15min**.
@@ -32,35 +24,41 @@ Alternatively, you can deploy a copy of the demo stack inside a [play-with-docke
- Sign in with your [Docker ID](https://docs.docker.com/docker-id)
- Follow [these](https://github.com/portainer/portainer-demo/blob/master/play-with-docker/docker-stack.yml#L5-L8) steps.
Unlike the public demo, the playground sessions are deleted after 4 hours. Apart from that, all the settings are same, including default credentials.
Unlike the public demo, the playground sessions are deleted after 4 hours. Apart from that, all the settings are the same, including default credentials.
## Getting started
* [Deploy Portainer](https://portainer.readthedocs.io/en/latest/deployment.html)
* [Documentation](https://portainer.readthedocs.io)
- [Deploy Portainer](https://www.portainer.io/installation/)
- [Documentation](https://documentation.portainer.io)
## Getting help
* Issues: https://github.com/portainer/portainer/issues
* FAQ: https://portainer.readthedocs.io/en/latest/faq.html
* Slack (chat): https://portainer.io/slack/
* Gitter (chat): https://gitter.im/portainer/Lobby
For FORMAL Support, please purchase a support subscription from here: https://www.portainer.io/products-services/portainer-business-support/
For community support: You can find more information about Portainer's community support framework policy here: https://www.portainer.io/2019/04/portainer-support-policy/
- Issues: https://github.com/portainer/portainer/issues
- FAQ: https://documentation.portainer.io
- Slack (chat): https://portainer.io/slack/
## Reporting bugs and contributing
* Want to report a bug or request a feature? Please open [an issue](https://github.com/portainer/portainer/issues/new).
* Want to help us build **_portainer_**? Follow our [contribution guidelines](https://portainer.readthedocs.io/en/latest/contribute.html) to build it locally and make a pull request. We need all the help we can get!
- Want to report a bug or request a feature? Please open [an issue](https://github.com/portainer/portainer/issues/new).
- Want to help us build **_portainer_**? Follow our [contribution guidelines](https://www.portainer.io/documentation/how-to-contribute/) to build it locally and make a pull request. We need all the help we can get!
## Security
- Here at Portainer, we believe in [responsible disclosure](https://en.wikipedia.org/wiki/Responsible_disclosure) of security issues. If you have found a security issue, please report it to <security@portainer.io>.
## Privacy
**To make sure we focus our development effort in the right places we need to know which features get used most often. To give us this information we use [Matomo Analytics](https://matomo.org/), which is hosted in Germany and is fully GDPR compliant.**
When Portainer first starts, you are given the option to DISABLE analytics. If you **don't** choose to disable it, we collect anonymous usage as per [our privacy policy](https://www.portainer.io/documentation/in-app-analytics-and-privacy-policy/). **Please note**, there is no personally identifiable information sent or stored at any time and we only use the data to help us improve Portainer.
## Limitations
**_Portainer_** has full support for the following Docker versions:
* Docker 1.10 to the latest version
* Standalone Docker Swarm >= 1.2.3 _(**NOTE:** Use of Standalone Docker Swarm is being discouraged since the introduction of built-in Swarm Mode in Docker. While older versions of Portainer had support for Standalone Docker Swarm, Portainer 1.17.0 and newer **do not** support it. However, the built-in Swarm Mode of Docker is fully supported.)_
Partial support for the following Docker versions (some features may not be available):
* Docker 1.9
Portainer supports "Current - 2 docker versions only. Prior versions may operate, however these are not supported.
## Licensing
@@ -70,4 +68,4 @@ Portainer also contains the following code, which is licensed under the [MIT lic
UI For Docker: Copyright (c) 2013-2016 Michael Crosby (crosbymichael.com), Kevan Ahlquist (kevanahlquist.com), Anthony Lapenna (portainer.io)
rdash-angular: Copyright (c) [2014] [Elliot Hesp]
rdash-angular: Copyright (c) [2014][elliot hesp]

View File

@@ -0,0 +1,69 @@
package adminmonitor
import (
"context"
"log"
"time"
portainer "github.com/portainer/portainer/api"
)
var logFatalf = log.Fatalf
type Monitor struct {
timeout time.Duration
datastore portainer.DataStore
shutdownCtx context.Context
cancellationFunc context.CancelFunc
}
// 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 portainer.DataStore, shutdownCtx context.Context) *Monitor {
return &Monitor{
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() {
cancellationCtx, cancellationFunc := context.WithCancel(context.Background())
m.cancellationFunc = cancellationFunc
go func() {
log.Println("[DEBUG] [internal,init] [message: start initialization monitor ]")
select {
case <-time.After(m.timeout):
initialized, err := m.WasInitialized()
if err != nil {
logFatalf("failed getting admin user: %s", err)
}
if !initialized {
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]")
case <-m.shutdownCtx.Done():
log.Println("[DEBUG] [internal,init] [message: shutting down initialization monitor]")
}
}()
}
// Stop stops monitor. Safe to call even if monitor wasn't started.
func (m *Monitor) Stop() {
if m.cancellationFunc == nil {
return
}
m.cancellationFunc()
m.cancellationFunc = nil
}
// WasInitialized is a system initialization check
func (m *Monitor) WasInitialized() (bool, error) {
users, err := m.datastore.User().UsersByRole(portainer.AdministratorRole)
if err != nil {
return false, err
}
return len(users) > 0, nil
}

View File

@@ -0,0 +1,50 @@
package adminmonitor
import (
"context"
"testing"
"time"
portainer "github.com/portainer/portainer/api"
i "github.com/portainer/portainer/api/internal/testhelpers"
"github.com/stretchr/testify/assert"
)
func Test_stopWithoutStarting(t *testing.T) {
monitor := New(1*time.Minute, nil, nil)
monitor.Stop()
}
func Test_stopCouldBeCalledMultipleTimes(t *testing.T) {
monitor := New(1*time.Minute, nil, nil)
monitor.Stop()
monitor.Stop()
}
func Test_canStopStartedMonitor(t *testing.T) {
monitor := New(1*time.Minute, nil, context.Background())
monitor.Start()
assert.NotNil(t, monitor.cancellationFunc, "cancellation function is missing in started monitor")
monitor.Stop()
assert.Nil(t, monitor.cancellationFunc, "cancellation function should absent in stopped monitor")
}
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)
assert.True(t, fataled, "monitor should been timeout and fatal")
}

53
api/api-description.md Normal file
View File

@@ -0,0 +1,53 @@
Portainer API is an HTTP API served by Portainer. It is used by the Portainer UI and everything you can do with the UI can be done using the HTTP API.
Examples are available at https://gist.github.com/deviantony/77026d402366b4b43fa5918d41bc42f8
You can find out more about Portainer at [http://portainer.io](http://portainer.io) and get some support on [Slack](http://portainer.io/slack/).
# Authentication
Most of the API endpoints require to be authenticated as well as some level of authorization to be used.
Portainer API uses JSON Web Token to manage authentication and thus requires you to provide a token in the **Authorization** header of each request
with the **Bearer** authentication mechanism.
Example:
```
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsInJvbGUiOjEsImV4cCI6MTQ5OTM3NjE1NH0.NJ6vE8FY1WG6jsRQzfMqeatJ4vh2TWAeeYfDhP71YEE
```
# Security
Each API endpoint has an associated access policy, it is documented in the description of each endpoint.
Different access policies are available:
- Public access
- Authenticated access
- Restricted access
- Administrator access
### Public access
No authentication is required to access the endpoints with this access policy.
### Authenticated access
Authentication is required to access the endpoints with this access policy.
### Restricted access
Authentication is required to access the endpoints with this access policy.
Extra-checks might be added to ensure access to the resource is granted. Returned data might also be filtered.
### Administrator access
Authentication as well as an administrator role are required to access the endpoints with this access policy.
# Execute Docker requests
Portainer **DO NOT** expose specific endpoints to manage your Docker resources (create a container, remove a volume, etc...).
Instead, it acts as a reverse-proxy to the Docker HTTP API. This means that you can execute Docker requests **via** the Portainer HTTP API.
To do so, you can use the `/endpoints/{id}/docker` Portainer API endpoint (which is not documented below due to Swagger limitations). This endpoint has a restricted access policy so you still need to be authenticated to be able to query this endpoint. Any query on this endpoint will be proxied to the Docker API of the associated endpoint (requests and responses objects are the same as documented in the Docker API).
**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://gist.github.com/deviantony/77026d402366b4b43fa5918d41bc42f8).

View File

@@ -7,13 +7,13 @@ import (
// TarFileInBuffer will create a tar archive containing a single file named via fileName and using the content
// specified in fileContent. Returns the archive as a byte array.
func TarFileInBuffer(fileContent []byte, fileName string) ([]byte, error) {
func TarFileInBuffer(fileContent []byte, fileName string, mode int64) ([]byte, error) {
var buffer bytes.Buffer
tarWriter := tar.NewWriter(&buffer)
header := &tar.Header{
Name: fileName,
Mode: 0600,
Mode: mode,
Size: int64(len(fileContent)),
}

119
api/archive/targz.go Normal file
View File

@@ -0,0 +1,119 @@
package archive
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
// TarGzDir creates a tar.gz archive and returns it's path.
// abosolutePath should be an absolute path to a directory.
// Archive name will be <directoryName>.tar.gz and will be placed next to the directory.
func TarGzDir(absolutePath string) (string, error) {
targzPath := filepath.Join(absolutePath, fmt.Sprintf("%s.tar.gz", filepath.Base(absolutePath)))
outFile, err := os.Create(targzPath)
if err != nil {
return "", err
}
defer outFile.Close()
zipWriter := gzip.NewWriter(outFile)
defer zipWriter.Close()
tarWriter := tar.NewWriter(zipWriter)
defer tarWriter.Close()
err = filepath.Walk(absolutePath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if path == targzPath {
return nil // skip archive file
}
pathInArchive := filepath.Clean(strings.TrimPrefix(path, absolutePath))
if pathInArchive == "" {
return nil // skip root dir
}
return addToArchive(tarWriter, pathInArchive, path, info)
})
return targzPath, err
}
func addToArchive(tarWriter *tar.Writer, pathInArchive string, path string, info os.FileInfo) error {
header, err := tar.FileInfoHeader(info, info.Name())
if err != nil {
return err
}
header.Name = pathInArchive // use relative paths in archive
err = tarWriter.WriteHeader(header)
if err != nil {
return err
}
if info.IsDir() {
return nil
}
file, err := os.Open(path)
if err != nil {
return err
}
_, err = io.Copy(tarWriter, file)
return err
}
// ExtractTarGz reads a .tar.gz archive from the reader and extracts it into outputDirPath directory
func ExtractTarGz(r io.Reader, outputDirPath string) error {
zipReader, err := gzip.NewReader(r)
if err != nil {
return err
}
defer zipReader.Close()
tarReader := tar.NewReader(zipReader)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
switch header.Typeflag {
case tar.TypeDir:
// skip, dir will be created with a file
case tar.TypeReg:
p := filepath.Clean(filepath.Join(outputDirPath, header.Name))
if err := os.MkdirAll(filepath.Dir(p), 0744); err != nil {
return fmt.Errorf("Failed to extract dir %s", filepath.Dir(p))
}
outFile, err := os.Create(p)
if err != nil {
return fmt.Errorf("Failed to create file %s", header.Name)
}
if _, err := io.Copy(outFile, tarReader); err != nil {
return fmt.Errorf("Failed to extract file %s", header.Name)
}
outFile.Close()
default:
return fmt.Errorf("Tar: uknown type: %v in %s",
header.Typeflag,
header.Name)
}
}
return nil
}

98
api/archive/targz_test.go Normal file
View File

@@ -0,0 +1,98 @@
package archive
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
func listFiles(dir string) []string {
items := make([]string, 0)
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if path == dir {
return nil
}
items = append(items, path)
return nil
})
return items
}
func Test_shouldCreateArhive(t *testing.T) {
tmpdir, _ := ioutil.TempDir("", "backup")
defer os.RemoveAll(tmpdir)
content := []byte("content")
ioutil.WriteFile(path.Join(tmpdir, "outer"), content, 0600)
os.MkdirAll(path.Join(tmpdir, "dir"), 0700)
ioutil.WriteFile(path.Join(tmpdir, "dir", ".dotfile"), content, 0600)
ioutil.WriteFile(path.Join(tmpdir, "dir", "inner"), content, 0600)
gzPath, err := TarGzDir(tmpdir)
assert.Nil(t, err)
assert.Equal(t, filepath.Join(tmpdir, fmt.Sprintf("%s.tar.gz", filepath.Base(tmpdir))), gzPath)
extractionDir, _ := ioutil.TempDir("", "extract")
defer os.RemoveAll(extractionDir)
cmd := exec.Command("tar", "-xzf", gzPath, "-C", extractionDir)
err = cmd.Run()
if err != nil {
t.Fatal("Failed to extract archive: ", err)
}
extractedFiles := listFiles(extractionDir)
wasExtracted := func(p string) {
fullpath := path.Join(extractionDir, p)
assert.Contains(t, extractedFiles, fullpath)
copyContent, _ := ioutil.ReadFile(fullpath)
assert.Equal(t, content, copyContent)
}
wasExtracted("outer")
wasExtracted("dir/inner")
wasExtracted("dir/.dotfile")
}
func Test_shouldCreateArhiveXXXXX(t *testing.T) {
tmpdir, _ := ioutil.TempDir("", "backup")
defer os.RemoveAll(tmpdir)
content := []byte("content")
ioutil.WriteFile(path.Join(tmpdir, "outer"), content, 0600)
os.MkdirAll(path.Join(tmpdir, "dir"), 0700)
ioutil.WriteFile(path.Join(tmpdir, "dir", ".dotfile"), content, 0600)
ioutil.WriteFile(path.Join(tmpdir, "dir", "inner"), content, 0600)
gzPath, err := TarGzDir(tmpdir)
assert.Nil(t, err)
assert.Equal(t, filepath.Join(tmpdir, fmt.Sprintf("%s.tar.gz", filepath.Base(tmpdir))), gzPath)
extractionDir, _ := ioutil.TempDir("", "extract")
defer os.RemoveAll(extractionDir)
r, _ := os.Open(gzPath)
ExtractTarGz(r, extractionDir)
if err != nil {
t.Fatal("Failed to extract archive: ", err)
}
extractedFiles := listFiles(extractionDir)
wasExtracted := func(p string) {
fullpath := path.Join(extractionDir, p)
assert.Contains(t, extractedFiles, fullpath)
copyContent, _ := ioutil.ReadFile(fullpath)
assert.Equal(t, content, copyContent)
}
wasExtracted("outer")
wasExtracted("dir/inner")
wasExtracted("dir/.dotfile")
}

BIN
api/archive/testdata/sample_archive.zip vendored Normal file

Binary file not shown.

114
api/archive/zip.go Normal file
View File

@@ -0,0 +1,114 @@
package archive
import (
"archive/zip"
"bytes"
"fmt"
"github.com/pkg/errors"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
// UnzipArchive will unzip an archive from bytes into the dest destination folder on disk
func UnzipArchive(archiveData []byte, dest string) error {
zipReader, err := zip.NewReader(bytes.NewReader(archiveData), int64(len(archiveData)))
if err != nil {
return err
}
for _, zipFile := range zipReader.File {
err := extractFileFromArchive(zipFile, dest)
if err != nil {
return err
}
}
return nil
}
func extractFileFromArchive(file *zip.File, dest string) error {
f, err := file.Open()
if err != nil {
return err
}
defer f.Close()
data, err := ioutil.ReadAll(f)
if err != nil {
return err
}
fpath := filepath.Join(dest, file.Name)
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
_, err = io.Copy(outFile, bytes.NewReader(data))
if err != nil {
return err
}
return outFile.Close()
}
// UnzipFile will decompress a zip archive, moving all files and folders
// within the zip file (parameter 1) to an output directory (parameter 2).
func UnzipFile(src string, dest string) error {
r, err := zip.OpenReader(src)
if err != nil {
return err
}
defer r.Close()
for _, f := range r.File {
p := filepath.Join(dest, f.Name)
// Check for ZipSlip. More Info: http://bit.ly/2MsjAWE
if !strings.HasPrefix(p, filepath.Clean(dest)+string(os.PathSeparator)) {
return fmt.Errorf("%s: illegal file path", p)
}
if f.FileInfo().IsDir() {
// Make Folder
os.MkdirAll(p, os.ModePerm)
continue
}
err = unzipFile(f, p)
if err != nil {
return err
}
}
return nil
}
func unzipFile(f *zip.File, p string) error {
// Make File
if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil {
return errors.Wrapf(err, "unzipFile: can't make a path %s", p)
}
outFile, err := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return errors.Wrapf(err, "unzipFile: can't create file %s", p)
}
defer outFile.Close()
rc, err := f.Open()
if err != nil {
return errors.Wrapf(err, "unzipFile: can't open zip file %s in the archive", f.Name)
}
defer rc.Close()
_, err = io.Copy(outFile, rc)
if err != nil {
return errors.Wrapf(err, "unzipFile: can't copy an archived file content")
}
return nil
}

32
api/archive/zip_test.go Normal file
View File

@@ -0,0 +1,32 @@
package archive
import (
"github.com/stretchr/testify/assert"
"io/ioutil"
"os"
"path/filepath"
"testing"
)
func TestUnzipFile(t *testing.T) {
dir, err := ioutil.TempDir("", "unzip-test-")
assert.NoError(t, err)
defer os.RemoveAll(dir)
/*
Archive structure.
├── 0
│ ├── 1
│ │ └── 2.txt
│ └── 1.txt
└── 0.txt
*/
err = UnzipFile("./testdata/sample_archive.zip", dir)
assert.NoError(t, err)
archiveDir := dir + "/sample_archive"
assert.FileExists(t, filepath.Join(archiveDir, "0.txt"))
assert.FileExists(t, filepath.Join(archiveDir, "0", "1.txt"))
assert.FileExists(t, filepath.Join(archiveDir, "0", "1", "2.txt"))
}

112
api/backup/backup.go Normal file
View File

@@ -0,0 +1,112 @@
package backup
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
"github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/archive"
"github.com/portainer/portainer/api/crypto"
"github.com/portainer/portainer/api/http/offlinegate"
"github.com/portainer/portainer/api/s3"
)
const rwxr__r__ os.FileMode = 0744
var filesToBackup = []string{"compose", "config.json", "custom_templates", "edge_jobs", "edge_stacks", "extensions", "portainer.key", "portainer.pub", "tls"}
func BackupToS3(settings portainer.S3BackupSettings, gate *offlinegate.OfflineGate, datastore portainer.DataStore, filestorePath string) error {
archivePath, err := CreateBackupArchive(settings.Password, gate, datastore, filestorePath)
if err != nil {
log.Printf("[ERROR] failed to backup: %s \n", err)
return err
}
archiveReader, err := os.Open(archivePath)
if err != nil {
log.Println("[ERROR] failed to open backup file")
return err
}
defer os.RemoveAll(filepath.Dir(archivePath))
archiveName := fmt.Sprintf("portainer-backup_%s", filepath.Base(archivePath))
s3session, err := s3.NewSession(settings.Region, settings.AccessKeyID, settings.SecretAccessKey)
if err != nil {
log.Printf("[ERROR] %s \n", err)
return err
}
if err := s3.Upload(s3session, archiveReader, settings.BucketName, archiveName); err != nil {
log.Printf("[ERROR] failed to upload backup to S3: %s \n", err)
return err
}
return nil
}
// Creates a tar.gz system archive and encrypts it if password is not empty. Returns a path to the archive file.
func CreateBackupArchive(password string, gate *offlinegate.OfflineGate, datastore portainer.DataStore, filestorePath string) (string, error) {
unlock := gate.Lock()
defer unlock()
backupDirPath := filepath.Join(filestorePath, "backup", time.Now().Format("2006-01-02_15-04-05"))
if err := os.MkdirAll(backupDirPath, rwxr__r__); err != nil {
return "", errors.Wrap(err, "Failed to create backup dir")
}
if err := backupDb(backupDirPath, datastore); err != nil {
return "", errors.Wrap(err, "Failed to backup database")
}
for _, filename := range filesToBackup {
err := copyPath(filepath.Join(filestorePath, filename), backupDirPath)
if err != nil {
return "", errors.Wrap(err, "Failed to create backup file")
}
}
archivePath, err := archive.TarGzDir(backupDirPath)
if err != nil {
return "", errors.Wrap(err, "Failed to make an archive")
}
if password != "" {
archivePath, err = encrypt(archivePath, password)
if err != nil {
return "", errors.Wrap(err, "Failed to encrypt backup with the password")
}
}
return archivePath, nil
}
func backupDb(backupDirPath string, datastore portainer.DataStore) error {
backupWriter, err := os.Create(filepath.Join(backupDirPath, "portainer.db"))
if err != nil {
return err
}
if err = datastore.BackupTo(backupWriter); err != nil {
return err
}
return backupWriter.Close()
}
func encrypt(path string, passphrase string) (string, error) {
in, err := os.Open(path)
if err != nil {
return "", err
}
defer in.Close()
outFileName := fmt.Sprintf("%s.encrypted", path)
out, err := os.Create(outFileName)
if err != nil {
return "", err
}
err = crypto.AesEncrypt(in, out, []byte(passphrase))
return outFileName, err
}

View File

@@ -0,0 +1,118 @@
package backup
import (
"context"
"log"
"time"
"github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/http/offlinegate"
"github.com/robfig/cron/v3"
)
// BackupScheduler orchestrates S3 settings and active backup cron jobs
type BackupScheduler struct {
cronmanager *cron.Cron
s3backupService portainer.S3BackupService
gate *offlinegate.OfflineGate
datastore portainer.DataStore
filestorePath string
}
func NewBackupScheduler(offlineGate *offlinegate.OfflineGate, datastore portainer.DataStore, filestorePath string) *BackupScheduler {
crontab := cron.New(cron.WithChain(cron.Recover(cron.DefaultLogger)))
s3backupService := datastore.S3Backup()
return &BackupScheduler{
cronmanager: crontab,
s3backupService: s3backupService,
gate: offlineGate,
datastore: datastore,
filestorePath: filestorePath,
}
}
// Start fetches latest backup settings and starts cron job if configured
func (s *BackupScheduler) Start() error {
s.cronmanager.Start()
settings, err := s.s3backupService.GetSettings()
if err != nil {
return errors.Wrap(err, "failed to fetch settings")
}
if canBeScheduled(settings) {
return s.startJob(settings)
}
return nil
}
// Stop stops the scheduler if it is running; otherwise it does nothing.
// A context is returned so the caller can wait for running jobs to complete.
func (s *BackupScheduler) Stop() context.Context {
if s.cronmanager != nil {
log.Println("[DEBUG] Stopping backup scheduler")
return s.cronmanager.Stop()
}
return nil
}
// Update updates stored S3 backup settings and orchestrates cron jobs.
// When scheduler has an active cron job, then it shuts it down.
// When a provided settings has a cron, then starts a new cron job.
// When ever current cron is being shut down, last cron error going to be dropped.
func (s *BackupScheduler) Update(settings portainer.S3BackupSettings) error {
if err := s.s3backupService.UpdateSettings(settings); err != nil {
return errors.Wrap(err, "failed to update settings")
}
if err := s.stopJobs(); err != nil {
return errors.Wrap(err, "failed to stop current cronjob")
}
if canBeScheduled(settings) {
return s.startJob(settings)
}
return nil
}
// stops current backup cron job and drops last cron error if any
func (s *BackupScheduler) stopJobs() error {
// stopping all cron jobs as there should be only one (c)
for _, job := range s.cronmanager.Entries() {
s.cronmanager.Remove(job.ID)
}
return s.s3backupService.DropStatus()
}
func (s *BackupScheduler) startJob(settings portainer.S3BackupSettings) error {
_, err := s.cronmanager.AddFunc(settings.CronRule, s.backup(settings))
if err != nil {
return errors.Wrap(err, "failed to start a new backup cron job")
}
return nil
}
func canBeScheduled(s portainer.S3BackupSettings) bool {
return s.AccessKeyID != "" && s.SecretAccessKey != "" && s.Region != "" && s.BucketName != "" && s.CronRule != ""
}
func (s *BackupScheduler) backup(settings portainer.S3BackupSettings) func() {
return func() {
err := BackupToS3(settings, s.gate, s.datastore, s.filestorePath)
status := portainer.S3BackupStatus{
Failed: err != nil,
Timestamp: time.Now(),
}
if err = s.s3backupService.UpdateStatus(status); err != nil {
log.Printf("[ERROR] failed to update status of last scheduled backup. Status: %+v . Err: %s \n", status, err)
}
}
}

View File

@@ -0,0 +1,112 @@
package backup
import (
"testing"
"time"
portainer "github.com/portainer/portainer/api"
i "github.com/portainer/portainer/api/internal/testhelpers"
"github.com/stretchr/testify/assert"
)
func newScheduler(status *portainer.S3BackupStatus, settings *portainer.S3BackupSettings) *BackupScheduler {
scheduler := NewBackupScheduler(nil, i.NewDatastore(i.WithS3BackupService(status, settings)), "")
scheduler.Start()
return scheduler
}
func settings(cronRule string,
accessKeyID string,
secretAccessKey string,
region string,
bucketName string) *portainer.S3BackupSettings {
return &portainer.S3BackupSettings{
CronRule: cronRule,
AccessKeyID: accessKeyID,
SecretAccessKey: secretAccessKey,
Region: region,
BucketName: bucketName,
}
}
func Test_startWithoutCron_shouldNotStartAJob(t *testing.T) {
scheduler := newScheduler(&portainer.S3BackupStatus{}, &portainer.S3BackupSettings{})
defer scheduler.Stop()
jobs := scheduler.cronmanager.Entries()
assert.Len(t, jobs, 0, "should have empty job list")
}
func Test_startWitACron_shouldAlsoStartAJob(t *testing.T) {
scheduler := newScheduler(&portainer.S3BackupStatus{}, settings("*/10 * * * *", "id", "key", "region", "bucket"))
defer scheduler.Stop()
jobs := scheduler.cronmanager.Entries()
assert.Len(t, jobs, 1, "should have 1 active job")
}
func Test_update_shouldDropStatus(t *testing.T) {
storedStatus := &portainer.S3BackupStatus{Failed: true, Timestamp: time.Now().Add(-time.Hour)}
scheduler := newScheduler(storedStatus, &portainer.S3BackupSettings{})
defer scheduler.Stop()
scheduler.Update(*settings("*/10 * * * *", "id", "key", "region", "bucket"))
assert.Equal(t, portainer.S3BackupStatus{}, *storedStatus, "stasus should be dropped")
}
func Test_update_shouldUpdateSettings(t *testing.T) {
storedSettings := &portainer.S3BackupSettings{}
scheduler := newScheduler(&portainer.S3BackupStatus{}, storedSettings)
defer scheduler.Stop()
newSettings := settings("", "id2", "key2", "region2", "bucket2")
scheduler.Update(*newSettings)
assert.EqualValues(t, *storedSettings, *newSettings, "updated settings should match stored settings")
}
func Test_updateWithCron_shouldStartAJob(t *testing.T) {
scheduler := newScheduler(&portainer.S3BackupStatus{}, &portainer.S3BackupSettings{})
defer scheduler.Stop()
jobs := scheduler.cronmanager.Entries()
assert.Len(t, jobs, 0, "should have empty job list upon startup")
scheduler.Update(*settings("*/10 * * * *", "id", "key", "region", "bucket"))
jobs = scheduler.cronmanager.Entries()
assert.Len(t, jobs, 1, "should have 1 active job")
}
func Test_updateWithoutCron_shouldStopActiveJob(t *testing.T) {
scheduler := newScheduler(&portainer.S3BackupStatus{}, &portainer.S3BackupSettings{})
defer scheduler.Stop()
scheduler.Update(*settings("*/10 * * * *", "id", "key", "region", "bucket"))
jobs := scheduler.cronmanager.Entries()
assert.Len(t, jobs, 1, "should have 1 active job")
scheduler.Update(*settings("", "id2", "key2", "region2", "bucket2"))
jobs = scheduler.cronmanager.Entries()
assert.Len(t, jobs, 0, "should have no active jobs")
}
func Test_updateWithACron_shouldStopActiveJob_andStartNewJob(t *testing.T) {
scheduler := newScheduler(&portainer.S3BackupStatus{}, &portainer.S3BackupSettings{})
defer scheduler.Stop()
scheduler.Update(*settings("*/10 * * * *", "id", "key", "region", "bucket"))
jobs := scheduler.cronmanager.Entries()
assert.Len(t, jobs, 1, "should have 1 active job")
initJobId := jobs[0].ID
scheduler.Update(*settings("*/10 * * * *", "id", "key", "region", "bucket"))
jobs = scheduler.cronmanager.Entries()
assert.Len(t, jobs, 1, "should have 1 active job")
assert.NotEqual(t, initJobId, jobs[0].ID, "new job should have a diffent id")
}

68
api/backup/copy.go Normal file
View File

@@ -0,0 +1,68 @@
package backup
import (
"errors"
"io"
"os"
"path/filepath"
"strings"
)
func copyPath(path string, toDir string) error {
info, err := os.Stat(path)
if err != nil && errors.Is(err, os.ErrNotExist) {
// skip copy if file does not exist
return nil
}
if !info.IsDir() {
destination := filepath.Join(toDir, info.Name())
return copyFile(path, destination)
}
return copyDir(path, toDir)
}
func copyDir(fromDir, toDir string) error {
cleanedSourcePath := filepath.Clean(fromDir)
parentDirectory := filepath.Dir(cleanedSourcePath)
err := filepath.Walk(cleanedSourcePath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
destination := filepath.Join(toDir, strings.TrimPrefix(path, parentDirectory))
if info.IsDir() {
return nil // skip directory creations
}
if info.Mode()&os.ModeSymlink != 0 { // entry is a symlink
return nil // don't copy symlinks
}
return copyFile(path, destination)
})
return err
}
// copies regular a file from src to dst
func copyFile(src, dst string) error {
from, err := os.Open(src)
if err != nil {
return err
}
defer from.Close()
// has to include 'execute' bit, otherwise fails. MkdirAll follows `mkdir -m` restrictions
if err := os.MkdirAll(filepath.Dir(dst), 0744); err != nil {
return err
}
to, err := os.Create(dst)
if err != nil {
return err
}
defer to.Close()
_, err = io.Copy(to, from)
return err
}

104
api/backup/copy_test.go Normal file
View File

@@ -0,0 +1,104 @@
package backup
import (
"io/ioutil"
"os"
"path"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
func listFiles(dir string) []string {
items := make([]string, 0)
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if path == dir {
return nil
}
items = append(items, path)
return nil
})
return items
}
func contains(t *testing.T, list []string, path string) {
assert.Contains(t, list, path)
copyContent, _ := ioutil.ReadFile(path)
assert.Equal(t, "content\n", string(copyContent))
}
func Test_copyFile_returnsError_whenSourceDoesNotExist(t *testing.T) {
tmpdir, _ := ioutil.TempDir("", "backup")
defer os.RemoveAll(tmpdir)
err := copyFile("does-not-exist", tmpdir)
assert.NotNil(t, err)
}
func Test_copyFile_shouldMakeAbackup(t *testing.T) {
tmpdir, _ := ioutil.TempDir("", "backup")
defer os.RemoveAll(tmpdir)
content := []byte("content")
ioutil.WriteFile(path.Join(tmpdir, "origin"), content, 0600)
err := copyFile(path.Join(tmpdir, "origin"), path.Join(tmpdir, "copy"))
assert.Nil(t, err)
copyContent, _ := ioutil.ReadFile(path.Join(tmpdir, "copy"))
assert.Equal(t, content, copyContent)
}
func Test_copyDir_shouldCopyAllFilesAndDirectories(t *testing.T) {
destination, _ := ioutil.TempDir("", "destination")
defer os.RemoveAll(destination)
err := copyDir("./test_assets/copy_test", destination)
assert.Nil(t, err)
createdFiles := listFiles(destination)
contains(t, createdFiles, filepath.Join(destination, "copy_test", "outer"))
contains(t, createdFiles, filepath.Join(destination, "copy_test", "dir", ".dotfile"))
contains(t, createdFiles, filepath.Join(destination, "copy_test", "dir", "inner"))
}
func Test_backupPath_shouldSkipWhenNotExist(t *testing.T) {
tmpdir, _ := ioutil.TempDir("", "backup")
defer os.RemoveAll(tmpdir)
err := copyPath("does-not-exists", tmpdir)
assert.Nil(t, err)
assert.Empty(t, listFiles(tmpdir))
}
func Test_backupPath_shouldCopyFile(t *testing.T) {
tmpdir, _ := ioutil.TempDir("", "backup")
defer os.RemoveAll(tmpdir)
content := []byte("content")
ioutil.WriteFile(path.Join(tmpdir, "file"), content, 0600)
os.MkdirAll(path.Join(tmpdir, "backup"), 0700)
err := copyPath(path.Join(tmpdir, "file"), path.Join(tmpdir, "backup"))
assert.Nil(t, err)
copyContent, err := ioutil.ReadFile(path.Join(tmpdir, "backup", "file"))
assert.Nil(t, err)
assert.Equal(t, content, copyContent)
}
func Test_backupPath_shouldCopyDir(t *testing.T) {
destination, _ := ioutil.TempDir("", "destination")
defer os.RemoveAll(destination)
err := copyPath("./test_assets/copy_test", destination)
assert.Nil(t, err)
createdFiles := listFiles(destination)
contains(t, createdFiles, filepath.Join(destination, "copy_test", "outer"))
contains(t, createdFiles, filepath.Join(destination, "copy_test", "dir", ".dotfile"))
contains(t, createdFiles, filepath.Join(destination, "copy_test", "dir", "inner"))
}

68
api/backup/restore.go Normal file
View File

@@ -0,0 +1,68 @@
package backup
import (
"context"
"io"
"os"
"path/filepath"
"time"
"github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/archive"
"github.com/portainer/portainer/api/crypto"
"github.com/portainer/portainer/api/http/offlinegate"
)
var filesToRestore = append(filesToBackup, "portainer.db")
// 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 portainer.DataStore, shutdownTrigger context.CancelFunc) error {
var err error
if password != "" {
archive, err = decrypt(archive, password)
if err != nil {
return errors.Wrap(err, "failed to decrypt the archive")
}
}
restorePath := filepath.Join(filestorePath, "restore", time.Now().Format("20060102150405"))
defer os.RemoveAll(filepath.Dir(restorePath))
err = extractArchive(archive, restorePath)
if err != nil {
return errors.Wrap(err, "cannot extract files from the archive. Please ensure the password is correct and try again")
}
unlock := gate.Lock()
defer unlock()
if err = datastore.Close(); err != nil {
return errors.Wrap(err, "Failed to stop db")
}
if err = restoreFiles(restorePath, filestorePath); err != nil {
return errors.Wrap(err, "failed to restore the system state")
}
shutdownTrigger()
return nil
}
func decrypt(r io.Reader, password string) (io.Reader, error) {
return crypto.AesDecrypt(r, []byte(password))
}
func extractArchive(r io.Reader, destinationDirPath string) error {
return archive.ExtractTarGz(r, destinationDirPath)
}
func restoreFiles(srcDir string, destinationDir string) error {
for _, filename := range filesToRestore {
err := copyPath(filepath.Join(srcDir, filename), destinationDir)
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1 @@
content

View File

@@ -0,0 +1 @@
content

View File

@@ -0,0 +1 @@
content

181
api/bolt/backup.go Normal file
View File

@@ -0,0 +1,181 @@
package bolt
import (
"fmt"
"io/ioutil"
"os"
"path"
"time"
portainer "github.com/portainer/portainer/api"
plog "github.com/portainer/portainer/api/bolt/log"
)
var backupDefaults = struct {
backupDir string
editions []string
databaseFileName string
}{
"backups",
[]string{"CE", "BE", "EE"},
databaseFileName,
}
var backupLog = plog.NewScopedLog("bolt, backup")
//
// Backup Helpers
//
// createBackupFolders create initial folders for backups
func (store *Store) createBackupFolders() {
for _, e := range backupDefaults.editions {
p := path.Join(store.path, backupDefaults.backupDir, e)
if exists, _ := store.fileService.FileExists(p); !exists {
err := os.MkdirAll(p, 0700)
if err != nil {
backupLog.Error("Error while creating backup folders", err)
}
}
}
}
func (store *Store) databasePath() string {
return path.Join(store.path, databaseFileName)
}
func (store *Store) editionBackupDir(edition portainer.SoftwareEdition) string {
return path.Join(store.path, backupDefaults.backupDir, edition.GetEditionLabel())
}
func (store *Store) copyDBFile(from string, to string) error {
backupLog.Info(fmt.Sprintf("Copying db file from %s to %s", from, to))
err := store.fileService.Copy(from, to, true)
if err != nil {
backupLog.Error("Failed", err)
}
return err
}
// BackupOptions provide a helper to inject backup options
type BackupOptions struct {
Edition portainer.SoftwareEdition
Version int
BackupDir string
BackupFileName string
BackupPath string
}
func (store *Store) setupOptions(options *BackupOptions) *BackupOptions {
if options == nil {
options = &BackupOptions{}
}
if options.Edition == 0 {
options.Edition = store.edition()
}
if options.Version == 0 {
options.Version, _ = store.version()
}
if options.BackupDir == "" {
options.BackupDir = store.editionBackupDir(options.Edition)
}
if options.BackupFileName == "" {
options.BackupFileName = fmt.Sprintf("%s.%s.%s", backupDefaults.databaseFileName, fmt.Sprintf("%03d", options.Version), time.Now().Format("20060102150405"))
}
if options.BackupPath == "" {
options.BackupPath = path.Join(options.BackupDir, options.BackupFileName)
}
return options
}
func (store *Store) listEditionBackups(edition portainer.SoftwareEdition) ([]string, error) {
var fileNames = []string{}
files, err := ioutil.ReadDir(store.editionBackupDir(edition))
if err != nil {
backupLog.Error("Error while retrieving backup files", err)
return fileNames, err
}
for _, f := range files {
fileNames = append(fileNames, f.Name())
}
return fileNames, nil
}
func (store *Store) lastestEditionBackup() (string, error) {
edition := store.edition()
files, err := store.listEditionBackups(edition)
if err != nil {
backupLog.Error("Error while retrieving backup files", err)
return "", err
}
if len(files) == 0 {
return "", nil
}
return files[len(files)-1], nil
}
// BackupWithOptions backup current database with options
func (store *Store) BackupWithOptions(options *BackupOptions) (string, error) {
backupLog.Info("creating db backup")
store.createBackupFolders()
options = store.setupOptions(options)
return options.BackupPath, store.copyDBFile(store.databasePath(), options.BackupPath)
}
// Backup current database with default options
func (store *Store) Backup() (string, error) {
return store.BackupWithOptions(nil)
}
// RestoreWithOptions previously saved backup for the current Edition with options
// Restore strategies:
// - default: restore latest from current edition
// - restore a specific
func (store *Store) RestoreWithOptions(options *BackupOptions) error {
// Check if backup file exist before restoring
options = store.setupOptions(options)
_, err := os.Stat(options.BackupPath)
if os.IsNotExist(err) {
backupLog.Error(fmt.Sprintf("Backup file to restore does not exist %s", options.BackupPath), err)
return err
}
err = store.Close()
if err != nil {
backupLog.Error("Error while closing store before restore", err)
return err
}
backupLog.Info("Restoring db backup")
err = store.copyDBFile(options.BackupPath, store.databasePath())
if err != nil {
return err
}
return store.Open()
}
// Restore previously saved backup for the current Edition with default options
func (store *Store) Restore() error {
var options = &BackupOptions{}
var err error
options.BackupFileName, err = store.lastestEditionBackup()
if err != nil {
return err
}
return store.RestoreWithOptions(options)
}

118
api/bolt/backup_test.go Normal file
View File

@@ -0,0 +1,118 @@
package bolt
import (
"fmt"
"log"
"testing"
portainer "github.com/portainer/portainer/api"
)
func TestCreateBackupFolders(t *testing.T) {
store := NewTestStore(portainer.PortainerEE, portainer.DBVersionEE, false)
if exists, _ := store.fileService.FileExists("tmp/backups"); exists {
t.Error("Expect backups folder to not exist")
}
store.createBackupFolders()
if exists, _ := store.fileService.FileExists("tmp/backups"); !exists {
t.Error("Expect backups folder to exist")
}
store.createBackupFolders()
store.Close()
teardown()
}
func TestStoreCreation(t *testing.T) {
store := NewTestStore(portainer.PortainerEE, portainer.DBVersionEE, false)
if store == nil {
t.Error("Expect to create a store")
}
if store.edition() != portainer.PortainerEE {
t.Error("Expect to get EE Edition")
}
version, err := store.version()
if err != nil {
log.Fatal(err)
}
if version != portainer.DBVersionEE {
t.Error("Expect to get EE DBVersion")
}
store.Close()
teardown()
}
func TestBackup(t *testing.T) {
tests := []struct {
edition portainer.SoftwareEdition
version int
}{
{edition: portainer.PortainerCE, version: portainer.DBVersion},
{edition: portainer.PortainerEE, version: portainer.DBVersionEE},
}
for _, tc := range tests {
backupFileName := fmt.Sprintf("tmp/backups/%s/portainer.db.%03d.*", tc.edition.GetEditionLabel(), tc.version)
t.Run(fmt.Sprintf("Backup should create %s", backupFileName), func(t *testing.T) {
store := NewTestStore(tc.edition, tc.version, false)
store.Backup()
if !isFileExist(backupFileName) {
t.Errorf("Expect backup file to be created %s", backupFileName)
}
store.Close()
})
}
t.Run("BackupWithOption should create a name specific backup", func(t *testing.T) {
edition := portainer.PortainerCE
version := portainer.DBVersion
store := NewTestStore(edition, version, false)
store.BackupWithOptions(&BackupOptions{
BackupFileName: beforePortainerUpgradeToEEBackup,
Edition: portainer.PortainerCE,
})
backupFileName := fmt.Sprintf("tmp/backups/%s/%s", edition.GetEditionLabel(), beforePortainerUpgradeToEEBackup)
if !isFileExist(backupFileName) {
t.Errorf("Expect backup file to be created %s", backupFileName)
}
store.Close()
})
teardown()
}
// TODO restore / backup failed test cases
func TestRestore(t *testing.T) {
editions := []portainer.SoftwareEdition{portainer.PortainerCE, portainer.PortainerEE}
var currentVersion = 0
for i, e := range editions {
editionLabel := e.GetEditionLabel()
currentVersion = 10 ^ i + 1
store := NewTestStore(e, currentVersion, false)
t.Run(fmt.Sprintf("Basic Restore for %s", editionLabel), func(t *testing.T) {
store.Backup()
updateVersion(store, currentVersion+1)
testVersion(store, currentVersion+1, t)
store.Restore()
testVersion(store, currentVersion, t)
})
t.Run(fmt.Sprintf("Basic Restore After Multiple Backup for %s", editionLabel), func(t *testing.T) {
currentVersion = currentVersion + 5
updateVersion(store, currentVersion)
store.Backup()
updateVersion(store, currentVersion+2)
testVersion(store, currentVersion+2, t)
store.Restore()
testVersion(store, currentVersion, t)
})
store.Close()
}
teardown()
}

View File

@@ -0,0 +1,73 @@
package bolttest
import (
"io/ioutil"
"log"
"os"
"github.com/pkg/errors"
"github.com/portainer/portainer/api/bolt"
"github.com/portainer/portainer/api/filesystem"
)
var errTempDir = errors.New("can't create a temp dir")
func MustNewTestStore(init bool) (*bolt.Store, func()) {
store, teardown, err := NewTestStore(init)
if err != nil {
if !errors.Is(err, errTempDir) {
teardown()
}
log.Fatal(err)
}
return store, teardown
}
func NewTestStore(init bool) (*bolt.Store, func(), error) {
// Creates unique temp directory in a concurrency friendly manner.
dataStorePath, err := ioutil.TempDir("", "boltdb")
if err != nil {
return nil, nil, errors.Wrap(errTempDir, err.Error())
}
fileService, err := filesystem.NewService(dataStorePath, "")
if err != nil {
return nil, nil, err
}
store, err := bolt.NewStore(dataStorePath, fileService)
if err != nil {
return nil, nil, err
}
err = store.Open()
if err != nil {
return nil, nil, err
}
if init {
err = store.Init()
if err != nil {
return nil, nil, err
}
}
teardown := func() {
teardown(store, dataStorePath)
}
return store, teardown, nil
}
func teardown(store *bolt.Store, dataStorePath string) {
err := store.Close()
if err != nil {
log.Fatalln(err)
}
err = os.RemoveAll(dataStorePath)
if err != nil {
log.Fatalln(err)
}
}

View File

@@ -0,0 +1,96 @@
package customtemplate
import (
"github.com/boltdb/bolt"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
)
const (
// BucketName represents the name of the bucket where this service stores data.
BucketName = "customtemplates"
)
// Service represents a service for managing custom template data.
type Service struct {
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
connection: connection,
}, nil
}
// CustomTemplates return an array containing all the custom templates.
func (service *Service) CustomTemplates() ([]portainer.CustomTemplate, error) {
var customTemplates = make([]portainer.CustomTemplate, 0)
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
var customTemplate portainer.CustomTemplate
err := internal.UnmarshalObjectWithJsoniter(v, &customTemplate)
if err != nil {
return err
}
customTemplates = append(customTemplates, customTemplate)
}
return nil
})
return customTemplates, err
}
// CustomTemplate returns an custom template by ID.
func (service *Service) CustomTemplate(ID portainer.CustomTemplateID) (*portainer.CustomTemplate, error) {
var customTemplate portainer.CustomTemplate
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.connection, BucketName, identifier, &customTemplate)
if err != nil {
return nil, err
}
return &customTemplate, nil
}
// UpdateCustomTemplate updates an custom template.
func (service *Service) UpdateCustomTemplate(ID portainer.CustomTemplateID, customTemplate *portainer.CustomTemplate) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.connection, BucketName, identifier, customTemplate)
}
// DeleteCustomTemplate deletes an custom template.
func (service *Service) DeleteCustomTemplate(ID portainer.CustomTemplateID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.connection, BucketName, identifier)
}
// CreateCustomTemplate assign an ID to a new custom template and saves it.
func (service *Service) CreateCustomTemplate(customTemplate *portainer.CustomTemplate) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
data, err := internal.MarshalObject(customTemplate)
if err != nil {
return err
}
return bucket.Put(internal.Itob(int(customTemplate.ID)), data)
})
}
// GetNextIdentifier returns the next identifier for a custom template.
func (service *Service) GetNextIdentifier() int {
return internal.GetNextIdentifier(service.connection, BucketName)
}

View File

@@ -1,54 +1,92 @@
package bolt
import (
"log"
"io"
"path"
"time"
"github.com/portainer/portainer/api/bolt/errors"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/portainer/portainer/api/bolt/license"
"github.com/portainer/portainer/api/bolt/s3backup"
"github.com/boltdb/bolt"
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/dockerhub"
"github.com/portainer/portainer/bolt/endpoint"
"github.com/portainer/portainer/bolt/endpointgroup"
"github.com/portainer/portainer/bolt/migrator"
"github.com/portainer/portainer/bolt/registry"
"github.com/portainer/portainer/bolt/resourcecontrol"
"github.com/portainer/portainer/bolt/settings"
"github.com/portainer/portainer/bolt/stack"
"github.com/portainer/portainer/bolt/tag"
"github.com/portainer/portainer/bolt/team"
"github.com/portainer/portainer/bolt/teammembership"
"github.com/portainer/portainer/bolt/template"
"github.com/portainer/portainer/bolt/user"
"github.com/portainer/portainer/bolt/version"
"github.com/portainer/portainer/bolt/webhook"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/customtemplate"
"github.com/portainer/portainer/api/bolt/dockerhub"
"github.com/portainer/portainer/api/bolt/edgegroup"
"github.com/portainer/portainer/api/bolt/edgejob"
"github.com/portainer/portainer/api/bolt/edgestack"
"github.com/portainer/portainer/api/bolt/endpoint"
"github.com/portainer/portainer/api/bolt/endpointgroup"
"github.com/portainer/portainer/api/bolt/endpointrelation"
"github.com/portainer/portainer/api/bolt/extension"
"github.com/portainer/portainer/api/bolt/registry"
"github.com/portainer/portainer/api/bolt/resourcecontrol"
"github.com/portainer/portainer/api/bolt/role"
"github.com/portainer/portainer/api/bolt/schedule"
"github.com/portainer/portainer/api/bolt/settings"
"github.com/portainer/portainer/api/bolt/stack"
"github.com/portainer/portainer/api/bolt/tag"
"github.com/portainer/portainer/api/bolt/team"
"github.com/portainer/portainer/api/bolt/teammembership"
"github.com/portainer/portainer/api/bolt/tunnelserver"
"github.com/portainer/portainer/api/bolt/user"
"github.com/portainer/portainer/api/bolt/version"
"github.com/portainer/portainer/api/bolt/webhook"
)
const (
var (
databaseFileName = "portainer.db"
)
// Store defines the implementation of portainer.DataStore using
// BoltDB as the storage system.
type Store struct {
path string
db *bolt.DB
checkForDataMigration bool
fileService portainer.FileService
DockerHubService *dockerhub.Service
EndpointGroupService *endpointgroup.Service
EndpointService *endpoint.Service
RegistryService *registry.Service
ResourceControlService *resourcecontrol.Service
SettingsService *settings.Service
StackService *stack.Service
TagService *tag.Service
TeamMembershipService *teammembership.Service
TeamService *team.Service
TemplateService *template.Service
UserService *user.Service
VersionService *version.Service
WebhookService *webhook.Service
path string
connection *internal.DbConnection
isNew bool
fileService portainer.FileService
CustomTemplateService *customtemplate.Service
DockerHubService *dockerhub.Service
EdgeGroupService *edgegroup.Service
EdgeJobService *edgejob.Service
EdgeStackService *edgestack.Service
EndpointGroupService *endpointgroup.Service
EndpointService *endpoint.Service
EndpointRelationService *endpointrelation.Service
ExtensionService *extension.Service
LicenseService *license.Service
RegistryService *registry.Service
ResourceControlService *resourcecontrol.Service
RoleService *role.Service
S3BackupService *s3backup.Service
ScheduleService *schedule.Service
SettingsService *settings.Service
StackService *stack.Service
TagService *tag.Service
TeamMembershipService *teammembership.Service
TeamService *team.Service
TunnelServerService *tunnelserver.Service
UserService *user.Service
VersionService *version.Service
WebhookService *webhook.Service
}
func (store *Store) version() (int, error) {
version, err := store.VersionService.DBVersion()
if err == errors.ErrObjectNotFound {
version = 0
}
return version, err
}
func (store *Store) edition() portainer.SoftwareEdition {
edition, err := store.VersionService.Edition()
if err == errors.ErrObjectNotFound {
edition = portainer.PortainerCE
}
return edition
}
// NewStore initializes a new Store and the associated services
@@ -56,6 +94,8 @@ func NewStore(storePath string, fileService portainer.FileService) (*Store, erro
store := &Store{
path: storePath,
fileService: fileService,
isNew: true,
connection: &internal.DbConnection{},
}
databasePath := path.Join(storePath, databaseFileName)
@@ -64,10 +104,8 @@ func NewStore(storePath string, fileService portainer.FileService) (*Store, erro
return nil, err
}
if !databaseFileExists {
store.checkForDataMigration = false
} else {
store.checkForDataMigration = true
if databaseFileExists {
store.isNew = false
}
return store, nil
@@ -80,165 +118,30 @@ func (store *Store) Open() error {
if err != nil {
return err
}
store.db = db
store.connection.DB = db
return store.initServices()
}
// Init creates the default data set.
func (store *Store) Init() error {
groups, err := store.EndpointGroupService.EndpointGroups()
if err != nil {
return err
}
if len(groups) == 0 {
unassignedGroup := &portainer.EndpointGroup{
Name: "Unassigned",
Description: "Unassigned endpoints",
Labels: []portainer.Pair{},
AuthorizedUsers: []portainer.UserID{},
AuthorizedTeams: []portainer.TeamID{},
Tags: []string{},
}
return store.EndpointGroupService.CreateEndpointGroup(unassignedGroup)
}
return nil
}
// Close closes the BoltDB database.
func (store *Store) Close() error {
if store.db != nil {
return store.db.Close()
if store.connection.DB != nil {
return store.connection.Close()
}
return nil
}
// MigrateData automatically migrate the data based on the DBVersion.
func (store *Store) MigrateData() error {
if !store.checkForDataMigration {
return store.VersionService.StoreDBVersion(portainer.DBVersion)
}
version, err := store.VersionService.DBVersion()
if err == portainer.ErrObjectNotFound {
version = 0
} else if err != nil {
return err
}
if version < portainer.DBVersion {
migratorParams := &migrator.Parameters{
DB: store.db,
DatabaseVersion: version,
EndpointGroupService: store.EndpointGroupService,
EndpointService: store.EndpointService,
ResourceControlService: store.ResourceControlService,
SettingsService: store.SettingsService,
StackService: store.StackService,
UserService: store.UserService,
VersionService: store.VersionService,
FileService: store.fileService,
}
migrator := migrator.NewMigrator(migratorParams)
log.Printf("Migrating database from version %v to %v.\n", version, portainer.DBVersion)
err = migrator.Migrate()
if err != nil {
log.Printf("An error occurred during database migration: %s\n", err)
return err
}
}
return nil
// IsNew returns true if the database was just created and false if it is re-using
// existing data.
func (store *Store) IsNew() bool {
return store.isNew
}
func (store *Store) initServices() error {
dockerhubService, err := dockerhub.NewService(store.db)
if err != nil {
// BackupTo backs up db to a provided writer.
// It does hot backup and doesn't block other database reads and writes
func (store *Store) BackupTo(w io.Writer) error {
return store.connection.View(func(tx *bolt.Tx) error {
_, err := tx.WriteTo(w)
return err
}
store.DockerHubService = dockerhubService
endpointgroupService, err := endpointgroup.NewService(store.db)
if err != nil {
return err
}
store.EndpointGroupService = endpointgroupService
endpointService, err := endpoint.NewService(store.db)
if err != nil {
return err
}
store.EndpointService = endpointService
registryService, err := registry.NewService(store.db)
if err != nil {
return err
}
store.RegistryService = registryService
resourcecontrolService, err := resourcecontrol.NewService(store.db)
if err != nil {
return err
}
store.ResourceControlService = resourcecontrolService
settingsService, err := settings.NewService(store.db)
if err != nil {
return err
}
store.SettingsService = settingsService
stackService, err := stack.NewService(store.db)
if err != nil {
return err
}
store.StackService = stackService
tagService, err := tag.NewService(store.db)
if err != nil {
return err
}
store.TagService = tagService
teammembershipService, err := teammembership.NewService(store.db)
if err != nil {
return err
}
store.TeamMembershipService = teammembershipService
teamService, err := team.NewService(store.db)
if err != nil {
return err
}
store.TeamService = teamService
templateService, err := template.NewService(store.db)
if err != nil {
return err
}
store.TemplateService = templateService
userService, err := user.NewService(store.db)
if err != nil {
return err
}
store.UserService = userService
versionService, err := version.NewService(store.db)
if err != nil {
return err
}
store.VersionService = versionService
webhookService, err := webhook.NewService(store.db)
if err != nil {
return err
}
store.WebhookService = webhookService
return nil
})
}

View File

@@ -1,10 +1,8 @@
package dockerhub
import (
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
"github.com/boltdb/bolt"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
)
const (
@@ -15,18 +13,18 @@ const (
// Service represents a service for managing Dockerhub data.
type Service struct {
db *bolt.DB
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(db *bolt.DB) (*Service, error) {
err := internal.CreateBucket(db, BucketName)
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
db: db,
connection: connection,
}, nil
}
@@ -34,7 +32,7 @@ func NewService(db *bolt.DB) (*Service, error) {
func (service *Service) DockerHub() (*portainer.DockerHub, error) {
var dockerhub portainer.DockerHub
err := internal.GetObject(service.db, BucketName, []byte(dockerHubKey), &dockerhub)
err := internal.GetObject(service.connection, BucketName, []byte(dockerHubKey), &dockerhub)
if err != nil {
return nil, err
}
@@ -44,5 +42,5 @@ func (service *Service) DockerHub() (*portainer.DockerHub, error) {
// UpdateDockerHub updates a DockerHub object.
func (service *Service) UpdateDockerHub(dockerhub *portainer.DockerHub) error {
return internal.UpdateObject(service.db, BucketName, []byte(dockerHubKey), dockerhub)
return internal.UpdateObject(service.connection, BucketName, []byte(dockerHubKey), dockerhub)
}

View File

@@ -0,0 +1,94 @@
package edgegroup
import (
"github.com/boltdb/bolt"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
)
const (
// BucketName represents the name of the bucket where this service stores data.
BucketName = "edgegroups"
)
// Service represents a service for managing Edge group data.
type Service struct {
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
connection: connection,
}, nil
}
// EdgeGroups return an array containing all the Edge groups.
func (service *Service) EdgeGroups() ([]portainer.EdgeGroup, error) {
var groups = make([]portainer.EdgeGroup, 0)
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
var group portainer.EdgeGroup
err := internal.UnmarshalObjectWithJsoniter(v, &group)
if err != nil {
return err
}
groups = append(groups, group)
}
return nil
})
return groups, err
}
// EdgeGroup returns an Edge group by ID.
func (service *Service) EdgeGroup(ID portainer.EdgeGroupID) (*portainer.EdgeGroup, error) {
var group portainer.EdgeGroup
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.connection, BucketName, identifier, &group)
if err != nil {
return nil, err
}
return &group, nil
}
// UpdateEdgeGroup updates an Edge group.
func (service *Service) UpdateEdgeGroup(ID portainer.EdgeGroupID, group *portainer.EdgeGroup) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.connection, BucketName, identifier, group)
}
// DeleteEdgeGroup deletes an Edge group.
func (service *Service) DeleteEdgeGroup(ID portainer.EdgeGroupID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.connection, BucketName, identifier)
}
// CreateEdgeGroup assign an ID to a new Edge group and saves it.
func (service *Service) CreateEdgeGroup(group *portainer.EdgeGroup) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
id, _ := bucket.NextSequence()
group.ID = portainer.EdgeGroupID(id)
data, err := internal.MarshalObject(group)
if err != nil {
return err
}
return bucket.Put(internal.Itob(int(group.ID)), data)
})
}

101
api/bolt/edgejob/edgejob.go Normal file
View File

@@ -0,0 +1,101 @@
package edgejob
import (
"github.com/boltdb/bolt"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
)
const (
// BucketName represents the name of the bucket where this service stores data.
BucketName = "edgejobs"
)
// Service represents a service for managing edge jobs data.
type Service struct {
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
connection: connection,
}, nil
}
// EdgeJobs returns a list of Edge jobs
func (service *Service) EdgeJobs() ([]portainer.EdgeJob, error) {
var edgeJobs = make([]portainer.EdgeJob, 0)
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
var edgeJob portainer.EdgeJob
err := internal.UnmarshalObject(v, &edgeJob)
if err != nil {
return err
}
edgeJobs = append(edgeJobs, edgeJob)
}
return nil
})
return edgeJobs, err
}
// EdgeJob returns an Edge job by ID
func (service *Service) EdgeJob(ID portainer.EdgeJobID) (*portainer.EdgeJob, error) {
var edgeJob portainer.EdgeJob
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.connection, BucketName, identifier, &edgeJob)
if err != nil {
return nil, err
}
return &edgeJob, nil
}
// CreateEdgeJob creates a new Edge job
func (service *Service) CreateEdgeJob(edgeJob *portainer.EdgeJob) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
if edgeJob.ID == 0 {
id, _ := bucket.NextSequence()
edgeJob.ID = portainer.EdgeJobID(id)
}
data, err := internal.MarshalObject(edgeJob)
if err != nil {
return err
}
return bucket.Put(internal.Itob(int(edgeJob.ID)), data)
})
}
// UpdateEdgeJob updates an Edge job by ID
func (service *Service) UpdateEdgeJob(ID portainer.EdgeJobID, edgeJob *portainer.EdgeJob) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.connection, BucketName, identifier, edgeJob)
}
// DeleteEdgeJob deletes an Edge job
func (service *Service) DeleteEdgeJob(ID portainer.EdgeJobID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.connection, BucketName, identifier)
}
// GetNextIdentifier returns the next identifier for an endpoint.
func (service *Service) GetNextIdentifier() int {
return internal.GetNextIdentifier(service.connection, BucketName)
}

View File

@@ -0,0 +1,101 @@
package edgestack
import (
"github.com/boltdb/bolt"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
)
const (
// BucketName represents the name of the bucket where this service stores data.
BucketName = "edge_stack"
)
// Service represents a service for managing Edge stack data.
type Service struct {
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
connection: connection,
}, nil
}
// EdgeStacks returns an array containing all edge stacks
func (service *Service) EdgeStacks() ([]portainer.EdgeStack, error) {
var stacks = make([]portainer.EdgeStack, 0)
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
var stack portainer.EdgeStack
err := internal.UnmarshalObject(v, &stack)
if err != nil {
return err
}
stacks = append(stacks, stack)
}
return nil
})
return stacks, err
}
// EdgeStack returns an Edge stack by ID.
func (service *Service) EdgeStack(ID portainer.EdgeStackID) (*portainer.EdgeStack, error) {
var stack portainer.EdgeStack
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.connection, BucketName, identifier, &stack)
if err != nil {
return nil, err
}
return &stack, nil
}
// CreateEdgeStack assign an ID to a new Edge stack and saves it.
func (service *Service) CreateEdgeStack(edgeStack *portainer.EdgeStack) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
if edgeStack.ID == 0 {
id, _ := bucket.NextSequence()
edgeStack.ID = portainer.EdgeStackID(id)
}
data, err := internal.MarshalObject(edgeStack)
if err != nil {
return err
}
return bucket.Put(internal.Itob(int(edgeStack.ID)), data)
})
}
// UpdateEdgeStack updates an Edge stack.
func (service *Service) UpdateEdgeStack(ID portainer.EdgeStackID, edgeStack *portainer.EdgeStack) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.connection, BucketName, identifier, edgeStack)
}
// DeleteEdgeStack deletes an Edge stack.
func (service *Service) DeleteEdgeStack(ID portainer.EdgeStackID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.connection, BucketName, identifier)
}
// GetNextIdentifier returns the next identifier for an endpoint.
func (service *Service) GetNextIdentifier() int {
return internal.GetNextIdentifier(service.connection, BucketName)
}

View File

@@ -1,10 +1,9 @@
package endpoint
import (
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
"github.com/boltdb/bolt"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
)
const (
@@ -14,18 +13,18 @@ const (
// Service represents a service for managing endpoint data.
type Service struct {
db *bolt.DB
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(db *bolt.DB) (*Service, error) {
err := internal.CreateBucket(db, BucketName)
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
db: db,
connection: connection,
}, nil
}
@@ -34,7 +33,7 @@ func (service *Service) Endpoint(ID portainer.EndpointID) (*portainer.Endpoint,
var endpoint portainer.Endpoint
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.db, BucketName, identifier, &endpoint)
err := internal.GetObject(service.connection, BucketName, identifier, &endpoint)
if err != nil {
return nil, err
}
@@ -45,26 +44,26 @@ func (service *Service) Endpoint(ID portainer.EndpointID) (*portainer.Endpoint,
// UpdateEndpoint updates an endpoint.
func (service *Service) UpdateEndpoint(ID portainer.EndpointID, endpoint *portainer.Endpoint) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.db, BucketName, identifier, endpoint)
return internal.UpdateObject(service.connection, BucketName, identifier, endpoint)
}
// DeleteEndpoint deletes an endpoint.
func (service *Service) DeleteEndpoint(ID portainer.EndpointID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.db, BucketName, identifier)
return internal.DeleteObject(service.connection, BucketName, identifier)
}
// Endpoints return an array containing all the endpoints.
func (service *Service) Endpoints() ([]portainer.Endpoint, error) {
var endpoints = make([]portainer.Endpoint, 0)
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
var endpoint portainer.Endpoint
err := internal.UnmarshalObject(v, &endpoint)
err := internal.UnmarshalObjectWithJsoniter(v, &endpoint)
if err != nil {
return err
}
@@ -79,7 +78,7 @@ func (service *Service) Endpoints() ([]portainer.Endpoint, error) {
// CreateEndpoint assign an ID to a new endpoint and saves it.
func (service *Service) CreateEndpoint(endpoint *portainer.Endpoint) error {
return service.db.Update(func(tx *bolt.Tx) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
// We manually manage sequences for endpoints
@@ -99,12 +98,12 @@ func (service *Service) CreateEndpoint(endpoint *portainer.Endpoint) error {
// GetNextIdentifier returns the next identifier for an endpoint.
func (service *Service) GetNextIdentifier() int {
return internal.GetNextIdentifier(service.db, BucketName)
return internal.GetNextIdentifier(service.connection, BucketName)
}
// Synchronize creates, updates and deletes endpoints inside a single transaction.
func (service *Service) Synchronize(toCreate, toUpdate, toDelete []*portainer.Endpoint) error {
return service.db.Update(func(tx *bolt.Tx) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
for _, endpoint := range toCreate {

View File

@@ -1,8 +1,8 @@
package endpointgroup
import (
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/boltdb/bolt"
)
@@ -14,18 +14,18 @@ const (
// Service represents a service for managing endpoint data.
type Service struct {
db *bolt.DB
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(db *bolt.DB) (*Service, error) {
err := internal.CreateBucket(db, BucketName)
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
db: db,
connection: connection,
}, nil
}
@@ -34,7 +34,7 @@ func (service *Service) EndpointGroup(ID portainer.EndpointGroupID) (*portainer.
var endpointGroup portainer.EndpointGroup
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.db, BucketName, identifier, &endpointGroup)
err := internal.GetObject(service.connection, BucketName, identifier, &endpointGroup)
if err != nil {
return nil, err
}
@@ -45,20 +45,20 @@ func (service *Service) EndpointGroup(ID portainer.EndpointGroupID) (*portainer.
// UpdateEndpointGroup updates an endpoint group.
func (service *Service) UpdateEndpointGroup(ID portainer.EndpointGroupID, endpointGroup *portainer.EndpointGroup) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.db, BucketName, identifier, endpointGroup)
return internal.UpdateObject(service.connection, BucketName, identifier, endpointGroup)
}
// DeleteEndpointGroup deletes an endpoint group.
func (service *Service) DeleteEndpointGroup(ID portainer.EndpointGroupID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.db, BucketName, identifier)
return internal.DeleteObject(service.connection, BucketName, identifier)
}
// EndpointGroups return an array containing all the endpoint groups.
func (service *Service) EndpointGroups() ([]portainer.EndpointGroup, error) {
var endpointGroups = make([]portainer.EndpointGroup, 0)
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -79,7 +79,7 @@ func (service *Service) EndpointGroups() ([]portainer.EndpointGroup, error) {
// CreateEndpointGroup assign an ID to a new endpoint group and saves it.
func (service *Service) CreateEndpointGroup(endpointGroup *portainer.EndpointGroup) error {
return service.db.Update(func(tx *bolt.Tx) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
id, _ := bucket.NextSequence()

View File

@@ -0,0 +1,68 @@
package endpointrelation
import (
"github.com/boltdb/bolt"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
)
const (
// BucketName represents the name of the bucket where this service stores data.
BucketName = "endpoint_relations"
)
// Service represents a service for managing endpoint relation data.
type Service struct {
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
connection: connection,
}, nil
}
// EndpointRelation returns a Endpoint relation object by EndpointID
func (service *Service) EndpointRelation(endpointID portainer.EndpointID) (*portainer.EndpointRelation, error) {
var endpointRelation portainer.EndpointRelation
identifier := internal.Itob(int(endpointID))
err := internal.GetObject(service.connection, BucketName, identifier, &endpointRelation)
if err != nil {
return nil, err
}
return &endpointRelation, nil
}
// CreateEndpointRelation saves endpointRelation
func (service *Service) CreateEndpointRelation(endpointRelation *portainer.EndpointRelation) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
data, err := internal.MarshalObject(endpointRelation)
if err != nil {
return err
}
return bucket.Put(internal.Itob(int(endpointRelation.EndpointID)), data)
})
}
// UpdateEndpointRelation updates an Endpoint relation object
func (service *Service) UpdateEndpointRelation(EndpointID portainer.EndpointID, endpointRelation *portainer.EndpointRelation) error {
identifier := internal.Itob(int(EndpointID))
return internal.UpdateObject(service.connection, BucketName, identifier, endpointRelation)
}
// DeleteEndpointRelation deletes an Endpoint relation object
func (service *Service) DeleteEndpointRelation(EndpointID portainer.EndpointID) error {
identifier := internal.Itob(int(EndpointID))
return internal.DeleteObject(service.connection, BucketName, identifier)
}

View File

@@ -0,0 +1,8 @@
package errors
import "errors"
var (
ErrObjectNotFound = errors.New("Object not found inside the database")
ErrMigrationToCE = errors.New("DB is already on CE edition")
)

View File

@@ -0,0 +1,86 @@
package extension
import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/boltdb/bolt"
)
const (
// BucketName represents the name of the bucket where this service stores data.
BucketName = "extension"
)
// Service represents a service for managing endpoint data.
type Service struct {
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
connection: connection,
}, nil
}
// Extension returns a extension by ID
func (service *Service) Extension(ID portainer.ExtensionID) (*portainer.Extension, error) {
var extension portainer.Extension
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.connection, BucketName, identifier, &extension)
if err != nil {
return nil, err
}
return &extension, nil
}
// Extensions return an array containing all the extensions.
func (service *Service) Extensions() ([]portainer.Extension, error) {
var extensions = make([]portainer.Extension, 0)
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
var extension portainer.Extension
err := internal.UnmarshalObject(v, &extension)
if err != nil {
return err
}
extensions = append(extensions, extension)
}
return nil
})
return extensions, err
}
// Persist persists a extension inside the database.
func (service *Service) Persist(extension *portainer.Extension) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
data, err := internal.MarshalObject(extension)
if err != nil {
return err
}
return bucket.Put(internal.Itob(int(extension.ID)), data)
})
}
// DeleteExtension deletes a Extension.
func (service *Service) DeleteExtension(ID portainer.ExtensionID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.connection, BucketName, identifier)
}

115
api/bolt/helpers_test.go Normal file
View File

@@ -0,0 +1,115 @@
package bolt
import (
"fmt"
"log"
"math/rand"
"os"
"path"
"path/filepath"
"testing"
"time"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/filesystem"
)
var (
dataStorePath string
testBackupPath string
)
func init() {
rand.Seed(time.Now().UnixNano())
databaseFileName = fmt.Sprintf("portainer-%08d.db", rand.Intn(100000000))
pwd, err := os.Getwd()
if err != nil {
log.Println(err)
}
dataStorePath = path.Join(pwd, "tmp")
testBackupPath = path.Join(dataStorePath, "backups")
teardown()
}
func NewTestStore(edition portainer.SoftwareEdition, version int, init bool) *Store {
fileService, err := filesystem.NewService(dataStorePath, "")
if err != nil {
log.Fatal(err)
}
store, err := NewStore(dataStorePath, fileService)
if err != nil {
log.Fatal(err)
}
err = store.Open()
if err != nil {
log.Fatal(err)
}
if init {
err = store.Init()
if err != nil {
log.Fatal(err)
}
}
err = store.VersionService.StoreEdition(edition)
if err != nil {
log.Fatal(err)
}
err = store.VersionService.StoreDBVersion(version)
if err != nil {
log.Fatal(err)
}
return store
}
func teardown() {
err := os.RemoveAll(testBackupPath)
if err != nil {
log.Fatalln(err)
}
files, err := filepath.Glob(path.Join(dataStorePath, "portainer-*.*"))
if err != nil {
log.Fatalln(err)
}
for _, f := range files {
if err := os.Remove(f); err != nil {
log.Fatalln(err)
}
}
}
func isFileExist(path string) bool {
matches, err := filepath.Glob(path)
if err != nil {
return false
}
return len(matches) > 0
}
func updateVersion(store *Store, v int) {
err := store.VersionService.StoreDBVersion(v)
if err != nil {
log.Fatal(err)
}
}
func testVersion(store *Store, versionWant int, t *testing.T) {
if v, _ := store.version(); v != versionWant {
t.Errorf("Expect store version to be %d but was %d", versionWant, v)
}
}
func testEdition(store *Store, editionWant portainer.SoftwareEdition, t *testing.T) {
if e := store.edition(); e != editionWant {
t.Errorf("Expect store edition to be %s but was %s", editionWant.GetEditionLabel(), e.GetEditionLabel())
}
}

112
api/bolt/init.go Normal file
View File

@@ -0,0 +1,112 @@
package bolt
import (
"github.com/gofrs/uuid"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/errors"
)
// Init creates the default data set.
func (store *Store) Init() error {
instanceID, err := store.VersionService.InstanceID()
if err == errors.ErrObjectNotFound {
uid, err := uuid.NewV4()
if err != nil {
return err
}
instanceID = uid.String()
err = store.VersionService.StoreInstanceID(instanceID)
if err != nil {
return err
}
} else if err != nil {
return err
}
_, err = store.SettingsService.Settings()
if err == errors.ErrObjectNotFound {
defaultSettings := &portainer.Settings{
AuthenticationMethod: portainer.AuthenticationInternal,
BlackListedLabels: make([]portainer.Pair, 0),
LDAPSettings: portainer.LDAPSettings{
AnonymousMode: true,
AutoCreateUsers: true,
TLSConfig: portainer.TLSConfiguration{},
URLs: []string{},
SearchSettings: []portainer.LDAPSearchSettings{
portainer.LDAPSearchSettings{},
},
GroupSearchSettings: []portainer.LDAPGroupSearchSettings{
portainer.LDAPGroupSearchSettings{},
},
},
OAuthSettings: portainer.OAuthSettings{
TeamMemberships: portainer.TeamMemberships{
OAuthClaimMappings: make([]portainer.OAuthClaimMappings, 0),
},
},
EdgeAgentCheckinInterval: portainer.DefaultEdgeAgentCheckinIntervalInSeconds,
TemplatesURL: portainer.DefaultTemplatesURL,
UserSessionTimeout: portainer.DefaultUserSessionTimeout,
}
err = store.SettingsService.UpdateSettings(defaultSettings)
if err != nil {
return err
}
} else if err != nil {
return err
}
_, err = store.DockerHubService.DockerHub()
if err == errors.ErrObjectNotFound {
defaultDockerHub := &portainer.DockerHub{
Authentication: false,
Username: "",
Password: "",
}
err := store.DockerHubService.UpdateDockerHub(defaultDockerHub)
if err != nil {
return err
}
} else if err != nil {
return err
}
groups, err := store.EndpointGroupService.EndpointGroups()
if err != nil {
return err
}
if len(groups) == 0 {
unassignedGroup := &portainer.EndpointGroup{
Name: "Unassigned",
Description: "Unassigned endpoints",
Labels: []portainer.Pair{},
UserAccessPolicies: portainer.UserAccessPolicies{},
TeamAccessPolicies: portainer.TeamAccessPolicies{},
TagIDs: []portainer.TagID{},
}
err = store.EndpointGroupService.CreateEndpointGroup(unassignedGroup)
if err != nil {
return err
}
}
roles, err := store.RoleService.Roles()
if err != nil {
return err
}
if len(roles) == 0 {
err := store.RoleService.CreateOrUpdatePredefinedRoles()
if err != nil {
return err
}
}
return nil
}

View File

@@ -4,9 +4,13 @@ import (
"encoding/binary"
"github.com/boltdb/bolt"
"github.com/portainer/portainer"
"github.com/portainer/portainer/api/bolt/errors"
)
type DbConnection struct {
*bolt.DB
}
// Itob returns an 8-byte big endian representation of v.
// This function is typically used for encoding integer IDs to byte slices
// so that they can be used as BoltDB keys.
@@ -17,8 +21,8 @@ func Itob(v int) []byte {
}
// CreateBucket is a generic function used to create a bucket inside a bolt database.
func CreateBucket(db *bolt.DB, bucketName string) error {
return db.Update(func(tx *bolt.Tx) error {
func CreateBucket(connection *DbConnection, bucketName string) error {
return connection.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(bucketName))
if err != nil {
return err
@@ -28,15 +32,15 @@ func CreateBucket(db *bolt.DB, bucketName string) error {
}
// GetObject is a generic function used to retrieve an unmarshalled object from a bolt database.
func GetObject(db *bolt.DB, bucketName string, key []byte, object interface{}) error {
func GetObject(connection *DbConnection, bucketName string, key []byte, object interface{}) error {
var data []byte
err := db.View(func(tx *bolt.Tx) error {
err := connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(bucketName))
value := bucket.Get(key)
if value == nil {
return portainer.ErrObjectNotFound
return errors.ErrObjectNotFound
}
data = make([]byte, len(value))
@@ -52,8 +56,8 @@ func GetObject(db *bolt.DB, bucketName string, key []byte, object interface{}) e
}
// UpdateObject is a generic function used to update an object inside a bolt database.
func UpdateObject(db *bolt.DB, bucketName string, key []byte, object interface{}) error {
return db.Update(func(tx *bolt.Tx) error {
func UpdateObject(connection *DbConnection, bucketName string, key []byte, object interface{}) error {
return connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(bucketName))
data, err := MarshalObject(object)
@@ -71,24 +75,26 @@ func UpdateObject(db *bolt.DB, bucketName string, key []byte, object interface{}
}
// DeleteObject is a generic function used to delete an object inside a bolt database.
func DeleteObject(db *bolt.DB, bucketName string, key []byte) error {
return db.Update(func(tx *bolt.Tx) error {
func DeleteObject(connection *DbConnection, bucketName string, key []byte) error {
return connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(bucketName))
return bucket.Delete(key)
})
}
// GetNextIdentifier is a generic function that returns the specified bucket identifier incremented by 1.
func GetNextIdentifier(db *bolt.DB, bucketName string) int {
func GetNextIdentifier(connection *DbConnection, bucketName string) int {
var identifier int
db.View(func(tx *bolt.Tx) error {
connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(bucketName))
id := bucket.Sequence()
id, err := bucket.NextSequence()
if err != nil {
return err
}
identifier = int(id)
return nil
})
identifier++
return identifier
}

View File

@@ -2,6 +2,8 @@ package internal
import (
"encoding/json"
jsoniter "github.com/json-iterator/go"
)
// MarshalObject encodes an object to binary format
@@ -13,3 +15,11 @@ func MarshalObject(object interface{}) ([]byte, error) {
func UnmarshalObject(data []byte, object interface{}) error {
return json.Unmarshal(data, object)
}
// UnmarshalObjectWithJsoniter decodes an object from binary data
// using the jsoniter library. It is mainly used to accelerate endpoint
// decoding at the moment.
func UnmarshalObjectWithJsoniter(data []byte, object interface{}) error {
var jsoni = jsoniter.ConfigCompatibleWithStandardLibrary
return jsoni.Unmarshal(data, &object)
}

View File

@@ -0,0 +1,92 @@
package license
import (
"github.com/portainer/liblicense"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/boltdb/bolt"
)
const (
// BucketName represents the name of the bucket where this service stores data.
BucketName = "license"
)
// Service represents a service for managing endpoint data.
type Service struct {
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
connection: connection,
}, nil
}
// License returns a license by licenseKey
func (service *Service) License(licenseKey string) (*liblicense.PortainerLicense, error) {
var license liblicense.PortainerLicense
identifier := []byte(licenseKey)
err := internal.GetObject(service.connection, BucketName, identifier, &license)
if err != nil {
return nil, err
}
return &license, nil
}
// Licenses return an array containing all the licenses.
func (service *Service) Licenses() ([]liblicense.PortainerLicense, error) {
var licenses = make([]liblicense.PortainerLicense, 0)
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
var license liblicense.PortainerLicense
err := internal.UnmarshalObject(v, &license)
if err != nil {
return err
}
licenses = append(licenses, license)
}
return nil
})
return licenses, err
}
// AddLicense persists a license inside the database.
func (service *Service) AddLicense(licenseKey string, license *liblicense.PortainerLicense) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
data, err := internal.MarshalObject(license)
if err != nil {
return err
}
return bucket.Put([]byte(licenseKey), data)
})
}
// UpdateLicense updates a license.
func (service *Service) UpdateLicense(licenseKey string, license *liblicense.PortainerLicense) error {
identifier := []byte(licenseKey)
return internal.UpdateObject(service.connection, BucketName, identifier, license)
}
// DeleteLicense deletes a License.
func (service *Service) DeleteLicense(licenseKey string) error {
identifier := []byte(licenseKey)
return internal.DeleteObject(service.connection, BucketName, identifier)
}

41
api/bolt/log/log.go Normal file
View File

@@ -0,0 +1,41 @@
package log
import (
"fmt"
"log"
)
const (
INFO = "INFO"
ERROR = "ERROR"
DEBUG = "DEBUG"
FATAL = "FATAL"
)
type ScopedLog struct {
scope string
}
func NewScopedLog(scope string) *ScopedLog {
return &ScopedLog{scope: scope}
}
func (slog *ScopedLog) print(kind string, message string) {
log.Printf("[%s] [%s] %s", kind, slog.scope, message)
}
func (slog *ScopedLog) Debug(message string) {
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) Error(message string, err error) {
slog.print(ERROR, fmt.Sprintf("[message: %s] [error: %s]", message, err))
}
func (slog *ScopedLog) NotImplemented(method string) {
log.Fatalf("[%s] [%s] [%s]", FATAL, slog.scope, fmt.Sprintf("%s is not yet implemented", method))
}

1
api/bolt/log/log.test.go Normal file
View File

@@ -0,0 +1 @@
package log

207
api/bolt/migrate_data.go Normal file
View File

@@ -0,0 +1,207 @@
package bolt
import (
"fmt"
portainer "github.com/portainer/portainer/api"
errors "github.com/portainer/portainer/api/bolt/errors"
plog "github.com/portainer/portainer/api/bolt/log"
"github.com/portainer/portainer/api/bolt/migrator"
"github.com/portainer/portainer/api/cli"
"github.com/portainer/portainer/api/internal/authorization"
)
const beforePortainerUpgradeToEEBackup = "portainer.db.before-EE-upgrade"
var migrateLog = plog.NewScopedLog("bolt, migrate")
// FailSafeMigrate backup and restore DB if migration fail
func (store *Store) FailSafeMigrate(migrator *migrator.Migrator, version int) error {
defer func() {
if err := recover(); err != nil {
migrateLog.Info(fmt.Sprintf("Error during migration, recovering [%v]", err))
store.Restore()
}
}()
return migrator.Migrate(version)
}
// MigrateData automatically migrate the data based on the DBVersion.
// This process is only triggered on an existing database, not if the database was just created.
// if force is true, then migrate regardless.
func (store *Store) MigrateData(force bool) error {
// 0 if DB is new then we don't need to migrate any data and just set version and edition to latest EE
if store.isNew && !force {
err := store.VersionService.StoreDBVersion(portainer.DBVersionEE)
if err != nil {
return err
}
err = store.VersionService.StoreEdition(portainer.PortainerEE)
if err != nil {
return err
}
return nil
}
migrator, err := store.newMigrator()
if err != nil {
return err
}
if migrator.Edition() == portainer.PortainerCE {
// backup before migrating
store.BackupWithOptions(&BackupOptions{
BackupFileName: beforePortainerUpgradeToEEBackup,
Edition: portainer.PortainerCE,
})
store.VersionService.StorePreviousDBVersion(migrator.Version())
// 1 We need to migrate DB to latest CE version
if migrator.Version() < portainer.DBVersion {
store.Backup()
err = store.FailSafeMigrate(migrator, portainer.DBVersion)
if err != nil {
store.Restore()
migrateLog.Error("An error occurred while migrating CE database to latest version", err)
return err
}
}
}
if portainer.Edition == portainer.PortainerEE {
// 2 if DB is CE Edition we need to upgrade settings to EE
if migrator.Edition() < portainer.PortainerEE {
err = migrator.UpgradeToEE()
if err != nil {
migrateLog.Error("An error occurred while upgrading database to EE", err)
store.RollbackFailedUpgradeToEE()
return err
}
}
// 3 if DB is EE Edition we need to migrate to latest version of EE
if migrator.Edition() == portainer.PortainerEE && migrator.Version() < portainer.DBVersionEE {
store.Backup()
err = store.FailSafeMigrate(migrator, portainer.DBVersionEE)
if err != nil {
migrateLog.Error("An error occurred while migrating EE database to latest version", err)
store.Restore()
return err
}
}
}
return nil
}
// RollbackFailedUpgradeToEE down migrate to previous version
func (store *Store) RollbackFailedUpgradeToEE() error {
return store.RestoreWithOptions(&BackupOptions{
BackupFileName: beforePortainerUpgradeToEEBackup,
Edition: portainer.PortainerCE,
})
}
// RollbackToCE rollbacks the store to the current ce version
func (store *Store) RollbackToCE() error {
migrator, err := store.newMigrator()
if err != nil {
return err
}
migrateLog.Info(fmt.Sprintf("Current Software Edition: %s", migrator.Edition().GetEditionLabel()))
migrateLog.Info(fmt.Sprintf("Current DB Version: %d", migrator.Version()))
if migrator.Edition() == portainer.PortainerCE {
return errors.ErrMigrationToCE
}
previousVersion, err := store.VersionService.PreviousDBVersion()
if err != nil {
migrateLog.Error("An Error occurred with retrieving previous DB version", err)
return err
}
confirmed, err := cli.Confirm(fmt.Sprintf("Are you sure you want to rollback your database to %d?", previousVersion))
if err != nil || !confirmed {
return err
}
if previousVersion < 25 {
migrator.DowngradeSettingsFrom25()
}
err = store.VersionService.StoreDBVersion(previousVersion)
if err != nil {
migrateLog.Error(fmt.Sprintf("An Error occurred with rolling back to CE Edition, DB Version %d", previousVersion), err)
return err
}
err = store.VersionService.StoreEdition(portainer.PortainerCE)
if err != nil {
migrateLog.Error(fmt.Sprintf("An Error occurred with rolling back to CE Edition, DB Version %d", previousVersion), err)
return err
}
migrateLog.Info(fmt.Sprintf("Rolled back to CE Edition, DB Version %d", previousVersion))
return nil
}
func (store *Store) newMigrator() (*migrator.Migrator, error) {
version, err := store.version()
if err != nil {
return nil, err
}
edition := store.edition()
params := &migrator.Parameters{
DB: store.connection.DB,
DatabaseVersion: version,
CurrentEdition: edition,
EndpointGroupService: store.EndpointGroupService,
EndpointService: store.EndpointService,
EndpointRelationService: store.EndpointRelationService,
ExtensionService: store.ExtensionService,
RegistryService: store.RegistryService,
ResourceControlService: store.ResourceControlService,
RoleService: store.RoleService,
ScheduleService: store.ScheduleService,
SettingsService: store.SettingsService,
StackService: store.StackService,
TagService: store.TagService,
TeamMembershipService: store.TeamMembershipService,
UserService: store.UserService,
VersionService: store.VersionService,
FileService: store.fileService,
AuthorizationService: authorization.NewService(store),
}
return migrator.NewMigrator(params), nil
}
// RollbackVersion down migrate to previous version
func (store *Store) RollbackVersion(version int) error {
// TODO
backupLog.NotImplemented("RollbackVersion")
return nil
}
// RollbackEdition downgrade to previous edition
func (store *Store) RollbackEdition(edition portainer.SoftwareEdition) error {
// TODO
backupLog.NotImplemented("RollbackEdition")
// Change Edition
// Migrate Services
// Restore Latest
return nil
}

View File

@@ -0,0 +1,99 @@
package bolt
import (
"fmt"
"log"
"testing"
"github.com/boltdb/bolt"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/filesystem"
)
// New Database should be EE and DBVersion
//
func TestMigrateData(t *testing.T) {
var store *Store
t.Run("MigrateData for New Store", func(t *testing.T) {
fileService, err := filesystem.NewService(dataStorePath, "")
if err != nil {
log.Fatal(err)
}
store, err := NewStore(dataStorePath, fileService)
if err != nil {
log.Fatal(err)
}
err = store.Open()
if err != nil {
log.Fatal(err)
}
err = store.Init()
if err != nil {
log.Fatal(err)
}
store.MigrateData(false)
testVersion(store, portainer.DBVersionEE, t)
testEdition(store, portainer.PortainerEE, t)
store.Close()
})
tests := []struct {
edition portainer.SoftwareEdition
version int
expectedVersion int
}{
{edition: portainer.PortainerCE, version: 5, expectedVersion: portainer.DBVersionEE},
{edition: portainer.PortainerCE, version: 21, expectedVersion: portainer.DBVersionEE},
}
for _, tc := range tests {
store = NewTestStore(tc.edition, tc.version, true)
t.Run(fmt.Sprintf("MigrateData for %s version %d", tc.edition.GetEditionLabel(), tc.version), func(t *testing.T) {
store.MigrateData(false)
testVersion(store, tc.expectedVersion, t)
testEdition(store, portainer.PortainerEE, t)
})
t.Run(fmt.Sprintf("Restoring DB after migrateData for %s version %d", tc.edition.GetEditionLabel(), tc.version), func(t *testing.T) {
store.RollbackToCE()
testVersion(store, tc.version, t)
testEdition(store, tc.edition, t)
})
store.Close()
}
t.Run("Error in MigrateData should restore backup before MigrateData", func(t *testing.T) {
version := 21
store = NewTestStore(portainer.PortainerCE, version, true)
deleteBucket(store.connection.DB, "settings")
store.MigrateData(false)
testVersion(store, version, t)
testEdition(store, portainer.PortainerCE, t)
store.Close()
})
teardown()
}
func deleteBucket(db *bolt.DB, bucketName string) {
db.Update(func(tx *bolt.Tx) error {
log.Printf("Delete bucket %s\n", bucketName)
err := tx.DeleteBucket([]byte(bucketName))
if err != nil {
log.Println(err)
}
return err
})
}

View File

@@ -0,0 +1,15 @@
package migrator
// DowngradeSettingsFrom25 downgrade template settings for portainer v1.2
func (migrator *Migrator) DowngradeSettingsFrom25() error {
legacySettings, err := migrator.settingsService.Settings()
if err != nil {
return err
}
legacySettings.TemplatesURL = "https://raw.githubusercontent.com/portainer/templates/master/templates-1.20.0.json"
err = migrator.settingsService.UpdateSettings(legacySettings)
return err
}

View File

@@ -0,0 +1,308 @@
package migrator
import (
"log"
portainer "github.com/portainer/portainer/api"
)
// MigrateCE checks the database version and migrate the existing data to the most recent data model.
func (m *Migrator) MigrateCE() error {
// Portainer < 1.12
if m.currentDBVersion < 1 {
err := m.updateAdminUserToDBVersion1()
if err != nil {
return err
}
}
// Portainer 1.12.x
if m.currentDBVersion < 2 {
err := m.updateResourceControlsToDBVersion2()
if err != nil {
return err
}
err = m.updateEndpointsToDBVersion2()
if err != nil {
return err
}
}
// Portainer 1.13.x
if m.currentDBVersion < 3 {
err := m.updateSettingsToDBVersion3()
if err != nil {
return err
}
}
// Portainer 1.14.0
if m.currentDBVersion < 4 {
err := m.updateEndpointsToDBVersion4()
if err != nil {
return err
}
}
// https://github.com/portainer/portainer/issues/1235
if m.currentDBVersion < 5 {
err := m.updateSettingsToVersion5()
if err != nil {
return err
}
}
// https://github.com/portainer/portainer/issues/1236
if m.currentDBVersion < 6 {
err := m.updateSettingsToVersion6()
if err != nil {
return err
}
}
// https://github.com/portainer/portainer/issues/1449
if m.currentDBVersion < 7 {
err := m.updateSettingsToVersion7()
if err != nil {
return err
}
}
if m.currentDBVersion < 8 {
err := m.updateEndpointsToVersion8()
if err != nil {
return err
}
}
// https: //github.com/portainer/portainer/issues/1396
if m.currentDBVersion < 9 {
err := m.updateEndpointsToVersion9()
if err != nil {
return err
}
}
// https://github.com/portainer/portainer/issues/461
if m.currentDBVersion < 10 {
err := m.updateEndpointsToVersion10()
if err != nil {
return err
}
}
// https://github.com/portainer/portainer/issues/1906
if m.currentDBVersion < 11 {
err := m.updateEndpointsToVersion11()
if err != nil {
return err
}
}
// Portainer 1.18.0
if m.currentDBVersion < 12 {
err := m.updateEndpointsToVersion12()
if err != nil {
return err
}
err = m.updateEndpointGroupsToVersion12()
if err != nil {
return err
}
err = m.updateStacksToVersion12()
if err != nil {
return err
}
}
// Portainer 1.19.0
if m.currentDBVersion < 13 {
err := m.updateSettingsToVersion13()
if err != nil {
return err
}
}
// Portainer 1.19.2
if m.currentDBVersion < 14 {
err := m.updateResourceControlsToDBVersion14()
if err != nil {
return err
}
}
// Portainer 1.20.0
if m.currentDBVersion < 15 {
err := m.updateSettingsToDBVersion15()
if err != nil {
return err
}
err = m.updateTemplatesToVersion15()
if err != nil {
return err
}
}
if m.currentDBVersion < 16 {
err := m.updateSettingsToDBVersion16()
if err != nil {
return err
}
}
// Portainer 1.20.1
if m.currentDBVersion < 17 {
err := m.updateExtensionsToDBVersion17()
if err != nil {
return err
}
}
// Portainer 1.21.0
if m.currentDBVersion < 18 {
err := m.updateUsersToDBVersion18()
if err != nil {
return err
}
err = m.updateEndpointsToDBVersion18()
if err != nil {
return err
}
err = m.updateEndpointGroupsToDBVersion18()
if err != nil {
return err
}
err = m.updateRegistriesToDBVersion18()
if err != nil {
return err
}
}
// Portainer 1.22.0
if m.currentDBVersion < 19 {
err := m.updateSettingsToDBVersion19()
if err != nil {
return err
}
}
// Portainer 1.22.1
if m.currentDBVersion < 20 {
err := m.updateUsersToDBVersion20()
if err != nil {
return err
}
err = m.updateSettingsToDBVersion20()
if err != nil {
return err
}
err = m.updateSchedulesToDBVersion20()
if err != nil {
return err
}
}
// 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 err
}
err = m.updateUsersAndRolesToDBVersion22()
if err != nil {
return err
}
}
// Portainer 1.24.0
if m.currentDBVersion < 23 {
err := m.updateTagsToDBVersion23()
if err != nil {
return err
}
err = m.updateEndpointsAndEndpointGroupsToDBVersion23()
if err != nil {
return err
}
}
// Portainer 1.24.1
if m.currentDBVersion < 24 {
err := m.updateSettingsToDB24()
if err != nil {
return err
}
}
// Portainer 2.0.0
if m.currentDBVersion < 25 {
err := m.updateSettingsToDB25()
if err != nil {
return err
}
err = m.updateStacksToDB24()
if err != nil {
return err
}
}
// Portainer 2.1.0
if m.currentDBVersion < 26 {
err := m.updateEndpointSettingsToDB26()
if err != nil {
return err
}
err = m.updateRbacRolesToDB26()
if err != nil {
return err
}
}
// Portainer 2.2.0
if m.currentDBVersion < 27 {
err := m.updateStackResourceControlToDB27()
if err != nil {
return err
}
}
// Portainer EE-2.4.0
if m.currentDBVersion < 28 {
err := m.updateUsersAndRolesToDBVersion28()
if err != nil {
return err
}
}
// Portainer EE-2.4.0
if m.currentDBVersion < 29 {
err := m.updateRbacRolesToDB29()
if err != nil {
return err
}
}
// Portainer EE-2.7.0
if m.currentDBVersion < 31 {
err := m.updateSettingsToDB31()
if err != nil {
return err
}
}
log.Println("Update DB version to ", portainer.DBVersion)
return m.versionService.StoreDBVersion(portainer.DBVersion)
}

View File

@@ -2,8 +2,9 @@ package migrator
import (
"github.com/boltdb/bolt"
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/user"
"github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/errors"
"github.com/portainer/portainer/api/bolt/user"
)
func (m *Migrator) updateAdminUserToDBVersion1() error {
@@ -22,7 +23,7 @@ func (m *Migrator) updateAdminUserToDBVersion1() error {
if err != nil {
return err
}
} else if err != nil && err != portainer.ErrObjectNotFound {
} else if err != nil && err != errors.ErrObjectNotFound {
return err
}
return nil

View File

@@ -2,8 +2,8 @@ package migrator
import (
"github.com/boltdb/bolt"
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
"github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
)
func (m *Migrator) updateResourceControlsToDBVersion2() error {

View File

@@ -1,6 +1,6 @@
package migrator
import "github.com/portainer/portainer"
import "github.com/portainer/portainer/api"
func (m *Migrator) updateEndpointsToVersion11() error {
legacyEndpoints, err := m.endpointService.Endpoints()

View File

@@ -5,9 +5,9 @@ import (
"strings"
"github.com/boltdb/bolt"
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
"github.com/portainer/portainer/bolt/stack"
"github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/portainer/portainer/api/bolt/stack"
)
func (m *Migrator) updateEndpointsToVersion12() error {

View File

@@ -1,6 +1,6 @@
package migrator
import "github.com/portainer/portainer"
import "github.com/portainer/portainer/api"
func (m *Migrator) updateSettingsToVersion13() error {
legacySettings, err := m.settingsService.Settings()

View File

@@ -0,0 +1,16 @@
package migrator
func (m *Migrator) updateSettingsToDBVersion15() error {
legacySettings, err := m.settingsService.Settings()
if err != nil {
return err
}
legacySettings.EnableHostManagementFeatures = false
return m.settingsService.UpdateSettings(legacySettings)
}
func (m *Migrator) updateTemplatesToVersion15() error {
// Removed with the entire template management layer, part of https://github.com/portainer/portainer/issues/3707
return nil
}

View File

@@ -0,0 +1,14 @@
package migrator
func (m *Migrator) updateSettingsToDBVersion16() error {
legacySettings, err := m.settingsService.Settings()
if err != nil {
return err
}
if legacySettings.SnapshotInterval == "" {
legacySettings.SnapshotInterval = "5m"
}
return m.settingsService.UpdateSettings(legacySettings)
}

View File

@@ -0,0 +1,19 @@
package migrator
func (m *Migrator) updateExtensionsToDBVersion17() error {
legacyExtensions, err := m.extensionService.Extensions()
if err != nil {
return err
}
for _, extension := range legacyExtensions {
extension.License.Valid = true
err = m.extensionService.Persist(&extension)
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,125 @@
package migrator
import (
portainer "github.com/portainer/portainer/api"
)
func (m *Migrator) updateUsersToDBVersion18() error {
legacyUsers, err := m.userService.Users()
if err != nil {
return err
}
for _, user := range legacyUsers {
user.PortainerAuthorizations = map[portainer.Authorization]bool{
portainer.OperationPortainerDockerHubInspect: true,
portainer.OperationPortainerEndpointGroupList: true,
portainer.OperationPortainerEndpointList: true,
portainer.OperationPortainerEndpointInspect: true,
portainer.OperationPortainerEndpointExtensionAdd: true,
portainer.OperationPortainerEndpointExtensionRemove: true,
portainer.OperationPortainerExtensionList: true,
portainer.OperationPortainerMOTD: true,
portainer.OperationPortainerRegistryList: true,
portainer.OperationPortainerRegistryInspect: true,
portainer.OperationPortainerTeamList: true,
portainer.OperationPortainerTemplateList: true,
portainer.OperationPortainerTemplateInspect: true,
portainer.OperationPortainerUserList: true,
portainer.OperationPortainerUserMemberships: true,
}
err = m.userService.UpdateUser(user.ID, &user)
if err != nil {
return err
}
}
return nil
}
func (m *Migrator) updateEndpointsToDBVersion18() error {
legacyEndpoints, err := m.endpointService.Endpoints()
if err != nil {
return err
}
for _, endpoint := range legacyEndpoints {
endpoint.UserAccessPolicies = make(portainer.UserAccessPolicies)
for _, userID := range endpoint.AuthorizedUsers {
endpoint.UserAccessPolicies[userID] = portainer.AccessPolicy{
RoleID: 4,
}
}
endpoint.TeamAccessPolicies = make(portainer.TeamAccessPolicies)
for _, teamID := range endpoint.AuthorizedTeams {
endpoint.TeamAccessPolicies[teamID] = portainer.AccessPolicy{
RoleID: 4,
}
}
err = m.endpointService.UpdateEndpoint(endpoint.ID, &endpoint)
if err != nil {
return err
}
}
return nil
}
func (m *Migrator) updateEndpointGroupsToDBVersion18() error {
legacyEndpointGroups, err := m.endpointGroupService.EndpointGroups()
if err != nil {
return err
}
for _, endpointGroup := range legacyEndpointGroups {
endpointGroup.UserAccessPolicies = make(portainer.UserAccessPolicies)
for _, userID := range endpointGroup.AuthorizedUsers {
endpointGroup.UserAccessPolicies[userID] = portainer.AccessPolicy{
RoleID: 4,
}
}
endpointGroup.TeamAccessPolicies = make(portainer.TeamAccessPolicies)
for _, teamID := range endpointGroup.AuthorizedTeams {
endpointGroup.TeamAccessPolicies[teamID] = portainer.AccessPolicy{
RoleID: 4,
}
}
err = m.endpointGroupService.UpdateEndpointGroup(endpointGroup.ID, &endpointGroup)
if err != nil {
return err
}
}
return nil
}
func (m *Migrator) updateRegistriesToDBVersion18() error {
legacyRegistries, err := m.registryService.Registries()
if err != nil {
return err
}
for _, registry := range legacyRegistries {
registry.UserAccessPolicies = make(portainer.UserAccessPolicies)
for _, userID := range registry.AuthorizedUsers {
registry.UserAccessPolicies[userID] = portainer.AccessPolicy{}
}
registry.TeamAccessPolicies = make(portainer.TeamAccessPolicies)
for _, teamID := range registry.AuthorizedTeams {
registry.TeamAccessPolicies[teamID] = portainer.AccessPolicy{}
}
err = m.registryService.UpdateRegistry(registry.ID, &registry)
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,16 @@
package migrator
import portainer "github.com/portainer/portainer/api"
func (m *Migrator) updateSettingsToDBVersion19() error {
legacySettings, err := m.settingsService.Settings()
if err != nil {
return err
}
if legacySettings.EdgeAgentCheckinInterval == 0 {
legacySettings.EdgeAgentCheckinInterval = portainer.DefaultEdgeAgentCheckinIntervalInSeconds
}
return m.settingsService.UpdateSettings(legacySettings)
}

View File

@@ -0,0 +1,57 @@
package migrator
import (
"strings"
)
const scheduleScriptExecutionJobType = 1
func (m *Migrator) updateUsersToDBVersion20() error {
return m.authorizationService.UpdateUsersAuthorizations()
}
func (m *Migrator) updateSettingsToDBVersion20() error {
legacySettings, err := m.settingsService.Settings()
if err != nil {
return err
}
legacySettings.AllowVolumeBrowserForRegularUsers = false
return m.settingsService.UpdateSettings(legacySettings)
}
func (m *Migrator) updateSchedulesToDBVersion20() error {
legacySchedules, err := m.scheduleService.Schedules()
if err != nil {
return err
}
for _, schedule := range legacySchedules {
if schedule.JobType == scheduleScriptExecutionJobType {
if schedule.CronExpression == "0 0 * * *" {
schedule.CronExpression = "0 * * * *"
} else if schedule.CronExpression == "0 0 0/2 * *" {
schedule.CronExpression = "0 */2 * * *"
} else if schedule.CronExpression == "0 0 0 * *" {
schedule.CronExpression = "0 0 * * *"
} else {
revisedCronExpression := strings.Split(schedule.CronExpression, " ")
if len(revisedCronExpression) == 5 {
continue
}
revisedCronExpression = revisedCronExpression[1:]
schedule.CronExpression = strings.Join(revisedCronExpression, " ")
}
err := m.scheduleService.UpdateSchedule(schedule.ID, &schedule)
if err != nil {
return err
}
}
}
return nil
}

View File

@@ -1,6 +1,6 @@
package migrator
import "github.com/portainer/portainer"
import "github.com/portainer/portainer/api"
func (m *Migrator) updateSettingsToDBVersion3() error {
legacySettings, err := m.settingsService.Settings()

View File

@@ -0,0 +1,80 @@
package migrator
import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/internal/authorization"
)
func (m *Migrator) updateResourceControlsToDBVersion22() error {
legacyResourceControls, err := m.resourceControlService.ResourceControls()
if err != nil {
return err
}
for _, resourceControl := range legacyResourceControls {
resourceControl.AdministratorsOnly = false
err := m.resourceControlService.UpdateResourceControl(resourceControl.ID, &resourceControl)
if err != nil {
return err
}
}
return nil
}
func (m *Migrator) updateUsersAndRolesToDBVersion22() error {
legacyUsers, err := m.userService.Users()
if err != nil {
return err
}
for _, user := range legacyUsers {
user.PortainerAuthorizations = authorization.DefaultPortainerAuthorizations()
err = m.userService.UpdateUser(user.ID, &user)
if err != nil {
return err
}
}
endpointAdministratorRole, err := m.roleService.Role(portainer.RoleID(1))
if err != nil {
return err
}
endpointAdministratorRole.Priority = 1
endpointAdministratorRole.Authorizations = authorization.DefaultEndpointAuthorizationsForEndpointAdministratorRole()
err = m.roleService.UpdateRole(endpointAdministratorRole.ID, endpointAdministratorRole)
helpDeskRole, err := m.roleService.Role(portainer.RoleID(2))
if err != nil {
return err
}
helpDeskRole.Priority = 2
helpDeskRole.Authorizations = authorization.DefaultEndpointAuthorizationsForHelpDeskRole()
err = m.roleService.UpdateRole(helpDeskRole.ID, helpDeskRole)
standardUserRole, err := m.roleService.Role(portainer.RoleID(3))
if err != nil {
return err
}
standardUserRole.Priority = 3
standardUserRole.Authorizations = authorization.DefaultEndpointAuthorizationsForStandardUserRole()
err = m.roleService.UpdateRole(standardUserRole.ID, standardUserRole)
readOnlyUserRole, err := m.roleService.Role(portainer.RoleID(4))
if err != nil {
return err
}
readOnlyUserRole.Priority = 4
readOnlyUserRole.Authorizations = authorization.DefaultEndpointAuthorizationsForReadOnlyUserRole()
err = m.roleService.UpdateRole(readOnlyUserRole.ID, readOnlyUserRole)
if err != nil {
return err
}
return m.authorizationService.UpdateUsersAuthorizations()
}

View File

@@ -0,0 +1,92 @@
package migrator
import "github.com/portainer/portainer/api"
func (m *Migrator) updateTagsToDBVersion23() error {
tags, err := m.tagService.Tags()
if err != nil {
return err
}
for _, tag := range tags {
tag.EndpointGroups = make(map[portainer.EndpointGroupID]bool)
tag.Endpoints = make(map[portainer.EndpointID]bool)
err = m.tagService.UpdateTag(tag.ID, &tag)
if err != nil {
return err
}
}
return nil
}
func (m *Migrator) updateEndpointsAndEndpointGroupsToDBVersion23() error {
tags, err := m.tagService.Tags()
if err != nil {
return err
}
tagsNameMap := make(map[string]portainer.Tag)
for _, tag := range tags {
tagsNameMap[tag.Name] = tag
}
endpoints, err := m.endpointService.Endpoints()
if err != nil {
return err
}
for _, endpoint := range endpoints {
endpointTags := make([]portainer.TagID, 0)
for _, tagName := range endpoint.Tags {
tag, ok := tagsNameMap[tagName]
if ok {
endpointTags = append(endpointTags, tag.ID)
tag.Endpoints[endpoint.ID] = true
}
}
endpoint.TagIDs = endpointTags
err = m.endpointService.UpdateEndpoint(endpoint.ID, &endpoint)
if err != nil {
return err
}
relation := &portainer.EndpointRelation{
EndpointID: endpoint.ID,
EdgeStacks: map[portainer.EdgeStackID]bool{},
}
err = m.endpointRelationService.CreateEndpointRelation(relation)
if err != nil {
return err
}
}
endpointGroups, err := m.endpointGroupService.EndpointGroups()
if err != nil {
return err
}
for _, endpointGroup := range endpointGroups {
endpointGroupTags := make([]portainer.TagID, 0)
for _, tagName := range endpointGroup.Tags {
tag, ok := tagsNameMap[tagName]
if ok {
endpointGroupTags = append(endpointGroupTags, tag.ID)
tag.EndpointGroups[endpointGroup.ID] = true
}
}
endpointGroup.TagIDs = endpointGroupTags
err = m.endpointGroupService.UpdateEndpointGroup(endpointGroup.ID, &endpointGroup)
if err != nil {
return err
}
}
for _, tag := range tagsNameMap {
err = m.tagService.UpdateTag(tag.ID, &tag)
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,34 @@
package migrator
import portainer "github.com/portainer/portainer/api"
func (m *Migrator) updateSettingsToDB24() error {
legacySettings, err := m.settingsService.Settings()
if err != nil {
return err
}
legacySettings.AllowHostNamespaceForRegularUsers = true
legacySettings.AllowDeviceMappingForRegularUsers = true
legacySettings.AllowStackManagementForRegularUsers = true
return m.settingsService.UpdateSettings(legacySettings)
}
func (m *Migrator) updateStacksToDB24() error {
stacks, err := m.stackService.Stacks()
if err != nil {
return err
}
for idx := range stacks {
stack := &stacks[idx]
stack.Status = portainer.StackStatusActive
err := m.stackService.UpdateStack(stack.ID, stack)
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,23 @@
package migrator
import (
"github.com/portainer/portainer/api"
)
func (m *Migrator) updateSettingsToDB25() error {
legacySettings, err := m.settingsService.Settings()
if err != nil {
return err
}
if legacySettings.TemplatesURL == "" {
legacySettings.TemplatesURL = portainer.DefaultTemplatesURL
}
legacySettings.UserSessionTimeout = portainer.DefaultUserSessionTimeout
legacySettings.EnableTelemetry = true
legacySettings.AllowContainerCapabilitiesForRegularUsers = true
return m.settingsService.UpdateSettings(legacySettings)
}

View File

@@ -0,0 +1,76 @@
package migrator
import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/internal/authorization"
)
func (m *Migrator) updateEndpointSettingsToDB26() error {
settings, err := m.settingsService.Settings()
if err != nil {
return err
}
endpoints, err := m.endpointService.Endpoints()
if err != nil {
return err
}
for i := range endpoints {
endpoint := endpoints[i]
securitySettings := portainer.EndpointSecuritySettings{}
if endpoint.Type == portainer.EdgeAgentOnDockerEnvironment ||
endpoint.Type == portainer.AgentOnDockerEnvironment ||
endpoint.Type == portainer.DockerEnvironment {
securitySettings = portainer.EndpointSecuritySettings{
AllowBindMountsForRegularUsers: settings.AllowBindMountsForRegularUsers,
AllowContainerCapabilitiesForRegularUsers: settings.AllowContainerCapabilitiesForRegularUsers,
AllowDeviceMappingForRegularUsers: settings.AllowDeviceMappingForRegularUsers,
AllowHostNamespaceForRegularUsers: settings.AllowHostNamespaceForRegularUsers,
AllowPrivilegedModeForRegularUsers: settings.AllowPrivilegedModeForRegularUsers,
AllowStackManagementForRegularUsers: settings.AllowStackManagementForRegularUsers,
}
if endpoint.Type == portainer.AgentOnDockerEnvironment || endpoint.Type == portainer.EdgeAgentOnDockerEnvironment {
securitySettings.AllowVolumeBrowserForRegularUsers = settings.AllowVolumeBrowserForRegularUsers
securitySettings.EnableHostManagementFeatures = settings.EnableHostManagementFeatures
}
}
endpoint.SecuritySettings = securitySettings
err = m.endpointService.UpdateEndpoint(endpoint.ID, &endpoint)
if err != nil {
return err
}
}
return nil
}
func (m *Migrator) updateRbacRolesToDB26() error {
defaultAuthorizationsOfRoles := map[portainer.RoleID]portainer.Authorizations{
portainer.RoleIDEndpointAdmin: authorization.DefaultEndpointAuthorizationsForEndpointAdministratorRole(),
portainer.RoleIDHelpdesk: authorization.DefaultEndpointAuthorizationsForHelpDeskRole(),
portainer.RoleIDStandardUser: authorization.DefaultEndpointAuthorizationsForStandardUserRole(),
portainer.RoleIDReadonly: authorization.DefaultEndpointAuthorizationsForReadOnlyUserRole(),
}
for roleID, defaultAuthorizations := range defaultAuthorizationsOfRoles {
role, err := m.roleService.Role(roleID)
if err != nil {
return err
}
role.Authorizations = defaultAuthorizations
err = m.roleService.UpdateRole(role.ID, role)
if err != nil {
return err
}
}
return m.authorizationService.UpdateUsersAuthorizations()
}

View File

@@ -0,0 +1,43 @@
package migrator
import (
"fmt"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/errors"
)
func (m *Migrator) updateStackResourceControlToDB27() error {
resourceControls, err := m.resourceControlService.ResourceControls()
if err != nil {
return err
}
for _, resource := range resourceControls {
if resource.Type != portainer.StackResourceControl {
continue
}
stackName := resource.ResourceID
if err != nil {
return err
}
stack, err := m.stackService.StackByName(stackName)
if err != nil {
if err == errors.ErrObjectNotFound {
continue
}
return err
}
resource.ResourceID = fmt.Sprintf("%d_%s", stack.EndpointID, stack.Name)
err = m.resourceControlService.UpdateResourceControl(resource.ID, &resource)
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,10 @@
package migrator
func (m *Migrator) updateUsersAndRolesToDBVersion28() error {
err := m.roleService.CreateOrUpdatePredefinedRoles()
if err != nil {
return err
}
return m.authorizationService.UpdateUsersAuthorizations()
}

View File

@@ -0,0 +1,31 @@
package migrator
import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/internal/authorization"
)
func (m *Migrator) updateRbacRolesToDB29() error {
defaultAuthorizationsOfRoles := map[portainer.RoleID]portainer.Authorizations{
portainer.RoleIDEndpointAdmin: authorization.DefaultEndpointAuthorizationsForEndpointAdministratorRole(),
portainer.RoleIDHelpdesk: authorization.DefaultEndpointAuthorizationsForHelpDeskRole(),
portainer.RoleIDOperator: authorization.DefaultEndpointAuthorizationsForOperatorRole(),
portainer.RoleIDStandardUser: authorization.DefaultEndpointAuthorizationsForStandardUserRole(),
portainer.RoleIDReadonly: authorization.DefaultEndpointAuthorizationsForReadOnlyUserRole(),
}
for roleID, defaultAuthorizations := range defaultAuthorizationsOfRoles {
role, err := m.roleService.Role(roleID)
if err != nil {
return err
}
role.Authorizations = defaultAuthorizations
err = m.roleService.UpdateRole(role.ID, role)
if err != nil {
return err
}
}
return m.authorizationService.UpdateUsersAuthorizations()
}

View File

@@ -1,6 +1,6 @@
package migrator
import "github.com/portainer/portainer"
import "github.com/portainer/portainer/api"
func (m *Migrator) updateEndpointsToDBVersion4() error {
legacyEndpoints, err := m.endpointService.Endpoints()

View File

@@ -0,0 +1,12 @@
package migrator
func (m *Migrator) updateSettingsToDB31() error {
legacySettings, err := m.settingsService.Settings()
if err != nil {
return err
}
legacySettings.OAuthSettings.SSO = false
legacySettings.OAuthSettings.HideInternalAuth = false
legacySettings.OAuthSettings.LogoutURI = ""
return m.settingsService.UpdateSettings(legacySettings)
}

View File

@@ -0,0 +1,67 @@
package migrator
import (
"os"
"testing"
"github.com/boltdb/bolt"
"github.com/portainer/portainer/api/bolt/settings"
)
var (
testingDBStorePath string
testingDBFileName string
dummyLogoURL string
dbConn *bolt.DB
settingsService *settings.Service
)
func setup() error {
testingDBStorePath, _ = os.Getwd()
testingDBFileName = "portainer-ee-mig-30.db"
dummyLogoURL = "example.com"
var err error
dbConn, err = initTestingDBConn(testingDBStorePath, testingDBFileName)
if err != nil {
return err
}
dummySettingsObj := map[string]interface{}{
"LogoURL": dummyLogoURL,
}
settingsService, err = initTestingSettingsService(dbConn, dummySettingsObj)
if err != nil {
return err
}
return nil
}
func TestUpdateSettingsToDB31(t *testing.T) {
if err := setup(); err != nil {
t.Errorf("failed to complete testing setups, err: %v", err)
}
defer dbConn.Close()
defer os.Remove(testingDBFileName)
m := &Migrator{
db: dbConn,
settingsService: settingsService,
}
if err := m.updateSettingsToDB31(); err != nil {
t.Errorf("failed to update settings: %v", err)
}
updatedSettings, err := m.settingsService.Settings()
if err != nil {
t.Errorf("failed to retrieve the updated settings: %v", err)
}
if updatedSettings.LogoURL != dummyLogoURL {
t.Errorf("unexpected value changes in the updated settings, want LogoURL value: %s, got LogoURL value: %s", dummyLogoURL, updatedSettings.LogoURL)
}
if updatedSettings.OAuthSettings.SSO != false {
t.Errorf("unexpected default OAuth SSO setting, want: false, got: %t", updatedSettings.OAuthSettings.SSO)
}
if updatedSettings.OAuthSettings.HideInternalAuth != false {
t.Errorf("unexpected default OAuth HideInternalAuth setting, want: false, got: %t", updatedSettings.OAuthSettings.HideInternalAuth)
}
if updatedSettings.OAuthSettings.LogoutURI != "" {
t.Errorf("unexpected default OAuth HideInternalAuth setting, want:, got: %s", updatedSettings.OAuthSettings.LogoutURI)
}
}

View File

@@ -1,6 +1,6 @@
package migrator
import "github.com/portainer/portainer"
import "github.com/portainer/portainer/api"
func (m *Migrator) updateEndpointsToVersion8() error {
legacyEndpoints, err := m.endpointService.Endpoints()

View File

@@ -1,6 +1,6 @@
package migrator
import "github.com/portainer/portainer"
import "github.com/portainer/portainer/api"
func (m *Migrator) updateEndpointsToVersion9() error {
legacyEndpoints, err := m.endpointService.Endpoints()

View File

@@ -1,6 +1,6 @@
package migrator
import "github.com/portainer/portainer"
import "github.com/portainer/portainer/api"
func (m *Migrator) updateEndpointsToVersion10() error {
legacyEndpoints, err := m.endpointService.Endpoints()

View File

@@ -0,0 +1,38 @@
package migrator
import (
"path"
"time"
"github.com/boltdb/bolt"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/portainer/portainer/api/bolt/settings"
)
// initTestingDBConn creates a raw bolt DB connection
// for unit testing usage only since using NewStore will cause cycle import inside migrator pkg
func initTestingDBConn(storePath, fileName string) (*bolt.DB, error) {
databasePath := path.Join(storePath, fileName)
dbConn, err := bolt.Open(databasePath, 0600, &bolt.Options{Timeout: 1 * time.Second})
if err != nil {
return nil, err
}
return dbConn, nil
}
// initTestingDBConn creates a settings service with raw bolt DB connection
// for unit testing usage only since using NewStore will cause cycle import inside migrator pkg
func initTestingSettingsService(dbConn *bolt.DB, preSetObj map[string]interface{}) (*settings.Service, error) {
internalDBConn := &internal.DbConnection{
DB: dbConn,
}
settingsService, err := settings.NewService(internalDBConn)
if err != nil {
return nil, err
}
//insert a obj
if err := internal.UpdateObject(internalDBConn, "settings", []byte("SETTINGS"), preSetObj); err != nil {
return nil, err
}
return settingsService, nil
}

View File

@@ -1,190 +1,142 @@
package migrator
import (
"fmt"
"github.com/boltdb/bolt"
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/endpoint"
"github.com/portainer/portainer/bolt/endpointgroup"
"github.com/portainer/portainer/bolt/resourcecontrol"
"github.com/portainer/portainer/bolt/settings"
"github.com/portainer/portainer/bolt/stack"
"github.com/portainer/portainer/bolt/user"
"github.com/portainer/portainer/bolt/version"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/endpoint"
"github.com/portainer/portainer/api/bolt/endpointgroup"
"github.com/portainer/portainer/api/bolt/endpointrelation"
"github.com/portainer/portainer/api/bolt/extension"
plog "github.com/portainer/portainer/api/bolt/log"
"github.com/portainer/portainer/api/bolt/registry"
"github.com/portainer/portainer/api/bolt/resourcecontrol"
"github.com/portainer/portainer/api/bolt/role"
"github.com/portainer/portainer/api/bolt/schedule"
"github.com/portainer/portainer/api/bolt/settings"
"github.com/portainer/portainer/api/bolt/stack"
"github.com/portainer/portainer/api/bolt/tag"
"github.com/portainer/portainer/api/bolt/teammembership"
"github.com/portainer/portainer/api/bolt/user"
"github.com/portainer/portainer/api/bolt/version"
"github.com/portainer/portainer/api/internal/authorization"
)
var migrateLog = plog.NewScopedLog("bolt, migrate")
type (
// Migrator defines a service to migrate data after a Portainer version update.
Migrator struct {
currentDBVersion int
db *bolt.DB
endpointGroupService *endpointgroup.Service
endpointService *endpoint.Service
resourceControlService *resourcecontrol.Service
settingsService *settings.Service
stackService *stack.Service
userService *user.Service
versionService *version.Service
fileService portainer.FileService
db *bolt.DB
currentDBVersion int
currentEdition portainer.SoftwareEdition
endpointGroupService *endpointgroup.Service
endpointService *endpoint.Service
endpointRelationService *endpointrelation.Service
extensionService *extension.Service
registryService *registry.Service
resourceControlService *resourcecontrol.Service
roleService *role.Service
scheduleService *schedule.Service
settingsService *settings.Service
stackService *stack.Service
tagService *tag.Service
teamMembershipService *teammembership.Service
userService *user.Service
versionService *version.Service
fileService portainer.FileService
authorizationService *authorization.Service
}
// Parameters represents the required parameters to create a new Migrator instance.
Parameters struct {
DB *bolt.DB
DatabaseVersion int
EndpointGroupService *endpointgroup.Service
EndpointService *endpoint.Service
ResourceControlService *resourcecontrol.Service
SettingsService *settings.Service
StackService *stack.Service
UserService *user.Service
VersionService *version.Service
FileService portainer.FileService
DB *bolt.DB
DatabaseVersion int
CurrentEdition portainer.SoftwareEdition
EndpointGroupService *endpointgroup.Service
EndpointService *endpoint.Service
EndpointRelationService *endpointrelation.Service
ExtensionService *extension.Service
RegistryService *registry.Service
ResourceControlService *resourcecontrol.Service
RoleService *role.Service
ScheduleService *schedule.Service
SettingsService *settings.Service
StackService *stack.Service
TagService *tag.Service
TeamMembershipService *teammembership.Service
UserService *user.Service
VersionService *version.Service
FileService portainer.FileService
AuthorizationService *authorization.Service
}
)
// NewMigrator creates a new Migrator.
func NewMigrator(parameters *Parameters) *Migrator {
return &Migrator{
db: parameters.DB,
currentDBVersion: parameters.DatabaseVersion,
endpointGroupService: parameters.EndpointGroupService,
endpointService: parameters.EndpointService,
resourceControlService: parameters.ResourceControlService,
settingsService: parameters.SettingsService,
stackService: parameters.StackService,
userService: parameters.UserService,
versionService: parameters.VersionService,
fileService: parameters.FileService,
db: parameters.DB,
currentDBVersion: parameters.DatabaseVersion,
currentEdition: parameters.CurrentEdition,
endpointGroupService: parameters.EndpointGroupService,
endpointService: parameters.EndpointService,
endpointRelationService: parameters.EndpointRelationService,
extensionService: parameters.ExtensionService,
registryService: parameters.RegistryService,
resourceControlService: parameters.ResourceControlService,
roleService: parameters.RoleService,
scheduleService: parameters.ScheduleService,
settingsService: parameters.SettingsService,
tagService: parameters.TagService,
teamMembershipService: parameters.TeamMembershipService,
stackService: parameters.StackService,
userService: parameters.UserService,
versionService: parameters.VersionService,
fileService: parameters.FileService,
authorizationService: parameters.AuthorizationService,
}
}
// Migrate checks the database version and migrate the existing data to the most recent data model.
func (m *Migrator) Migrate() error {
// Portainer < 1.12
if m.currentDBVersion < 1 {
err := m.updateAdminUserToDBVersion1()
if err != nil {
return err
}
}
// Portainer 1.12.x
if m.currentDBVersion < 2 {
err := m.updateResourceControlsToDBVersion2()
if err != nil {
return err
}
err = m.updateEndpointsToDBVersion2()
if err != nil {
return err
}
}
// Portainer 1.13.x
if m.currentDBVersion < 3 {
err := m.updateSettingsToDBVersion3()
if err != nil {
return err
}
}
// Portainer 1.14.0
if m.currentDBVersion < 4 {
err := m.updateEndpointsToDBVersion4()
if err != nil {
return err
}
}
// https://github.com/portainer/portainer/issues/1235
if m.currentDBVersion < 5 {
err := m.updateSettingsToVersion5()
if err != nil {
return err
}
}
// https://github.com/portainer/portainer/issues/1236
if m.currentDBVersion < 6 {
err := m.updateSettingsToVersion6()
if err != nil {
return err
}
}
// https://github.com/portainer/portainer/issues/1449
if m.currentDBVersion < 7 {
err := m.updateSettingsToVersion7()
if err != nil {
return err
}
}
if m.currentDBVersion < 8 {
err := m.updateEndpointsToVersion8()
if err != nil {
return err
}
}
// https: //github.com/portainer/portainer/issues/1396
if m.currentDBVersion < 9 {
err := m.updateEndpointsToVersion9()
if err != nil {
return err
}
}
// https://github.com/portainer/portainer/issues/461
if m.currentDBVersion < 10 {
err := m.updateEndpointsToVersion10()
if err != nil {
return err
}
}
// https://github.com/portainer/portainer/issues/1906
if m.currentDBVersion < 11 {
err := m.updateEndpointsToVersion11()
if err != nil {
return err
}
}
// Portainer 1.18.0
if m.currentDBVersion < 12 {
err := m.updateEndpointsToVersion12()
if err != nil {
return err
}
err = m.updateEndpointGroupsToVersion12()
if err != nil {
return err
}
err = m.updateStacksToVersion12()
if err != nil {
return err
}
}
// Portainer 1.19.0
if m.currentDBVersion < 13 {
err := m.updateSettingsToVersion13()
if err != nil {
return err
}
}
// Portainer 1.19.2
if m.currentDBVersion < 14 {
err := m.updateResourceControlsToDBVersion14()
if err != nil {
return err
}
}
return m.versionService.StoreDBVersion(portainer.DBVersion)
// Version exposes version of database
func (migrator *Migrator) Version() int {
return migrator.currentDBVersion
}
// Edition exposes edition of portainer
func (migrator *Migrator) Edition() portainer.SoftwareEdition {
return migrator.currentEdition
}
// Migrate helper to upgrade DB
func (migrator *Migrator) Migrate(version int) error {
migrateLog.Info(fmt.Sprintf("Migrating %s database from version %d to %d.", migrator.Edition().GetEditionLabel(), migrator.currentDBVersion, version))
// TODO : run backup before migration and restore if failed
err := migrator.MigrateCE() //CE
if err != nil {
migrateLog.Error("An error occurred during database migration", err)
return err
}
migrator.versionService.StoreDBVersion(version)
migrator.currentDBVersion = version
return nil
}
// RollbackVersion rolls back the db to version
func (migrator *Migrator) RollbackVersion(version int) error {
err := migrator.versionService.StoreDBVersion(version) // portainer.DBVersion
return err
}
// RollbackEdition rolls back the db to portainer CE
func (migrator *Migrator) RollbackEdition(edition portainer.SoftwareEdition) error {
err := migrator.versionService.StoreEdition(portainer.PortainerCE)
return err
}

View File

@@ -0,0 +1,4 @@
package migrator
// test CE version is always upgraded to latest version of CE
// test EE version is always upgraded to latest version of EE

View File

@@ -0,0 +1,228 @@
package migrator
import (
"fmt"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/internal/authorization"
)
// UpgradeToEE will migrate the db from latest ce version to latest ee version
// Latest version is v25 on 06/11/2020
func (m *Migrator) UpgradeToEE() error {
migrateLog.Info(fmt.Sprintf("Migrating CE database version %d to EE database version %d.", m.Version(), portainer.DBVersion))
migrateLog.Info("Updating LDAP settings to EE")
err := m.updateSettingsToEE()
if err != nil {
return err
}
migrateLog.Info("Updating user roles to EE")
err = m.updateUserRolesToEE()
if err != nil {
return err
}
migrateLog.Info("Updating role authorizations to EE")
err = m.updateRoleAuthorizationsToEE()
if err != nil {
return err
}
migrateLog.Info("Updating user authorizations")
err = m.authorizationService.UpdateUsersAuthorizations()
if err != nil {
return err
}
migrateLog.Info(fmt.Sprintf("Setting db version to %d", portainer.DBVersionEE))
err = m.versionService.StoreDBVersion(portainer.DBVersionEE)
if err != nil {
return err
}
migrateLog.Info(fmt.Sprintf("Setting edition to %s", portainer.PortainerEE.GetEditionLabel()))
err = m.versionService.StoreEdition(portainer.PortainerEE)
if err != nil {
return err
}
m.currentDBVersion = portainer.DBVersionEE
m.currentEdition = portainer.PortainerEE
return nil
}
func (m *Migrator) updateSettingsToEE() error {
legacySettings, err := m.settingsService.Settings()
if err != nil {
return err
}
legacySettings.LDAPSettings.URLs = []string{}
url := legacySettings.LDAPSettings.URL
if url != "" {
legacySettings.LDAPSettings.URLs = append(legacySettings.LDAPSettings.URLs, url)
}
legacySettings.LDAPSettings.ServerType = portainer.LDAPServerCustom
return m.settingsService.UpdateSettings(legacySettings)
}
// Updating role authorizations because of the new policies in Kube RBAC
func (m *Migrator) updateRoleAuthorizationsToEE() error {
migrateLog.Debug("Retriving settings")
migrateLog.Debug("Updating Endpoint Admin Role")
endpointAdministratorRole, err := m.roleService.Role(portainer.RoleID(1))
if err != nil {
return err
}
endpointAdministratorRole.Priority = 1
endpointAdministratorRole.Authorizations = authorization.DefaultEndpointAuthorizationsForEndpointAdministratorRole()
err = m.roleService.UpdateRole(endpointAdministratorRole.ID, endpointAdministratorRole)
migrateLog.Debug("Updating Help Desk Role")
helpDeskRole, err := m.roleService.Role(portainer.RoleID(2))
if err != nil {
return err
}
helpDeskRole.Priority = 2
helpDeskRole.Authorizations = authorization.DefaultEndpointAuthorizationsForHelpDeskRole()
err = m.roleService.UpdateRole(helpDeskRole.ID, helpDeskRole)
migrateLog.Debug("Updating Standard User Role")
standardUserRole, err := m.roleService.Role(portainer.RoleID(3))
if err != nil {
return err
}
standardUserRole.Priority = 3
standardUserRole.Authorizations = authorization.DefaultEndpointAuthorizationsForStandardUserRole()
err = m.roleService.UpdateRole(standardUserRole.ID, standardUserRole)
migrateLog.Debug("Updating Read Only User Role")
readOnlyUserRole, err := m.roleService.Role(portainer.RoleID(4))
if err != nil {
return err
}
readOnlyUserRole.Priority = 4
readOnlyUserRole.Authorizations = authorization.DefaultEndpointAuthorizationsForReadOnlyUserRole()
err = m.roleService.UpdateRole(readOnlyUserRole.ID, readOnlyUserRole)
if err != nil {
return err
}
return nil
}
// If RBAC extension wasn't installed before, update all users in endpoints and
// endpoint groups to have read only access.
func (m *Migrator) updateUserRolesToEE() error {
err := m.updateUserAuthorizationToEE()
if err != nil {
return err
}
migrateLog.Debug("Retriving extension info")
extensions, err := m.extensionService.Extensions()
for _, extension := range extensions {
if extension.ID == 3 && extension.Enabled {
migrateLog.Info("RBAC extensions were enabled before; Skip updating User Roles")
return nil
}
}
migrateLog.Debug("Retriving endpoint groups")
endpointGroups, err := m.endpointGroupService.EndpointGroups()
if err != nil {
return err
}
for _, endpointGroup := range endpointGroups {
migrateLog.Debug(fmt.Sprintf("Updating user policies for endpoint group %v", endpointGroup.ID))
for key := range endpointGroup.UserAccessPolicies {
updateUserAccessPolicyToReadOnlyRole(endpointGroup.UserAccessPolicies, key)
}
for key := range endpointGroup.TeamAccessPolicies {
updateTeamAccessPolicyToReadOnlyRole(endpointGroup.TeamAccessPolicies, key)
}
err := m.endpointGroupService.UpdateEndpointGroup(endpointGroup.ID, &endpointGroup)
if err != nil {
return err
}
}
migrateLog.Debug("Retriving endpoints")
endpoints, err := m.endpointService.Endpoints()
if err != nil {
return err
}
for _, endpoint := range endpoints {
migrateLog.Debug(fmt.Sprintf("Updating user policies for endpoint %v", endpoint.ID))
for key := range endpoint.UserAccessPolicies {
updateUserAccessPolicyToReadOnlyRole(endpoint.UserAccessPolicies, key)
}
for key := range endpoint.TeamAccessPolicies {
updateTeamAccessPolicyToReadOnlyRole(endpoint.TeamAccessPolicies, key)
}
err := m.endpointService.UpdateEndpoint(endpoint.ID, &endpoint)
if err != nil {
return err
}
}
return nil
}
func (m *Migrator) updateUserAuthorizationToEE() error {
legacyUsers, err := m.userService.Users()
if err != nil {
return err
}
for _, user := range legacyUsers {
user.PortainerAuthorizations = authorization.DefaultPortainerAuthorizations()
err = m.userService.UpdateUser(user.ID, &user)
if err != nil {
return err
}
}
return nil
}
func updateUserAccessPolicyToNoRole(policies portainer.UserAccessPolicies, key portainer.UserID) {
tmp := policies[key]
tmp.RoleID = 0
policies[key] = tmp
}
func updateTeamAccessPolicyToNoRole(policies portainer.TeamAccessPolicies, key portainer.TeamID) {
tmp := policies[key]
tmp.RoleID = 0
policies[key] = tmp
}
func updateUserAccessPolicyToReadOnlyRole(policies portainer.UserAccessPolicies, key portainer.UserID) {
tmp := policies[key]
tmp.RoleID = 4
policies[key] = tmp
}
func updateTeamAccessPolicyToReadOnlyRole(policies portainer.TeamAccessPolicies, key portainer.TeamID) {
tmp := policies[key]
tmp.RoleID = 4
policies[key] = tmp
}

View File

@@ -1,8 +1,8 @@
package registry
import (
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/boltdb/bolt"
)
@@ -14,18 +14,18 @@ const (
// Service represents a service for managing endpoint data.
type Service struct {
db *bolt.DB
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(db *bolt.DB) (*Service, error) {
err := internal.CreateBucket(db, BucketName)
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
db: db,
connection: connection,
}, nil
}
@@ -34,7 +34,7 @@ func (service *Service) Registry(ID portainer.RegistryID) (*portainer.Registry,
var registry portainer.Registry
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.db, BucketName, identifier, &registry)
err := internal.GetObject(service.connection, BucketName, identifier, &registry)
if err != nil {
return nil, err
}
@@ -46,7 +46,7 @@ func (service *Service) Registry(ID portainer.RegistryID) (*portainer.Registry,
func (service *Service) Registries() ([]portainer.Registry, error) {
var registries = make([]portainer.Registry, 0)
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -67,7 +67,7 @@ func (service *Service) Registries() ([]portainer.Registry, error) {
// CreateRegistry creates a new registry.
func (service *Service) CreateRegistry(registry *portainer.Registry) error {
return service.db.Update(func(tx *bolt.Tx) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
id, _ := bucket.NextSequence()
@@ -85,11 +85,11 @@ func (service *Service) CreateRegistry(registry *portainer.Registry) error {
// UpdateRegistry updates an registry.
func (service *Service) UpdateRegistry(ID portainer.RegistryID, registry *portainer.Registry) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.db, BucketName, identifier, registry)
return internal.UpdateObject(service.connection, BucketName, identifier, registry)
}
// DeleteRegistry deletes an registry.
func (service *Service) DeleteRegistry(ID portainer.RegistryID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.db, BucketName, identifier)
return internal.DeleteObject(service.connection, BucketName, identifier)
}

View File

@@ -1,8 +1,8 @@
package resourcecontrol
import (
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/boltdb/bolt"
)
@@ -14,18 +14,18 @@ const (
// Service represents a service for managing endpoint data.
type Service struct {
db *bolt.DB
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(db *bolt.DB) (*Service, error) {
err := internal.CreateBucket(db, BucketName)
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
db: db,
connection: connection,
}, nil
}
@@ -34,7 +34,7 @@ func (service *Service) ResourceControl(ID portainer.ResourceControlID) (*portai
var resourceControl portainer.ResourceControl
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.db, BucketName, identifier, &resourceControl)
err := internal.GetObject(service.connection, BucketName, identifier, &resourceControl)
if err != nil {
return nil, err
}
@@ -42,12 +42,13 @@ func (service *Service) ResourceControl(ID portainer.ResourceControlID) (*portai
return &resourceControl, nil
}
// ResourceControlByResourceID returns a ResourceControl object by checking if the resourceID is equal
// to the main ResourceID or in SubResourceIDs
func (service *Service) ResourceControlByResourceID(resourceID string) (*portainer.ResourceControl, error) {
// ResourceControlByResourceIDAndType returns a ResourceControl object by checking if the resourceID is equal
// to the main ResourceID or in SubResourceIDs. It also performs a check on the resource type. Return nil
// if no ResourceControl was found.
func (service *Service) ResourceControlByResourceIDAndType(resourceID string, resourceType portainer.ResourceControlType) (*portainer.ResourceControl, error) {
var resourceControl *portainer.ResourceControl
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -58,7 +59,7 @@ func (service *Service) ResourceControlByResourceID(resourceID string) (*portain
return err
}
if rc.ResourceID == resourceID {
if rc.ResourceID == resourceID && rc.Type == resourceType {
resourceControl = &rc
break
}
@@ -71,10 +72,6 @@ func (service *Service) ResourceControlByResourceID(resourceID string) (*portain
}
}
if resourceControl == nil {
return portainer.ErrObjectNotFound
}
return nil
})
@@ -85,7 +82,7 @@ func (service *Service) ResourceControlByResourceID(resourceID string) (*portain
func (service *Service) ResourceControls() ([]portainer.ResourceControl, error) {
var rcs = make([]portainer.ResourceControl, 0)
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -106,7 +103,7 @@ func (service *Service) ResourceControls() ([]portainer.ResourceControl, error)
// CreateResourceControl creates a new ResourceControl object
func (service *Service) CreateResourceControl(resourceControl *portainer.ResourceControl) error {
return service.db.Update(func(tx *bolt.Tx) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
id, _ := bucket.NextSequence()
@@ -124,11 +121,11 @@ func (service *Service) CreateResourceControl(resourceControl *portainer.Resourc
// UpdateResourceControl saves a ResourceControl object.
func (service *Service) UpdateResourceControl(ID portainer.ResourceControlID, resourceControl *portainer.ResourceControl) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.db, BucketName, identifier, resourceControl)
return internal.UpdateObject(service.connection, BucketName, identifier, resourceControl)
}
// DeleteResourceControl deletes a ResourceControl object by ID
func (service *Service) DeleteResourceControl(ID portainer.ResourceControlID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.db, BucketName, identifier)
return internal.DeleteObject(service.connection, BucketName, identifier)
}

View File

@@ -0,0 +1,68 @@
package role
import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/errors"
"github.com/portainer/portainer/api/internal/authorization"
)
// CreateOrUpdatePredefinedRoles update the predefined roles. Create one if it does not exist yet.
func (service *Service) CreateOrUpdatePredefinedRoles() error {
predefinedRoles := map[portainer.RoleID]*portainer.Role{
portainer.RoleIDEndpointAdmin: &portainer.Role{
Name: "Endpoint administrator",
Description: "Full control of all resources in an endpoint",
ID: portainer.RoleIDEndpointAdmin,
Priority: 1,
Authorizations: authorization.DefaultEndpointAuthorizationsForEndpointAdministratorRole(),
},
portainer.RoleIDOperator: &portainer.Role{
Name: "Operator",
Description: "Operational control of all existing resources in an endpoint",
ID: portainer.RoleIDOperator,
Priority: 2,
Authorizations: authorization.DefaultEndpointAuthorizationsForOperatorRole(),
},
portainer.RoleIDHelpdesk: &portainer.Role{
Name: "Helpdesk",
Description: "Read-only access of all resources in an endpoint",
ID: portainer.RoleIDHelpdesk,
Priority: 3,
Authorizations: authorization.DefaultEndpointAuthorizationsForHelpDeskRole(),
},
portainer.RoleIDStandardUser: &portainer.Role{
Name: "Standard user",
Description: "Full control of assigned resources in an endpoint",
ID: portainer.RoleIDStandardUser,
Priority: 4,
Authorizations: authorization.DefaultEndpointAuthorizationsForStandardUserRole(),
},
portainer.RoleIDReadonly: &portainer.Role{
Name: "Read-only user",
Description: "Read-only access of assigned resources in an endpoint",
ID: portainer.RoleIDReadonly,
Priority: 5,
Authorizations: authorization.DefaultEndpointAuthorizationsForReadOnlyUserRole(),
},
}
for roleID, predefinedRole := range predefinedRoles {
_, err := service.Role(roleID)
if err == errors.ErrObjectNotFound {
err := service.CreateRole(predefinedRole)
if err != nil {
return err
}
} else if err != nil {
return err
} else {
err = service.UpdateRole(predefinedRole.ID, predefinedRole)
if err != nil {
return err
}
}
}
return nil
}

91
api/bolt/role/role.go Normal file
View File

@@ -0,0 +1,91 @@
package role
import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/boltdb/bolt"
)
const (
// BucketName represents the name of the bucket where this service stores data.
BucketName = "roles"
)
// Service represents a service for managing endpoint data.
type Service struct {
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
connection: connection,
}, nil
}
// Role returns a Role by ID
func (service *Service) Role(ID portainer.RoleID) (*portainer.Role, error) {
var set portainer.Role
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.connection, BucketName, identifier, &set)
if err != nil {
return nil, err
}
return &set, nil
}
// Roles return an array containing all the sets.
func (service *Service) Roles() ([]portainer.Role, error) {
var sets = make([]portainer.Role, 0)
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
var set portainer.Role
err := internal.UnmarshalObject(v, &set)
if err != nil {
return err
}
sets = append(sets, set)
}
return nil
})
return sets, err
}
// CreateRole creates a new Role.
func (service *Service) CreateRole(role *portainer.Role) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
id, _ := bucket.NextSequence()
if role.ID == 0 {
role.ID = portainer.RoleID(id)
}
data, err := internal.MarshalObject(role)
if err != nil {
return err
}
return bucket.Put(internal.Itob(int(role.ID)), data)
})
}
// UpdateRole updates a role.
func (service *Service) UpdateRole(ID portainer.RoleID, role *portainer.Role) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.connection, BucketName, identifier, role)
}

View File

@@ -0,0 +1,66 @@
package s3backup
import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/errors"
"github.com/portainer/portainer/api/bolt/internal"
)
const (
bucketName = "s3backup"
statusKey = "lastRunStatus"
settingsKey = "settings"
)
type Service struct {
connection *internal.DbConnection
}
// NewService creates a new service and ensures corresponding bucket exist
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, bucketName)
if err != nil {
return nil, err
}
return &Service{
connection: connection,
}, nil
}
// GetStatus returns the status of the last scheduled backup run
func (s *Service) GetStatus() (portainer.S3BackupStatus, error) {
var status portainer.S3BackupStatus
err := internal.GetObject(s.connection, bucketName, []byte(statusKey), &status)
if err == errors.ErrObjectNotFound {
return status, nil
}
return status, err
}
// DropStatus deletes the status of the last sheduled backup run
func (s *Service) DropStatus() error {
return internal.DeleteObject(s.connection, bucketName, []byte(statusKey))
}
// UpdateStatus upserts a status of the last scheduled backup run
func (s *Service) UpdateStatus(status portainer.S3BackupStatus) error {
return internal.UpdateObject(s.connection, bucketName, []byte(statusKey), status)
}
// UpdateSettings updates stored s3 backup settings
func (s *Service) UpdateSettings(settings portainer.S3BackupSettings) error {
return internal.UpdateObject(s.connection, bucketName, []byte(settingsKey), settings)
}
// GetSettings returns stored s3 backup settings
func (s *Service) GetSettings() (portainer.S3BackupSettings, error) {
var settings portainer.S3BackupSettings
err := internal.GetObject(s.connection, bucketName, []byte(settingsKey), &settings)
if err == errors.ErrObjectNotFound {
return settings, nil
}
return settings, err
}

View File

@@ -0,0 +1,129 @@
package schedule
import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/boltdb/bolt"
)
const (
// BucketName represents the name of the bucket where this service stores data.
BucketName = "schedules"
)
// Service represents a service for managing schedule data.
type Service struct {
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
connection: connection,
}, nil
}
// Schedule returns a schedule by ID.
func (service *Service) Schedule(ID portainer.ScheduleID) (*portainer.Schedule, error) {
var schedule portainer.Schedule
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.connection, BucketName, identifier, &schedule)
if err != nil {
return nil, err
}
return &schedule, nil
}
// UpdateSchedule updates a schedule.
func (service *Service) UpdateSchedule(ID portainer.ScheduleID, schedule *portainer.Schedule) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.connection, BucketName, identifier, schedule)
}
// DeleteSchedule deletes a schedule.
func (service *Service) DeleteSchedule(ID portainer.ScheduleID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.connection, BucketName, identifier)
}
// Schedules return a array containing all the schedules.
func (service *Service) Schedules() ([]portainer.Schedule, error) {
var schedules = make([]portainer.Schedule, 0)
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
var schedule portainer.Schedule
err := internal.UnmarshalObject(v, &schedule)
if err != nil {
return err
}
schedules = append(schedules, schedule)
}
return nil
})
return schedules, err
}
// SchedulesByJobType return a array containing all the schedules
// with the specified JobType.
func (service *Service) SchedulesByJobType(jobType portainer.JobType) ([]portainer.Schedule, error) {
var schedules = make([]portainer.Schedule, 0)
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
var schedule portainer.Schedule
err := internal.UnmarshalObject(v, &schedule)
if err != nil {
return err
}
if schedule.JobType == jobType {
schedules = append(schedules, schedule)
}
}
return nil
})
return schedules, err
}
// CreateSchedule assign an ID to a new schedule and saves it.
func (service *Service) CreateSchedule(schedule *portainer.Schedule) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
// We manually manage sequences for schedules
err := bucket.SetSequence(uint64(schedule.ID))
if err != nil {
return err
}
data, err := internal.MarshalObject(schedule)
if err != nil {
return err
}
return bucket.Put(internal.Itob(int(schedule.ID)), data)
})
}
// GetNextIdentifier returns the next identifier for a schedule.
func (service *Service) GetNextIdentifier() int {
return internal.GetNextIdentifier(service.connection, BucketName)
}

287
api/bolt/services.go Normal file
View File

@@ -0,0 +1,287 @@
package bolt
import (
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/customtemplate"
"github.com/portainer/portainer/api/bolt/dockerhub"
"github.com/portainer/portainer/api/bolt/edgegroup"
"github.com/portainer/portainer/api/bolt/edgejob"
"github.com/portainer/portainer/api/bolt/edgestack"
"github.com/portainer/portainer/api/bolt/endpoint"
"github.com/portainer/portainer/api/bolt/endpointgroup"
"github.com/portainer/portainer/api/bolt/endpointrelation"
"github.com/portainer/portainer/api/bolt/extension"
"github.com/portainer/portainer/api/bolt/license"
"github.com/portainer/portainer/api/bolt/registry"
"github.com/portainer/portainer/api/bolt/resourcecontrol"
"github.com/portainer/portainer/api/bolt/role"
"github.com/portainer/portainer/api/bolt/s3backup"
"github.com/portainer/portainer/api/bolt/schedule"
"github.com/portainer/portainer/api/bolt/settings"
"github.com/portainer/portainer/api/bolt/stack"
"github.com/portainer/portainer/api/bolt/tag"
"github.com/portainer/portainer/api/bolt/team"
"github.com/portainer/portainer/api/bolt/teammembership"
"github.com/portainer/portainer/api/bolt/tunnelserver"
"github.com/portainer/portainer/api/bolt/user"
"github.com/portainer/portainer/api/bolt/version"
"github.com/portainer/portainer/api/bolt/webhook"
)
func (store *Store) initServices() error {
authorizationsetService, err := role.NewService(store.connection)
if err != nil {
return err
}
store.RoleService = authorizationsetService
customTemplateService, err := customtemplate.NewService(store.connection)
if err != nil {
return err
}
store.CustomTemplateService = customTemplateService
dockerhubService, err := dockerhub.NewService(store.connection)
if err != nil {
return err
}
store.DockerHubService = dockerhubService
edgeStackService, err := edgestack.NewService(store.connection)
if err != nil {
return err
}
store.EdgeStackService = edgeStackService
edgeGroupService, err := edgegroup.NewService(store.connection)
if err != nil {
return err
}
store.EdgeGroupService = edgeGroupService
edgeJobService, err := edgejob.NewService(store.connection)
if err != nil {
return err
}
store.EdgeJobService = edgeJobService
endpointgroupService, err := endpointgroup.NewService(store.connection)
if err != nil {
return err
}
store.EndpointGroupService = endpointgroupService
endpointService, err := endpoint.NewService(store.connection)
if err != nil {
return err
}
store.EndpointService = endpointService
endpointRelationService, err := endpointrelation.NewService(store.connection)
if err != nil {
return err
}
store.EndpointRelationService = endpointRelationService
extensionService, err := extension.NewService(store.connection)
if err != nil {
return err
}
store.ExtensionService = extensionService
licenseService, err := license.NewService(store.connection)
if err != nil {
return err
}
store.LicenseService = licenseService
registryService, err := registry.NewService(store.connection)
if err != nil {
return err
}
store.RegistryService = registryService
resourcecontrolService, err := resourcecontrol.NewService(store.connection)
if err != nil {
return err
}
store.ResourceControlService = resourcecontrolService
s3backupService, err := s3backup.NewService(store.connection)
if err != nil {
return nil
}
store.S3BackupService = s3backupService
settingsService, err := settings.NewService(store.connection)
if err != nil {
return err
}
store.SettingsService = settingsService
stackService, err := stack.NewService(store.connection)
if err != nil {
return err
}
store.StackService = stackService
tagService, err := tag.NewService(store.connection)
if err != nil {
return err
}
store.TagService = tagService
teammembershipService, err := teammembership.NewService(store.connection)
if err != nil {
return err
}
store.TeamMembershipService = teammembershipService
teamService, err := team.NewService(store.connection)
if err != nil {
return err
}
store.TeamService = teamService
tunnelServerService, err := tunnelserver.NewService(store.connection)
if err != nil {
return err
}
store.TunnelServerService = tunnelServerService
userService, err := user.NewService(store.connection)
if err != nil {
return err
}
store.UserService = userService
versionService, err := version.NewService(store.connection)
if err != nil {
return err
}
store.VersionService = versionService
webhookService, err := webhook.NewService(store.connection)
if err != nil {
return err
}
store.WebhookService = webhookService
scheduleService, err := schedule.NewService(store.connection)
if err != nil {
return err
}
store.ScheduleService = scheduleService
return nil
}
// CustomTemplate gives access to the CustomTemplate data management layer
func (store *Store) CustomTemplate() portainer.CustomTemplateService {
return store.CustomTemplateService
}
// DockerHub gives access to the DockerHub data management layer
func (store *Store) DockerHub() portainer.DockerHubService {
return store.DockerHubService
}
// EdgeGroup gives access to the EdgeGroup data management layer
func (store *Store) EdgeGroup() portainer.EdgeGroupService {
return store.EdgeGroupService
}
// EdgeJob gives access to the EdgeJob data management layer
func (store *Store) EdgeJob() portainer.EdgeJobService {
return store.EdgeJobService
}
// EdgeStack gives access to the EdgeStack data management layer
func (store *Store) EdgeStack() portainer.EdgeStackService {
return store.EdgeStackService
}
// Endpoint gives access to the Endpoint data management layer
func (store *Store) Endpoint() portainer.EndpointService {
return store.EndpointService
}
// EndpointGroup gives access to the EndpointGroup data management layer
func (store *Store) EndpointGroup() portainer.EndpointGroupService {
return store.EndpointGroupService
}
// EndpointRelation gives access to the EndpointRelation data management layer
func (store *Store) EndpointRelation() portainer.EndpointRelationService {
return store.EndpointRelationService
}
// License provides access to the License data management layer
func (store *Store) License() portainer.LicenseRepository {
return store.LicenseService
}
// Registry gives access to the Registry data management layer
func (store *Store) Registry() portainer.RegistryService {
return store.RegistryService
}
// ResourceControl gives access to the ResourceControl data management layer
func (store *Store) ResourceControl() portainer.ResourceControlService {
return store.ResourceControlService
}
// Role gives access to the Role data management layer
func (store *Store) Role() portainer.RoleService {
return store.RoleService
}
// S3Backup gives access to S3 backup settings and status
func (store *Store) S3Backup() portainer.S3BackupService {
return store.S3BackupService
}
// Settings gives access to the Settings data management layer
func (store *Store) Settings() portainer.SettingsService {
return store.SettingsService
}
// Stack gives access to the Stack data management layer
func (store *Store) Stack() portainer.StackService {
return store.StackService
}
// Tag gives access to the Tag data management layer
func (store *Store) Tag() portainer.TagService {
return store.TagService
}
// TeamMembership gives access to the TeamMembership data management layer
func (store *Store) TeamMembership() portainer.TeamMembershipService {
return store.TeamMembershipService
}
// Team gives access to the Team data management layer
func (store *Store) Team() portainer.TeamService {
return store.TeamService
}
// TunnelServer gives access to the TunnelServer data management layer
func (store *Store) TunnelServer() portainer.TunnelServerService {
return store.TunnelServerService
}
// User gives access to the User data management layer
func (store *Store) User() portainer.UserService {
return store.UserService
}
// Version gives access to the Version data management layer
func (store *Store) Version() portainer.VersionService {
return store.VersionService
}
// Webhook gives access to the Webhook data management layer
func (store *Store) Webhook() portainer.WebhookService {
return store.WebhookService
}

View File

@@ -1,10 +1,8 @@
package settings
import (
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
"github.com/boltdb/bolt"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
)
const (
@@ -15,18 +13,18 @@ const (
// Service represents a service for managing endpoint data.
type Service struct {
db *bolt.DB
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(db *bolt.DB) (*Service, error) {
err := internal.CreateBucket(db, BucketName)
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
db: db,
connection: connection,
}, nil
}
@@ -34,7 +32,7 @@ func NewService(db *bolt.DB) (*Service, error) {
func (service *Service) Settings() (*portainer.Settings, error) {
var settings portainer.Settings
err := internal.GetObject(service.db, BucketName, []byte(settingsKey), &settings)
err := internal.GetObject(service.connection, BucketName, []byte(settingsKey), &settings)
if err != nil {
return nil, err
}
@@ -44,5 +42,5 @@ func (service *Service) Settings() (*portainer.Settings, error) {
// UpdateSettings persists a Settings object.
func (service *Service) UpdateSettings(settings *portainer.Settings) error {
return internal.UpdateObject(service.db, BucketName, []byte(settingsKey), settings)
return internal.UpdateObject(service.connection, BucketName, []byte(settingsKey), settings)
}

View File

@@ -1,8 +1,9 @@
package stack
import (
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/errors"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/boltdb/bolt"
)
@@ -14,18 +15,18 @@ const (
// Service represents a service for managing endpoint data.
type Service struct {
db *bolt.DB
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(db *bolt.DB) (*Service, error) {
err := internal.CreateBucket(db, BucketName)
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
db: db,
connection: connection,
}, nil
}
@@ -34,7 +35,7 @@ func (service *Service) Stack(ID portainer.StackID) (*portainer.Stack, error) {
var stack portainer.Stack
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.db, BucketName, identifier, &stack)
err := internal.GetObject(service.connection, BucketName, identifier, &stack)
if err != nil {
return nil, err
}
@@ -46,7 +47,7 @@ func (service *Service) Stack(ID portainer.StackID) (*portainer.Stack, error) {
func (service *Service) StackByName(name string) (*portainer.Stack, error) {
var stack *portainer.Stack
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -64,7 +65,7 @@ func (service *Service) StackByName(name string) (*portainer.Stack, error) {
}
if stack == nil {
return portainer.ErrObjectNotFound
return errors.ErrObjectNotFound
}
return nil
@@ -77,7 +78,7 @@ func (service *Service) StackByName(name string) (*portainer.Stack, error) {
func (service *Service) Stacks() ([]portainer.Stack, error) {
var stacks = make([]portainer.Stack, 0)
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -98,12 +99,12 @@ func (service *Service) Stacks() ([]portainer.Stack, error) {
// GetNextIdentifier returns the next identifier for a stack.
func (service *Service) GetNextIdentifier() int {
return internal.GetNextIdentifier(service.db, BucketName)
return internal.GetNextIdentifier(service.connection, BucketName)
}
// CreateStack creates a new stack.
func (service *Service) CreateStack(stack *portainer.Stack) error {
return service.db.Update(func(tx *bolt.Tx) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
// We manually manage sequences for stacks
@@ -124,11 +125,11 @@ func (service *Service) CreateStack(stack *portainer.Stack) error {
// UpdateStack updates a stack.
func (service *Service) UpdateStack(ID portainer.StackID, stack *portainer.Stack) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.db, BucketName, identifier, stack)
return internal.UpdateObject(service.connection, BucketName, identifier, stack)
}
// DeleteStack deletes a stack.
func (service *Service) DeleteStack(ID portainer.StackID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.db, BucketName, identifier)
return internal.DeleteObject(service.connection, BucketName, identifier)
}

View File

@@ -1,8 +1,8 @@
package tag
import (
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/boltdb/bolt"
)
@@ -14,18 +14,18 @@ const (
// Service represents a service for managing endpoint data.
type Service struct {
db *bolt.DB
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(db *bolt.DB) (*Service, error) {
err := internal.CreateBucket(db, BucketName)
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
db: db,
connection: connection,
}, nil
}
@@ -33,7 +33,7 @@ func NewService(db *bolt.DB) (*Service, error) {
func (service *Service) Tags() ([]portainer.Tag, error) {
var tags = make([]portainer.Tag, 0)
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -52,9 +52,22 @@ func (service *Service) Tags() ([]portainer.Tag, error) {
return tags, err
}
// Tag returns a tag by ID.
func (service *Service) Tag(ID portainer.TagID) (*portainer.Tag, error) {
var tag portainer.Tag
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.connection, BucketName, identifier, &tag)
if err != nil {
return nil, err
}
return &tag, nil
}
// CreateTag creates a new tag.
func (service *Service) CreateTag(tag *portainer.Tag) error {
return service.db.Update(func(tx *bolt.Tx) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
id, _ := bucket.NextSequence()
@@ -69,8 +82,14 @@ func (service *Service) CreateTag(tag *portainer.Tag) error {
})
}
// UpdateTag updates a tag.
func (service *Service) UpdateTag(ID portainer.TagID, tag *portainer.Tag) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.connection, BucketName, identifier, tag)
}
// DeleteTag deletes a tag.
func (service *Service) DeleteTag(ID portainer.TagID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.db, BucketName, identifier)
return internal.DeleteObject(service.connection, BucketName, identifier)
}

View File

@@ -1,10 +1,11 @@
package team
import (
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
"github.com/boltdb/bolt"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/errors"
"github.com/portainer/portainer/api/bolt/internal"
"strings"
)
const (
@@ -14,18 +15,18 @@ const (
// Service represents a service for managing endpoint data.
type Service struct {
db *bolt.DB
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(db *bolt.DB) (*Service, error) {
err := internal.CreateBucket(db, BucketName)
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
db: db,
connection: connection,
}, nil
}
@@ -34,7 +35,7 @@ func (service *Service) Team(ID portainer.TeamID) (*portainer.Team, error) {
var team portainer.Team
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.db, BucketName, identifier, &team)
err := internal.GetObject(service.connection, BucketName, identifier, &team)
if err != nil {
return nil, err
}
@@ -46,7 +47,7 @@ func (service *Service) Team(ID portainer.TeamID) (*portainer.Team, error) {
func (service *Service) TeamByName(name string) (*portainer.Team, error) {
var team *portainer.Team
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -57,14 +58,14 @@ func (service *Service) TeamByName(name string) (*portainer.Team, error) {
return err
}
if t.Name == name {
if strings.EqualFold(t.Name, name) {
team = &t
break
}
}
if team == nil {
return portainer.ErrObjectNotFound
return errors.ErrObjectNotFound
}
return nil
@@ -77,7 +78,7 @@ func (service *Service) TeamByName(name string) (*portainer.Team, error) {
func (service *Service) Teams() ([]portainer.Team, error) {
var teams = make([]portainer.Team, 0)
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -99,12 +100,12 @@ func (service *Service) Teams() ([]portainer.Team, error) {
// UpdateTeam saves a Team.
func (service *Service) UpdateTeam(ID portainer.TeamID, team *portainer.Team) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.db, BucketName, identifier, team)
return internal.UpdateObject(service.connection, BucketName, identifier, team)
}
// CreateTeam creates a new Team.
func (service *Service) CreateTeam(team *portainer.Team) error {
return service.db.Update(func(tx *bolt.Tx) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
id, _ := bucket.NextSequence()
@@ -122,5 +123,5 @@ func (service *Service) CreateTeam(team *portainer.Team) error {
// DeleteTeam deletes a Team.
func (service *Service) DeleteTeam(ID portainer.TeamID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.db, BucketName, identifier)
return internal.DeleteObject(service.connection, BucketName, identifier)
}

View File

@@ -1,8 +1,8 @@
package teammembership
import (
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/bolt/internal"
"github.com/boltdb/bolt"
)
@@ -14,18 +14,18 @@ const (
// Service represents a service for managing endpoint data.
type Service struct {
db *bolt.DB
connection *internal.DbConnection
}
// NewService creates a new instance of a service.
func NewService(db *bolt.DB) (*Service, error) {
err := internal.CreateBucket(db, BucketName)
func NewService(connection *internal.DbConnection) (*Service, error) {
err := internal.CreateBucket(connection, BucketName)
if err != nil {
return nil, err
}
return &Service{
db: db,
connection: connection,
}, nil
}
@@ -34,7 +34,7 @@ func (service *Service) TeamMembership(ID portainer.TeamMembershipID) (*portaine
var membership portainer.TeamMembership
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.db, BucketName, identifier, &membership)
err := internal.GetObject(service.connection, BucketName, identifier, &membership)
if err != nil {
return nil, err
}
@@ -46,7 +46,7 @@ func (service *Service) TeamMembership(ID portainer.TeamMembershipID) (*portaine
func (service *Service) TeamMemberships() ([]portainer.TeamMembership, error) {
var memberships = make([]portainer.TeamMembership, 0)
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -69,7 +69,7 @@ func (service *Service) TeamMemberships() ([]portainer.TeamMembership, error) {
func (service *Service) TeamMembershipsByUserID(userID portainer.UserID) ([]portainer.TeamMembership, error) {
var memberships = make([]portainer.TeamMembership, 0)
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -95,7 +95,7 @@ func (service *Service) TeamMembershipsByUserID(userID portainer.UserID) ([]port
func (service *Service) TeamMembershipsByTeamID(teamID portainer.TeamID) ([]portainer.TeamMembership, error) {
var memberships = make([]portainer.TeamMembership, 0)
err := service.db.View(func(tx *bolt.Tx) error {
err := service.connection.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -120,12 +120,12 @@ func (service *Service) TeamMembershipsByTeamID(teamID portainer.TeamID) ([]port
// UpdateTeamMembership saves a TeamMembership object.
func (service *Service) UpdateTeamMembership(ID portainer.TeamMembershipID, membership *portainer.TeamMembership) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.db, BucketName, identifier, membership)
return internal.UpdateObject(service.connection, BucketName, identifier, membership)
}
// CreateTeamMembership creates a new TeamMembership object.
func (service *Service) CreateTeamMembership(membership *portainer.TeamMembership) error {
return service.db.Update(func(tx *bolt.Tx) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
id, _ := bucket.NextSequence()
@@ -143,12 +143,12 @@ func (service *Service) CreateTeamMembership(membership *portainer.TeamMembershi
// DeleteTeamMembership deletes a TeamMembership object.
func (service *Service) DeleteTeamMembership(ID portainer.TeamMembershipID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.db, BucketName, identifier)
return internal.DeleteObject(service.connection, BucketName, identifier)
}
// DeleteTeamMembershipByUserID deletes all the TeamMembership object associated to a UserID.
func (service *Service) DeleteTeamMembershipByUserID(userID portainer.UserID) error {
return service.db.Update(func(tx *bolt.Tx) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
@@ -173,7 +173,7 @@ func (service *Service) DeleteTeamMembershipByUserID(userID portainer.UserID) er
// DeleteTeamMembershipByTeamID deletes all the TeamMembership object associated to a TeamID.
func (service *Service) DeleteTeamMembershipByTeamID(teamID portainer.TeamID) error {
return service.db.Update(func(tx *bolt.Tx) error {
return service.connection.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()

View File

@@ -1,95 +0,0 @@
package template
import (
"github.com/portainer/portainer"
"github.com/portainer/portainer/bolt/internal"
"github.com/boltdb/bolt"
)
const (
// BucketName represents the name of the bucket where this service stores data.
BucketName = "templates"
)
// Service represents a service for managing endpoint data.
type Service struct {
db *bolt.DB
}
// NewService creates a new instance of a service.
func NewService(db *bolt.DB) (*Service, error) {
err := internal.CreateBucket(db, BucketName)
if err != nil {
return nil, err
}
return &Service{
db: db,
}, nil
}
// Templates return an array containing all the templates.
func (service *Service) Templates() ([]portainer.Template, error) {
var templates = make([]portainer.Template, 0)
err := service.db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
cursor := bucket.Cursor()
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
var template portainer.Template
err := internal.UnmarshalObject(v, &template)
if err != nil {
return err
}
templates = append(templates, template)
}
return nil
})
return templates, err
}
// Template returns a template by ID.
func (service *Service) Template(ID portainer.TemplateID) (*portainer.Template, error) {
var template portainer.Template
identifier := internal.Itob(int(ID))
err := internal.GetObject(service.db, BucketName, identifier, &template)
if err != nil {
return nil, err
}
return &template, nil
}
// CreateTemplate creates a new template.
func (service *Service) CreateTemplate(template *portainer.Template) error {
return service.db.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(BucketName))
id, _ := bucket.NextSequence()
template.ID = portainer.TemplateID(id)
data, err := internal.MarshalObject(template)
if err != nil {
return err
}
return bucket.Put(internal.Itob(int(template.ID)), data)
})
}
// UpdateTemplate saves a template.
func (service *Service) UpdateTemplate(ID portainer.TemplateID, template *portainer.Template) error {
identifier := internal.Itob(int(ID))
return internal.UpdateObject(service.db, BucketName, identifier, template)
}
// DeleteTemplate deletes a template.
func (service *Service) DeleteTemplate(ID portainer.TemplateID) error {
identifier := internal.Itob(int(ID))
return internal.DeleteObject(service.db, BucketName, identifier)
}

Some files were not shown because too many files have changed in this diff Show More